diff --git a/crates/test-programs/wasi-tests/src/bin/path_open_read_without_rights.rs b/crates/test-programs/wasi-tests/src/bin/path_open_read_without_rights.rs index c67fbe1280..0adceee9a8 100644 --- a/crates/test-programs/wasi-tests/src/bin/path_open_read_without_rights.rs +++ b/crates/test-programs/wasi-tests/src/bin/path_open_read_without_rights.rs @@ -30,7 +30,7 @@ unsafe fn try_read_file(dir_fd: wasi::Fd) { wasi::fd_read(fd, &[iovec]) .expect_err("reading bytes from file should fail") .raw_error(), - wasi::ERRNO_NOTCAPABLE + wasi::ERRNO_BADF ); } diff --git a/crates/test-programs/wasi-tests/src/bin/truncation_rights.rs b/crates/test-programs/wasi-tests/src/bin/truncation_rights.rs index c28d11f1fa..5faa85fd91 100644 --- a/crates/test-programs/wasi-tests/src/bin/truncation_rights.rs +++ b/crates/test-programs/wasi-tests/src/bin/truncation_rights.rs @@ -68,7 +68,7 @@ unsafe fn test_truncation_rights(dir_fd: wasi::Fd) { wasi::path_open(dir_fd, 0, "file", wasi::OFLAGS_TRUNC, 0, 0, 0) .expect_err("truncating a file without path_filestat_set_size right") .raw_error(), - wasi::ERRNO_NOTCAPABLE + wasi::ERRNO_PERM ); } diff --git a/crates/wasi-common/src/dir.rs b/crates/wasi-common/src/dir.rs index 464f527325..18818763f5 100644 --- a/crates/wasi-common/src/dir.rs +++ b/crates/wasi-common/src/dir.rs @@ -76,15 +76,23 @@ impl DirEntry { if self.caps.contains(caps) { Ok(()) } else { - Err(Error::not_capable().context(format!("desired {:?}, has {:?}", caps, self.caps,))) + let missing = caps & !self.caps; + let err = if missing.intersects(DirCaps::READDIR) { + Error::not_dir() + } else { + Error::perm() + }; + Err(err.context(format!("desired rights {:?}, has {:?}", caps, self.caps))) } } pub fn capable_of_file(&self, caps: FileCaps) -> Result<(), Error> { if self.file_caps.contains(caps) { Ok(()) } else { - Err(Error::not_capable() - .context(format!("desired {:?}, has {:?}", caps, self.file_caps))) + Err(Error::perm().context(format!( + "desired rights {:?}, has {:?}", + caps, self.file_caps + ))) } } pub fn drop_caps_to(&mut self, caps: DirCaps, file_caps: FileCaps) -> Result<(), Error> { diff --git a/crates/wasi-common/src/error.rs b/crates/wasi-common/src/error.rs index e843a11766..0d50ab213c 100644 --- a/crates/wasi-common/src/error.rs +++ b/crates/wasi-common/src/error.rs @@ -72,6 +72,9 @@ pub enum ErrorKind { /// Errno::Spipe: Invalid seek #[error("Spipe: Invalid seek")] Spipe, + /// Errno::Perm: Permission denied + #[error("Permission denied")] + Perm, /// Errno::NotCapable: Not capable #[error("Not capable")] NotCapable, @@ -92,7 +95,7 @@ pub trait ErrorExt { fn overflow() -> Self; fn range() -> Self; fn seek_pipe() -> Self; - fn not_capable() -> Self; + fn perm() -> Self; } impl ErrorExt for Error { @@ -138,7 +141,7 @@ impl ErrorExt for Error { fn seek_pipe() -> Self { ErrorKind::Spipe.into() } - fn not_capable() -> Self { - ErrorKind::NotCapable.into() + fn perm() -> Self { + ErrorKind::Perm.into() } } diff --git a/crates/wasi-common/src/file.rs b/crates/wasi-common/src/file.rs index 0de79e3128..8d4bf6a45a 100644 --- a/crates/wasi-common/src/file.rs +++ b/crates/wasi-common/src/file.rs @@ -238,7 +238,16 @@ impl FileEntry { if self.caps.contains(caps) { Ok(()) } else { - Err(Error::not_capable().context(format!("desired {:?}, has {:?}", caps, self.caps,))) + let missing = caps & !self.caps; + let err = if missing.intersects(FileCaps::READ | FileCaps::WRITE) { + // `EBADF` is a little surprising here because it's also used + // for unknown-file-descriptor errors, but it's what POSIX uses + // in this situation. + Error::badf() + } else { + Error::perm() + }; + Err(err.context(format!("desired rights {:?}, has {:?}", caps, self.caps))) } } diff --git a/crates/wasi-common/src/snapshots/preview_1.rs b/crates/wasi-common/src/snapshots/preview_1.rs index 4eb7476a51..6e2506480c 100644 --- a/crates/wasi-common/src/snapshots/preview_1.rs +++ b/crates/wasi-common/src/snapshots/preview_1.rs @@ -84,6 +84,7 @@ impl From for types::Errno { ErrorKind::Range => Errno::Range, ErrorKind::Spipe => Errno::Spipe, ErrorKind::NotCapable => Errno::Notcapable, + ErrorKind::Perm => Errno::Perm, } } }