diff --git a/crates/test-programs/wasi-tests/src/bin/path_open_preopen.rs b/crates/test-programs/wasi-tests/src/bin/path_open_preopen.rs index f1e7a3f7cfba..cb8e07490f6d 100644 --- a/crates/test-programs/wasi-tests/src/bin/path_open_preopen.rs +++ b/crates/test-programs/wasi-tests/src/bin/path_open_preopen.rs @@ -20,6 +20,18 @@ unsafe fn path_open_preopen() { fdstat.fs_rights_base, fdstat.fs_rights_inheriting ); + for (right, name) in directory_base_rights() { + assert!( + (fdstat.fs_rights_base & right) == right, + "fs_rights_base does not have required right `{name}`" + ); + } + for (right, name) in directory_inheriting_rights() { + assert!( + (fdstat.fs_rights_inheriting & right) == right, + "fs_rights_inheriting does not have required right `{name}`" + ); + } // Open with same rights it has now: let _ = wasi::path_open( @@ -90,3 +102,52 @@ fn main() { path_open_preopen(); } } + +// Hard-code the set of rights expected for a preopened directory. This is +// more brittle than we wanted to test for, but various userland +// implementations expect (at least) this set of rights to be present on all +// directories: + +fn directory_base_rights() -> Vec<(wasi::Rights, &'static str)> { + vec![ + (wasi::RIGHTS_PATH_CREATE_DIRECTORY, "PATH_CREATE_DIRECTORY"), + (wasi::RIGHTS_PATH_CREATE_FILE, "PATH_CREATE_FILE"), + (wasi::RIGHTS_PATH_LINK_SOURCE, "PATH_LINK_SOURCE"), + (wasi::RIGHTS_PATH_LINK_TARGET, "PATH_LINK_TARGET"), + (wasi::RIGHTS_PATH_OPEN, "PATH_OPEN"), + (wasi::RIGHTS_FD_READDIR, "FD_READDIR"), + (wasi::RIGHTS_PATH_READLINK, "PATH_READLINK"), + (wasi::RIGHTS_PATH_RENAME_SOURCE, "PATH_RENAME_SOURCE"), + (wasi::RIGHTS_PATH_RENAME_TARGET, "PATH_RENAME_TARGET"), + (wasi::RIGHTS_PATH_SYMLINK, "PATH_SYMLINK"), + (wasi::RIGHTS_PATH_REMOVE_DIRECTORY, "PATH_REMOVE_DIRECTORY"), + (wasi::RIGHTS_PATH_UNLINK_FILE, "PATH_UNLINK_FILE"), + (wasi::RIGHTS_PATH_FILESTAT_GET, "PATH_FILESTAT_GET"), + ( + wasi::RIGHTS_PATH_FILESTAT_SET_TIMES, + "PATH_FILESTAT_SET_TIMES", + ), + (wasi::RIGHTS_FD_FILESTAT_GET, "FD_FILESTAT_GET"), + (wasi::RIGHTS_FD_FILESTAT_SET_TIMES, "FD_FILESTAT_SET_TIMES"), + ] +} + +pub(crate) fn directory_inheriting_rights() -> Vec<(wasi::Rights, &'static str)> { + let mut rights = directory_base_rights(); + rights.extend_from_slice(&[ + (wasi::RIGHTS_FD_DATASYNC, "FD_DATASYNC"), + (wasi::RIGHTS_FD_READ, "FD_READ"), + (wasi::RIGHTS_FD_SEEK, "FD_SEEK"), + (wasi::RIGHTS_FD_FDSTAT_SET_FLAGS, "FD_FDSTAT_SET_FLAGS"), + (wasi::RIGHTS_FD_SYNC, "FD_SYNC"), + (wasi::RIGHTS_FD_TELL, "FD_TELL"), + (wasi::RIGHTS_FD_WRITE, "FD_WRITE"), + (wasi::RIGHTS_FD_ADVISE, "FD_ADVISE"), + (wasi::RIGHTS_FD_ALLOCATE, "FD_ALLOCATE"), + (wasi::RIGHTS_FD_FILESTAT_GET, "FD_FILESTAT_GET"), + (wasi::RIGHTS_FD_FILESTAT_SET_SIZE, "FD_FILESTAT_SET_SIZE"), + (wasi::RIGHTS_FD_FILESTAT_SET_TIMES, "FD_FILESTAT_SET_TIMES"), + (wasi::RIGHTS_POLL_FD_READWRITE, "POLL_FD_READWRITE"), + ]); + rights +} diff --git a/crates/wasi-preview1-component-adapter/src/lib.rs b/crates/wasi-preview1-component-adapter/src/lib.rs index 7d64bf080c58..69aa91959724 100644 --- a/crates/wasi-preview1-component-adapter/src/lib.rs +++ b/crates/wasi-preview1-component-adapter/src/lib.rs @@ -481,41 +481,86 @@ pub unsafe extern "C" fn fd_fdstat_get(fd: Fd, stat: *mut Fdstat) -> Errno { }) => { let flags = filesystem::get_flags(file.fd)?; let type_ = filesystem::get_type(file.fd)?; + match type_ { + filesystem::DescriptorType::Directory => { + // Hard-coded set of rights expected by many userlands: + let fs_rights_base = wasi::RIGHTS_PATH_CREATE_DIRECTORY + | wasi::RIGHTS_PATH_CREATE_FILE + | wasi::RIGHTS_PATH_LINK_SOURCE + | wasi::RIGHTS_PATH_LINK_TARGET + | wasi::RIGHTS_PATH_OPEN + | wasi::RIGHTS_FD_READDIR + | wasi::RIGHTS_PATH_READLINK + | wasi::RIGHTS_PATH_RENAME_SOURCE + | wasi::RIGHTS_PATH_RENAME_TARGET + | wasi::RIGHTS_PATH_SYMLINK + | wasi::RIGHTS_PATH_REMOVE_DIRECTORY + | wasi::RIGHTS_PATH_UNLINK_FILE + | wasi::RIGHTS_PATH_FILESTAT_GET + | wasi::RIGHTS_PATH_FILESTAT_SET_TIMES + | wasi::RIGHTS_FD_FILESTAT_GET + | wasi::RIGHTS_FD_FILESTAT_SET_TIMES; + + let fs_rights_inheriting = fs_rights_base + | wasi::RIGHTS_FD_DATASYNC + | wasi::RIGHTS_FD_READ + | wasi::RIGHTS_FD_SEEK + | wasi::RIGHTS_FD_FDSTAT_SET_FLAGS + | wasi::RIGHTS_FD_SYNC + | wasi::RIGHTS_FD_TELL + | wasi::RIGHTS_FD_WRITE + | wasi::RIGHTS_FD_ADVISE + | wasi::RIGHTS_FD_ALLOCATE + | wasi::RIGHTS_FD_FILESTAT_GET + | wasi::RIGHTS_FD_FILESTAT_SET_SIZE + | wasi::RIGHTS_FD_FILESTAT_SET_TIMES + | wasi::RIGHTS_POLL_FD_READWRITE; + + stat.write(Fdstat { + fs_filetype: wasi::FILETYPE_DIRECTORY, + fs_flags: 0, + fs_rights_base, + fs_rights_inheriting, + }); + Ok(()) + } + _ => { + let fs_filetype = type_.into(); - let fs_filetype = type_.into(); - - let mut fs_flags = 0; - let mut fs_rights_base = !0; - if !flags.contains(filesystem::DescriptorFlags::READ) { - fs_rights_base &= !RIGHTS_FD_READ; - } - if !flags.contains(filesystem::DescriptorFlags::WRITE) { - fs_rights_base &= !RIGHTS_FD_WRITE; - } - if flags.contains(filesystem::DescriptorFlags::DATA_INTEGRITY_SYNC) { - fs_flags |= FDFLAGS_DSYNC; - } - if flags.contains(filesystem::DescriptorFlags::REQUESTED_WRITE_SYNC) { - fs_flags |= FDFLAGS_RSYNC; - } - if flags.contains(filesystem::DescriptorFlags::FILE_INTEGRITY_SYNC) { - fs_flags |= FDFLAGS_SYNC; - } - if file.append { - fs_flags |= FDFLAGS_APPEND; - } - if !file.blocking { - fs_flags |= FDFLAGS_NONBLOCK; + let mut fs_flags = 0; + let mut fs_rights_base = !0; + if !flags.contains(filesystem::DescriptorFlags::READ) { + fs_rights_base &= !RIGHTS_FD_READ; + } + if !flags.contains(filesystem::DescriptorFlags::WRITE) { + fs_rights_base &= !RIGHTS_FD_WRITE; + } + if flags.contains(filesystem::DescriptorFlags::DATA_INTEGRITY_SYNC) { + fs_flags |= FDFLAGS_DSYNC; + } + if flags.contains(filesystem::DescriptorFlags::REQUESTED_WRITE_SYNC) { + fs_flags |= FDFLAGS_RSYNC; + } + if flags.contains(filesystem::DescriptorFlags::FILE_INTEGRITY_SYNC) { + fs_flags |= FDFLAGS_SYNC; + } + if file.append { + fs_flags |= FDFLAGS_APPEND; + } + if !file.blocking { + fs_flags |= FDFLAGS_NONBLOCK; + } + let fs_rights_inheriting = fs_rights_base; + + stat.write(Fdstat { + fs_filetype, + fs_flags, + fs_rights_base, + fs_rights_inheriting, + }); + Ok(()) + } } - let fs_rights_inheriting = fs_rights_base; - - stat.write(Fdstat { - fs_filetype, - fs_flags, - fs_rights_base, - fs_rights_inheriting, - }); - Ok(()) } Descriptor::Streams(Streams { input, diff --git a/crates/wasi/src/preview2/preview1/mod.rs b/crates/wasi/src/preview2/preview1/mod.rs index 0bbbe1c9b67d..6a2332882e2f 100644 --- a/crates/wasi/src/preview2/preview1/mod.rs +++ b/crates/wasi/src/preview2/preview1/mod.rs @@ -861,7 +861,47 @@ impl< fs_rights_inheriting: fs_rights_base, }); } - Descriptor::PreopenDirectory((fd, _)) => (*fd, false, false), + Descriptor::PreopenDirectory((_, _)) => { + // Hard-coded set or rights expected by many userlands: + let fs_rights_base = types::Rights::PATH_CREATE_DIRECTORY + | types::Rights::PATH_CREATE_FILE + | types::Rights::PATH_LINK_SOURCE + | types::Rights::PATH_LINK_TARGET + | types::Rights::PATH_OPEN + | types::Rights::FD_READDIR + | types::Rights::PATH_READLINK + | types::Rights::PATH_RENAME_SOURCE + | types::Rights::PATH_RENAME_TARGET + | types::Rights::PATH_SYMLINK + | types::Rights::PATH_REMOVE_DIRECTORY + | types::Rights::PATH_UNLINK_FILE + | types::Rights::PATH_FILESTAT_GET + | types::Rights::PATH_FILESTAT_SET_TIMES + | types::Rights::FD_FILESTAT_GET + | types::Rights::FD_FILESTAT_SET_TIMES; + + let fs_rights_inheriting = fs_rights_base + | types::Rights::FD_DATASYNC + | types::Rights::FD_READ + | types::Rights::FD_SEEK + | types::Rights::FD_FDSTAT_SET_FLAGS + | types::Rights::FD_SYNC + | types::Rights::FD_TELL + | types::Rights::FD_WRITE + | types::Rights::FD_ADVISE + | types::Rights::FD_ALLOCATE + | types::Rights::FD_FILESTAT_GET + | types::Rights::FD_FILESTAT_SET_SIZE + | types::Rights::FD_FILESTAT_SET_TIMES + | types::Rights::POLL_FD_READWRITE; + + return Ok(types::Fdstat { + fs_filetype: types::Filetype::Directory, + fs_flags: types::Fdflags::empty(), + fs_rights_base, + fs_rights_inheriting, + }); + } Descriptor::File(File { fd, blocking,