From 781aca4421a31651ac73d8540d033191815e0f0f Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 31 Mar 2026 18:08:54 -0700 Subject: [PATCH 1/2] wasmtime-wasi p1: get_seekable fails with Errno SPIPE for Fifo or CharacterDevice --- crates/wasi/src/p0.rs | 8 ++++---- crates/wasi/src/p1.rs | 23 ++++++++++++++++------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/crates/wasi/src/p0.rs b/crates/wasi/src/p0.rs index 5d610f0ae557..f9a4d0fcc439 100644 --- a/crates/wasi/src/p0.rs +++ b/crates/wasi/src/p0.rs @@ -31,7 +31,7 @@ wiggle::from_witx!({ fd_filestat_set_times, fd_read, fd_pread, fd_seek, fd_sync, fd_readdir, fd_write, fd_pwrite, poll_oneoff, path_create_directory, path_filestat_get, path_filestat_set_times, path_link, path_open, path_readlink, path_remove_directory, - path_rename, path_symlink, path_unlink_file + path_rename, path_symlink, path_unlink_file, fd_tell, } }, errors: { errno => trappable Error }, @@ -50,7 +50,7 @@ mod sync { fd_filestat_set_times, fd_read, fd_pread, fd_seek, fd_sync, fd_readdir, fd_write, fd_pwrite, poll_oneoff, path_create_directory, path_filestat_get, path_filestat_set_times, path_link, path_open, path_readlink, path_remove_directory, - path_rename, path_symlink, path_unlink_file + path_rename, path_symlink, path_unlink_file, fd_tell, } }, errors: { errno => trappable Error }, @@ -325,12 +325,12 @@ impl wasi_unstable::WasiUnstable for T { Ok(()) } - fn fd_tell( + async fn fd_tell( &mut self, memory: &mut GuestMemory<'_>, fd: types::Fd, ) -> Result { - Ok(Snapshot1::fd_tell(self, memory, fd.into())?) + Ok(Snapshot1::fd_tell(self, memory, fd.into()).await?) } async fn fd_readdir( diff --git a/crates/wasi/src/p1.rs b/crates/wasi/src/p1.rs index b063aa7a9aae..7fef7700c650 100644 --- a/crates/wasi/src/p1.rs +++ b/crates/wasi/src/p1.rs @@ -532,10 +532,18 @@ impl Transaction<'_> { /// # Errors /// /// Returns [`types::Errno::Spipe`] if the descriptor corresponds to stdio - fn get_seekable(&self, fd: types::Fd) -> Result<&File> { + async fn get_seekable(&mut self, fd: types::Fd) -> Result<&File> { let fd = fd.into(); match self.descriptors.used.get(&fd) { - Some(Descriptor::File(file)) => Ok(file), + Some(Descriptor::File(file)) => { + if matches!( + self.view.filesystem().get_type(file.fd.borrowed()).await?, + filesystem::DescriptorType::CharacterDevice | filesystem::DescriptorType::Fifo + ) { + return Err(types::Errno::Spipe.into()); + } + Ok(file) + } Some( Descriptor::Stdin { .. } | Descriptor::Stdout { .. } | Descriptor::Stderr { .. }, ) => { @@ -863,7 +871,7 @@ wiggle::from_witx!({ fd_filestat_set_times, fd_read, fd_pread, fd_seek, fd_sync, fd_readdir, fd_write, fd_pwrite, poll_oneoff, path_create_directory, path_filestat_get, path_filestat_set_times, path_link, path_open, path_readlink, path_remove_directory, - path_rename, path_symlink, path_unlink_file + path_rename, path_symlink, path_unlink_file, fd_tell, } }, errors: { errno => trappable Error }, @@ -882,7 +890,7 @@ pub(crate) mod sync { fd_filestat_set_times, fd_read, fd_pread, fd_seek, fd_sync, fd_readdir, fd_write, fd_pwrite, poll_oneoff, path_create_directory, path_filestat_get, path_filestat_set_times, path_link, path_open, path_readlink, path_remove_directory, - path_rename, path_symlink, path_unlink_file + path_rename, path_symlink, path_unlink_file, fd_tell, } }, errors: { errno => trappable Error }, @@ -1888,8 +1896,8 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiP1Ctx { offset: types::Filedelta, whence: types::Whence, ) -> Result { - let t = self.transact()?; - let File { fd, position, .. } = t.get_seekable(fd)?; + let mut t = self.transact()?; + let File { fd, position, .. } = t.get_seekable(fd).await?; let fd = fd.borrowed(); let position = position.clone(); drop(t); @@ -1927,7 +1935,7 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiP1Ctx { /// Return the current offset of a file descriptor. /// NOTE: This is similar to `lseek(fd, 0, SEEK_CUR)` in POSIX. #[instrument(skip(self, _memory))] - fn fd_tell( + async fn fd_tell( &mut self, _memory: &mut GuestMemory<'_>, fd: types::Fd, @@ -1935,6 +1943,7 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiP1Ctx { let pos = self .transact()? .get_seekable(fd) + .await .map(|File { position, .. }| position.load(Ordering::Relaxed))?; Ok(pos) } From 27956bf8692cec5eca6e3f7760b510a6a35e4416 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 31 Mar 2026 18:41:05 -0700 Subject: [PATCH 2/2] wasmtime-wasi: plumb through cap_std FileTypeExt::is_fifo to DescriptorType::Fifo --- crates/wasi/src/filesystem.rs | 4 ++++ crates/wasi/src/p1.rs | 3 ++- crates/wasi/src/p2/host/filesystem.rs | 1 + crates/wasi/src/p3/filesystem/mod.rs | 3 +++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/crates/wasi/src/filesystem.rs b/crates/wasi/src/filesystem.rs index 917defac77e0..af08a154f0cb 100644 --- a/crates/wasi/src/filesystem.rs +++ b/crates/wasi/src/filesystem.rs @@ -254,6 +254,8 @@ pub(crate) enum DescriptorType { SymbolicLink, /// The descriptor refers to a regular file inode. RegularFile, + /// The descriptor refers to a FIFO + Fifo, } impl From for DescriptorType { @@ -268,6 +270,8 @@ impl From for DescriptorType { DescriptorType::CharacterDevice } else if ft.is_file() { DescriptorType::RegularFile + } else if ft.is_fifo() { + DescriptorType::Fifo } else { DescriptorType::Unknown } diff --git a/crates/wasi/src/p1.rs b/crates/wasi/src/p1.rs index 7fef7700c650..c48f96e4daf2 100644 --- a/crates/wasi/src/p1.rs +++ b/crates/wasi/src/p1.rs @@ -536,8 +536,9 @@ impl Transaction<'_> { let fd = fd.into(); match self.descriptors.used.get(&fd) { Some(Descriptor::File(file)) => { + let descriptor_type = self.view.filesystem().get_type(file.fd.borrowed()).await?; if matches!( - self.view.filesystem().get_type(file.fd.borrowed()).await?, + descriptor_type, filesystem::DescriptorType::CharacterDevice | filesystem::DescriptorType::Fifo ) { return Err(types::Errno::Spipe.into()); diff --git a/crates/wasi/src/p2/host/filesystem.rs b/crates/wasi/src/p2/host/filesystem.rs index 02f2b0322a41..dc967974a59d 100644 --- a/crates/wasi/src/p2/host/filesystem.rs +++ b/crates/wasi/src/p2/host/filesystem.rs @@ -616,6 +616,7 @@ impl From for types::DescriptorType { crate::filesystem::DescriptorType::Directory => Self::Directory, crate::filesystem::DescriptorType::SymbolicLink => Self::SymbolicLink, crate::filesystem::DescriptorType::RegularFile => Self::RegularFile, + crate::filesystem::DescriptorType::Fifo => Self::Fifo, } } } diff --git a/crates/wasi/src/p3/filesystem/mod.rs b/crates/wasi/src/p3/filesystem/mod.rs index 0ef9c3166c7f..72f3efc130d2 100644 --- a/crates/wasi/src/p3/filesystem/mod.rs +++ b/crates/wasi/src/p3/filesystem/mod.rs @@ -261,6 +261,7 @@ impl From for types::DescriptorType { crate::filesystem::DescriptorType::Directory => Self::Directory, crate::filesystem::DescriptorType::SymbolicLink => Self::SymbolicLink, crate::filesystem::DescriptorType::RegularFile => Self::RegularFile, + crate::filesystem::DescriptorType::Fifo => Self::Fifo, } } } @@ -278,6 +279,8 @@ impl From for types::DescriptorType { Self::CharacterDevice } else if ft.is_file() { Self::RegularFile + } else if ft.is_fifo() { + Self::Fifo } else { Self::Other(None) }