Fix path_get returning ENOTDIR when base not dir (#159)

* Fix path_get returning ENOTDIR when base not dir

This commit makes certain adjustments to `WasiCtx` and `FdEntry`
by introducing methods `get_nonvalidated_fd_entry` and
`get_nonvalidated_fd_entry_mut` which only check if the `FdEntry`
corresponding to the specified raw WASI fd exists in the context
object but **without** automatically validating the rights. Thanks
to postponing the validation until after the `FdEntry` object is
extracted from the context, it is possible to check if the extracted
`FdEntry` object is indeed a valid dir descriptor when processing
paths in `path_get` helper fn. In essence then, this commit closes
 #158.

* Remove potentially useless FdObject struct

This commit removes `FdObject` struct which wasn't really used
in our codebase, and flattens its contents into `FdEntry`. IMHO,
this cleans up a fair amount of code and generally unclutters it.

* Refactor and document `WasiCtx` and `FdEntry`

This commit refactors `WasiCtx` struct by making the collection
of `FdEntry`s stored within private, and only allowing it to be
accessed via the provided set of modifier methods (push, insert,
remove, etc.).

Additionally, this commit documents the methods of `WasiCtx` and
`FdEntry` structs for easier debugging and maintenance in the future.
This commit is contained in:
Jakub Konka
2019-10-30 22:41:43 +01:00
committed by Dan Gohman
parent 0302f1a164
commit f4d3f08fc6
6 changed files with 279 additions and 195 deletions

View File

@@ -162,7 +162,7 @@ impl WasiCtxBuilder {
#[derive(Debug)]
pub struct WasiCtx {
pub(crate) fds: HashMap<host::__wasi_fd_t, FdEntry>,
fds: HashMap<host::__wasi_fd_t, FdEntry>,
pub(crate) args: Vec<CString>,
pub(crate) env: Vec<CString>,
}
@@ -183,48 +183,28 @@ impl WasiCtx {
.and_then(|ctx| ctx.build())
}
/// Check if `WasiCtx` contains the specified raw WASI `fd`.
pub(crate) unsafe fn contains_fd_entry(&self, fd: host::__wasi_fd_t) -> bool {
self.fds.contains_key(&fd)
}
pub(crate) unsafe fn get_fd_entry(
&self,
fd: host::__wasi_fd_t,
rights_base: host::__wasi_rights_t,
rights_inheriting: host::__wasi_rights_t,
) -> Result<&FdEntry> {
if let Some(fe) = self.fds.get(&fd) {
Self::validate_rights(fe, rights_base, rights_inheriting).and(Ok(fe))
} else {
Err(Error::EBADF)
}
/// Get an immutable `FdEntry` corresponding to the specified raw WASI `fd`.
pub(crate) unsafe fn get_fd_entry(&self, fd: host::__wasi_fd_t) -> Result<&FdEntry> {
self.fds.get(&fd).ok_or(Error::EBADF)
}
/// Get a mutable `FdEntry` corresponding to the specified raw WASI `fd`.
pub(crate) unsafe fn get_fd_entry_mut(
&mut self,
fd: host::__wasi_fd_t,
rights_base: host::__wasi_rights_t,
rights_inheriting: host::__wasi_rights_t,
) -> Result<&mut FdEntry> {
if let Some(fe) = self.fds.get_mut(&fd) {
Self::validate_rights(fe, rights_base, rights_inheriting).and(Ok(fe))
} else {
Err(Error::EBADF)
}
}
fn validate_rights(
fe: &FdEntry,
rights_base: host::__wasi_rights_t,
rights_inheriting: host::__wasi_rights_t,
) -> Result<()> {
if !fe.rights_base & rights_base != 0 || !fe.rights_inheriting & rights_inheriting != 0 {
Err(Error::ENOTCAPABLE)
} else {
Ok(())
}
self.fds.get_mut(&fd).ok_or(Error::EBADF)
}
/// Insert the specified `FdEntry` into the `WasiCtx` object.
///
/// The `FdEntry` will automatically get another free raw WASI `fd` assigned. Note that
/// the two subsequent free raw WASI `fd`s do not have to be stored contiguously.
pub(crate) fn insert_fd_entry(&mut self, fe: FdEntry) -> Result<host::__wasi_fd_t> {
// never insert where stdio handles usually are
let mut fd = 3;
@@ -238,4 +218,19 @@ impl WasiCtx {
self.fds.insert(fd, fe);
Ok(fd)
}
/// Insert the specified `FdEntry` with the specified raw WASI `fd` key into the `WasiCtx`
/// object.
pub(crate) fn insert_fd_entry_at(
&mut self,
fd: host::__wasi_fd_t,
fe: FdEntry,
) -> Option<FdEntry> {
self.fds.insert(fd, fe)
}
/// Remove `FdEntry` corresponding to the specified raw WASI `fd` from the `WasiCtx` object.
pub(crate) fn remove_fd_entry(&mut self, fd: host::__wasi_fd_t) -> Result<FdEntry> {
self.fds.remove(&fd).ok_or(Error::EBADF)
}
}