Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
## 44.0.3

Released 2026-06-15.

### Fixed

* Leak in WASIp1 `fd_renumber` implementation.
[GHSA-3p27-qvp9-27qf](https://github.com/bytecodealliance/wasmtime/security/advisories/GHSA-3p27-qvp9-27qf)

--------------------------------------------------------------------------------

## 44.0.2

Released 2026-05-21.
Expand Down
23 changes: 23 additions & 0 deletions crates/test-programs/src/bin/p1_renumber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,28 @@ unsafe fn test_renumber(dir_fd: wasip1::Fd) {
);
}

unsafe fn test_renumber_loop(dir_fd: wasip1::Fd) {
let mut cur = wasip1::path_open(
dir_fd,
0,
"file1",
wasip1::OFLAGS_CREAT,
wasip1::RIGHTS_FD_READ | wasip1::RIGHTS_FD_WRITE,
0,
0,
)
.expect("opening a file");

for _ in 0..2000 {
let next = wasip1::path_open(dir_fd, 0, "file1", 0, wasip1::RIGHTS_FD_READ, 0, 0)
.expect("opening a file");
wasip1::fd_renumber(cur, next).unwrap();
cur = next;
}

wasip1::fd_close(cur).unwrap();
}

fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
Expand All @@ -134,4 +156,5 @@ fn main() {

// Run the tests.
unsafe { test_renumber(dir_fd) }
unsafe { test_renumber_loop(dir_fd) }
}
8 changes: 4 additions & 4 deletions crates/wasi/src/p0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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_renumber
}
},
errors: { errno => trappable Error },
Expand All @@ -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_renumber
}
},
errors: { errno => trappable Error },
Expand Down Expand Up @@ -300,13 +300,13 @@ impl<T: Snapshot1 + Send> wasi_unstable::WasiUnstable for T {
Ok(())
}

fn fd_renumber(
async fn fd_renumber(
&mut self,
memory: &mut GuestMemory<'_>,
from: types::Fd,
to: types::Fd,
) -> Result<(), Error> {
Snapshot1::fd_renumber(self, memory, from.into(), to.into())?;
Snapshot1::fd_renumber(self, memory, from.into(), to.into()).await?;
Ok(())
}

Expand Down
41 changes: 23 additions & 18 deletions crates/wasi/src/p1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -863,7 +863,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_renumber
}
},
errors: { errno => trappable Error },
Expand All @@ -882,7 +882,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_renumber
}
},
errors: { errno => trappable Error },
Expand Down Expand Up @@ -1853,28 +1853,33 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiP1Ctx {
}

/// Atomically replace a file descriptor by renumbering another file descriptor.
#[instrument(skip(self, _memory))]
fn fd_renumber(
#[instrument(skip(self, memory))]
async fn fd_renumber(
&mut self,
_memory: &mut GuestMemory<'_>,
from: types::Fd,
to: types::Fd,
memory: &mut GuestMemory<'_>,
from_fd: types::Fd,
to_fd: types::Fd,
) -> Result<(), types::Error> {
let mut st = self.transact()?;
let from = from.into();
let to = to.into();
if !st.descriptors.used.contains_key(&to) {
return Err(types::Errno::Badf.into());
let from = from_fd.into();
let to = to_fd.into();
{
let st = self.transact()?;
if !st.descriptors.used.contains_key(&to) || !st.descriptors.used.contains_key(&from) {
return Err(types::Errno::Badf.into());
}
if from == to {
return Ok(());
}
}
self.fd_close(memory, to_fd).await?;
let mut st = self.transact()?;
let btree_map::Entry::Occupied(desc) = st.descriptors.used.entry(from) else {
return Err(types::Errno::Badf.into());
};
if from != to {
let desc = desc.remove();
st.descriptors.free.insert(from);
st.descriptors.free.remove(&to);
st.descriptors.used.insert(to, desc);
}
let desc = desc.remove();
st.descriptors.free.insert(from);
st.descriptors.free.remove(&to);
st.descriptors.used.insert(to, desc);
Ok(())
}

Expand Down
Loading