redesign how caps fit into entries!
This commit is contained in:
@@ -26,36 +26,23 @@ impl WasiCtx {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_file(
|
||||
&self,
|
||||
fd: u32,
|
||||
file: Box<dyn WasiFile>,
|
||||
base_caps: FileCaps,
|
||||
inheriting_caps: FileCaps,
|
||||
) {
|
||||
let e = FileEntry {
|
||||
base_caps,
|
||||
inheriting_caps,
|
||||
file,
|
||||
};
|
||||
self.table().insert_at(fd, Box::new(e));
|
||||
pub fn insert_file(&self, fd: u32, file: Box<dyn WasiFile>, caps: FileCaps) {
|
||||
self.table()
|
||||
.insert_at(fd, Box::new(FileEntry::new(caps, file)));
|
||||
}
|
||||
|
||||
pub fn insert_dir(
|
||||
&self,
|
||||
fd: u32,
|
||||
dir: Box<dyn WasiDir>,
|
||||
base_caps: DirCaps,
|
||||
inheriting_caps: DirCaps,
|
||||
caps: DirCaps,
|
||||
file_caps: FileCaps,
|
||||
path: PathBuf,
|
||||
) {
|
||||
let e = DirEntry {
|
||||
base_caps,
|
||||
inheriting_caps,
|
||||
preopen_path: Some(path),
|
||||
dir,
|
||||
};
|
||||
self.table().insert_at(fd, Box::new(e));
|
||||
self.table().insert_at(
|
||||
fd,
|
||||
Box::new(DirEntry::new(caps, file_caps, Some(path), dir)),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn table(&self) -> RefMut<Table> {
|
||||
@@ -79,8 +66,7 @@ impl WasiCtxBuilder {
|
||||
self.0.insert_file(
|
||||
0,
|
||||
f,
|
||||
FileCaps::READ, // XXX probably more rights are ok
|
||||
FileCaps::READ,
|
||||
FileCaps::READ, // XXX fixme: more rights are ok, but this is read-only
|
||||
);
|
||||
self
|
||||
}
|
||||
@@ -89,8 +75,7 @@ impl WasiCtxBuilder {
|
||||
self.0.insert_file(
|
||||
1,
|
||||
f,
|
||||
FileCaps::WRITE, // XXX probably more rights are ok
|
||||
FileCaps::WRITE,
|
||||
FileCaps::WRITE, // XXX fixme: more rights are ok, but this is append only
|
||||
);
|
||||
self
|
||||
}
|
||||
@@ -99,8 +84,7 @@ impl WasiCtxBuilder {
|
||||
self.0.insert_file(
|
||||
2,
|
||||
f,
|
||||
FileCaps::WRITE, // XXX probably more rights are ok
|
||||
FileCaps::WRITE,
|
||||
FileCaps::WRITE, // XXX fixme: more rights are ok, but this is append only
|
||||
);
|
||||
self
|
||||
}
|
||||
@@ -116,14 +100,14 @@ impl WasiCtxBuilder {
|
||||
dir: Box<dyn WasiDir>,
|
||||
path: impl AsRef<Path>,
|
||||
) -> Result<&mut Self, Error> {
|
||||
let base_caps = DirCaps::OPEN;
|
||||
let inheriting_caps = DirCaps::OPEN;
|
||||
self.0.table().push(Box::new(DirEntry {
|
||||
base_caps,
|
||||
inheriting_caps,
|
||||
preopen_path: Some(path.as_ref().to_owned()),
|
||||
let caps = DirCaps::OPEN | DirCaps::CREATE_FILE; // XXX more base caps
|
||||
let file_caps = FileCaps::READ | FileCaps::WRITE; // XXX more base caps
|
||||
self.0.table().push(Box::new(DirEntry::new(
|
||||
caps,
|
||||
file_caps,
|
||||
Some(path.as_ref().to_owned()),
|
||||
dir,
|
||||
}))?;
|
||||
)))?;
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ use crate::error::Error;
|
||||
use crate::file::{FileCaps, OFlags, WasiFile};
|
||||
use std::ops::Deref;
|
||||
use std::path::{Path, PathBuf};
|
||||
use tracing::debug;
|
||||
|
||||
pub trait WasiDir {
|
||||
fn open_file(
|
||||
@@ -24,27 +23,60 @@ pub trait WasiDir {
|
||||
}
|
||||
|
||||
pub(crate) struct DirEntry {
|
||||
pub(crate) base_caps: DirCaps,
|
||||
pub(crate) inheriting_caps: DirCaps,
|
||||
pub(crate) preopen_path: Option<PathBuf>, // precondition: PathBuf is valid unicode
|
||||
pub(crate) dir: Box<dyn WasiDir>,
|
||||
caps: DirCaps,
|
||||
file_caps: FileCaps,
|
||||
preopen_path: Option<PathBuf>, // precondition: PathBuf is valid unicode
|
||||
dir: Box<dyn WasiDir>,
|
||||
}
|
||||
|
||||
impl DirEntry {
|
||||
pub fn get_cap(&self, caps: DirCaps) -> Result<&dyn WasiDir, Error> {
|
||||
if self.base_caps.contains(&caps) && self.inheriting_caps.contains(&caps) {
|
||||
Ok(self.dir.deref())
|
||||
} else {
|
||||
Err(Error::DirNotCapable(caps))
|
||||
pub fn new(
|
||||
caps: DirCaps,
|
||||
file_caps: FileCaps,
|
||||
preopen_path: Option<PathBuf>,
|
||||
dir: Box<dyn WasiDir>,
|
||||
) -> Self {
|
||||
DirEntry {
|
||||
caps,
|
||||
file_caps,
|
||||
preopen_path,
|
||||
dir,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_cap(&self, caps: DirCaps) -> Result<&dyn WasiDir, Error> {
|
||||
if self.caps.contains(&caps) {
|
||||
Ok(self.dir.deref())
|
||||
} else {
|
||||
Err(Error::DirNotCapable {
|
||||
desired: caps,
|
||||
has: self.caps,
|
||||
})
|
||||
}
|
||||
}
|
||||
pub fn drop_caps_to(&mut self, caps: DirCaps, file_caps: FileCaps) -> Result<(), Error> {
|
||||
if self.caps.contains(&caps) && self.file_caps.contains(&file_caps) {
|
||||
self.caps = caps;
|
||||
self.file_caps = file_caps;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::NotCapable)
|
||||
}
|
||||
}
|
||||
pub fn child_dir_caps(&self, desired_caps: DirCaps) -> DirCaps {
|
||||
self.caps.intersection(&desired_caps)
|
||||
}
|
||||
pub fn child_file_caps(&self, desired_caps: FileCaps) -> FileCaps {
|
||||
self.file_caps.intersection(&desired_caps)
|
||||
}
|
||||
pub fn get_dirstat(&self) -> DirStat {
|
||||
DirStat {
|
||||
base_caps: self.base_caps,
|
||||
inheriting_caps: self.inheriting_caps,
|
||||
dir_caps: self.caps,
|
||||
file_caps: self.file_caps,
|
||||
}
|
||||
}
|
||||
pub fn preopen_path(&self) -> &Option<PathBuf> {
|
||||
&self.preopen_path
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
@@ -62,6 +94,12 @@ impl DirCaps {
|
||||
self.flags & other.flags == other.flags
|
||||
}
|
||||
|
||||
/// Intersection of two sets of flags (bitwise and)
|
||||
pub fn intersection(&self, rhs: &Self) -> Self {
|
||||
DirCaps {
|
||||
flags: self.flags & rhs.flags,
|
||||
}
|
||||
}
|
||||
pub const CREATE_DIRECTORY: Self = DirCaps { flags: 1 };
|
||||
pub const CREATE_FILE: Self = DirCaps { flags: 2 };
|
||||
pub const LINK_SOURCE: Self = DirCaps { flags: 4 };
|
||||
@@ -86,8 +124,8 @@ impl std::ops::BitOr for DirCaps {
|
||||
}
|
||||
|
||||
pub struct DirStat {
|
||||
pub base_caps: DirCaps,
|
||||
pub inheriting_caps: DirCaps,
|
||||
pub file_caps: FileCaps,
|
||||
pub dir_caps: DirCaps,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for DirCaps {
|
||||
|
||||
@@ -17,12 +17,12 @@ pub enum Error {
|
||||
GetRandom(#[from] getrandom::Error),
|
||||
|
||||
/// Errno::Notcapable: Extension: Capabilities insufficient
|
||||
#[error("File not capable: {0}")]
|
||||
FileNotCapable(FileCaps),
|
||||
#[error("File not capable: desired {desired}, has {has}")]
|
||||
FileNotCapable { desired: FileCaps, has: FileCaps },
|
||||
|
||||
/// Errno::Notcapable: Extension: Capabilities insufficient
|
||||
#[error("Directory not capable: {0}")]
|
||||
DirNotCapable(DirCaps),
|
||||
#[error("Directory not capable: desired {desired}, has {has}")]
|
||||
DirNotCapable { desired: DirCaps, has: DirCaps },
|
||||
|
||||
/// Idk what the deal with this guy is yet
|
||||
#[error("Table overflow")]
|
||||
|
||||
@@ -98,25 +98,39 @@ pub struct Filestat {
|
||||
}
|
||||
|
||||
pub(crate) struct FileEntry {
|
||||
pub(crate) base_caps: FileCaps,
|
||||
pub(crate) inheriting_caps: FileCaps,
|
||||
pub(crate) file: Box<dyn WasiFile>,
|
||||
caps: FileCaps,
|
||||
file: Box<dyn WasiFile>,
|
||||
}
|
||||
|
||||
impl FileEntry {
|
||||
pub fn new(caps: FileCaps, file: Box<dyn WasiFile>) -> Self {
|
||||
FileEntry { caps, file }
|
||||
}
|
||||
|
||||
pub fn get_cap(&self, caps: FileCaps) -> Result<&dyn WasiFile, Error> {
|
||||
if self.base_caps.contains(&caps) && self.inheriting_caps.contains(&caps) {
|
||||
if self.caps.contains(&caps) {
|
||||
Ok(self.file.deref())
|
||||
} else {
|
||||
Err(Error::FileNotCapable(caps))
|
||||
Err(Error::FileNotCapable {
|
||||
desired: caps,
|
||||
has: self.caps,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn drop_caps_to(&mut self, caps: FileCaps) -> Result<(), Error> {
|
||||
if self.caps.contains(&caps) {
|
||||
self.caps = caps;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::NotCapable)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_fdstat(&self) -> Result<FdStat, Error> {
|
||||
Ok(FdStat {
|
||||
filetype: self.file.get_filetype()?,
|
||||
base_caps: self.base_caps,
|
||||
inheriting_caps: self.inheriting_caps,
|
||||
caps: self.caps,
|
||||
flags: self.file.get_fdflags()?,
|
||||
})
|
||||
}
|
||||
@@ -137,6 +151,13 @@ impl FileCaps {
|
||||
self.flags & other.flags == other.flags
|
||||
}
|
||||
|
||||
/// Intersection of two sets of flags (bitwise and)
|
||||
pub fn intersection(&self, rhs: &Self) -> Self {
|
||||
FileCaps {
|
||||
flags: self.flags & rhs.flags,
|
||||
}
|
||||
}
|
||||
|
||||
pub const DATASYNC: Self = FileCaps { flags: 1 };
|
||||
pub const READ: Self = FileCaps { flags: 2 };
|
||||
pub const SEEK: Self = FileCaps { flags: 4 };
|
||||
@@ -168,8 +189,7 @@ impl std::fmt::Display for FileCaps {
|
||||
|
||||
pub struct FdStat {
|
||||
pub filetype: Filetype,
|
||||
pub base_caps: FileCaps,
|
||||
pub inheriting_caps: FileCaps,
|
||||
pub caps: FileCaps,
|
||||
pub flags: FdFlags,
|
||||
}
|
||||
|
||||
|
||||
@@ -178,7 +178,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
} else if table.is::<DirEntry>(fd) {
|
||||
// We cannot close preopened directories
|
||||
let dir_entry: RefMut<DirEntry> = table.get(fd).unwrap();
|
||||
if dir_entry.preopen_path.is_some() {
|
||||
if dir_entry.preopen_path().is_some() {
|
||||
return Err(Error::Notsup);
|
||||
}
|
||||
drop(dir_entry);
|
||||
@@ -230,17 +230,18 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
fs_rights_inheriting: types::Rights,
|
||||
) -> Result<(), Error> {
|
||||
let table = self.table();
|
||||
let mut file_entry: RefMut<FileEntry> = table.get(u32::from(fd))?;
|
||||
let base_caps = FileCaps::try_from(&fs_rights_base)?;
|
||||
let inheriting_caps = FileCaps::try_from(&fs_rights_inheriting)?;
|
||||
if file_entry.base_caps.contains(&base_caps)
|
||||
&& file_entry.inheriting_caps.contains(&inheriting_caps)
|
||||
{
|
||||
file_entry.base_caps = base_caps;
|
||||
file_entry.inheriting_caps = inheriting_caps;
|
||||
Ok(())
|
||||
let fd = u32::from(fd);
|
||||
if table.is::<FileEntry>(fd) {
|
||||
let mut file_entry: RefMut<FileEntry> = table.get(fd)?;
|
||||
let file_caps = FileCaps::from(&fs_rights_base);
|
||||
file_entry.drop_caps_to(file_caps)
|
||||
} else if table.is::<DirEntry>(fd) {
|
||||
let mut dir_entry: RefMut<DirEntry> = table.get(fd)?;
|
||||
let dir_caps = DirCaps::from(&fs_rights_base);
|
||||
let file_caps = FileCaps::from(&fs_rights_inheriting);
|
||||
dir_entry.drop_caps_to(dir_caps, file_caps)
|
||||
} else {
|
||||
Err(Error::NotCapable)
|
||||
Err(Error::Badf)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,7 +413,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
fn fd_prestat_get(&self, fd: types::Fd) -> Result<types::Prestat, Error> {
|
||||
let table = self.table();
|
||||
let dir_entry: RefMut<DirEntry> = table.get(u32::from(fd)).map_err(|_| Error::Badf)?;
|
||||
if let Some(ref preopen) = dir_entry.preopen_path {
|
||||
if let Some(ref preopen) = dir_entry.preopen_path() {
|
||||
let path_str = preopen.to_str().ok_or(Error::Notsup)?;
|
||||
let pr_name_len =
|
||||
u32::try_from(path_str.as_bytes().len()).map_err(|_| Error::Overflow)?;
|
||||
@@ -430,7 +431,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
) -> Result<(), Error> {
|
||||
let table = self.table();
|
||||
let dir_entry: RefMut<DirEntry> = table.get(u32::from(fd)).map_err(|_| Error::Notdir)?;
|
||||
if let Some(ref preopen) = dir_entry.preopen_path {
|
||||
if let Some(ref preopen) = dir_entry.preopen_path() {
|
||||
let path_bytes = preopen.to_str().ok_or(Error::Notsup)?.as_bytes();
|
||||
let path_len = path_bytes.len();
|
||||
if path_len < path_max_len as usize {
|
||||
@@ -573,7 +574,6 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
) -> Result<types::Fd, Error> {
|
||||
let mut table = self.table();
|
||||
let dir_entry: RefMut<DirEntry> = table.get(u32::from(dirfd))?;
|
||||
let dir = dir_entry.get_cap(DirCaps::OPEN)?;
|
||||
|
||||
let symlink_follow = dirflags.contains(&types::Lookupflags::SYMLINK_FOLLOW);
|
||||
|
||||
@@ -587,33 +587,28 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
{
|
||||
return Err(Error::Inval);
|
||||
}
|
||||
let dir = dir_entry.get_cap(DirCaps::OPEN)?;
|
||||
let child_dir = dir.open_dir(symlink_follow, path.deref())?;
|
||||
|
||||
let base_caps = DirCaps::from(&fs_rights_base);
|
||||
let inheriting_caps = DirCaps::from(&fs_rights_inheriting);
|
||||
let file_caps = dir_entry.child_file_caps(FileCaps::from(&fs_rights_base));
|
||||
let dir_caps = dir_entry.child_dir_caps(DirCaps::from(&fs_rights_inheriting));
|
||||
drop(dir);
|
||||
drop(dir_entry);
|
||||
let fd = table.push(Box::new(DirEntry {
|
||||
dir: child_dir,
|
||||
base_caps,
|
||||
inheriting_caps,
|
||||
preopen_path: None,
|
||||
}))?;
|
||||
let fd = table.push(Box::new(DirEntry::new(
|
||||
dir_caps, file_caps, None, child_dir,
|
||||
)))?;
|
||||
Ok(types::Fd::from(fd))
|
||||
} else {
|
||||
// XXX go back and check these caps conversions - probably need to validate them
|
||||
// against ???
|
||||
let base_caps = FileCaps::from(&fs_rights_base);
|
||||
let inheriting_caps = FileCaps::from(&fs_rights_inheriting);
|
||||
let mut required_caps = DirCaps::OPEN;
|
||||
if oflags.contains(&OFlags::CREATE) {
|
||||
required_caps = required_caps | DirCaps::CREATE_FILE;
|
||||
}
|
||||
|
||||
let file = dir.open_file(symlink_follow, path.deref(), oflags, base_caps)?;
|
||||
let dir = dir_entry.get_cap(required_caps)?;
|
||||
let file_caps = dir_entry.child_file_caps(FileCaps::from(&fs_rights_base));
|
||||
let file = dir.open_file(symlink_follow, path.deref(), oflags, file_caps)?;
|
||||
drop(dir);
|
||||
drop(dir_entry);
|
||||
let fd = table.push(Box::new(FileEntry {
|
||||
file,
|
||||
base_caps,
|
||||
inheriting_caps,
|
||||
}))?;
|
||||
let fd = table.push(Box::new(FileEntry::new(file_caps, file)))?;
|
||||
Ok(types::Fd::from(fd))
|
||||
}
|
||||
}
|
||||
@@ -724,8 +719,8 @@ impl From<&FdStat> for types::Fdstat {
|
||||
fn from(fdstat: &FdStat) -> types::Fdstat {
|
||||
types::Fdstat {
|
||||
fs_filetype: types::Filetype::from(&fdstat.filetype),
|
||||
fs_rights_base: types::Rights::from(&fdstat.base_caps),
|
||||
fs_rights_inheriting: types::Rights::from(&fdstat.inheriting_caps),
|
||||
fs_rights_base: types::Rights::from(&fdstat.caps),
|
||||
fs_rights_inheriting: types::Rights::empty(),
|
||||
fs_flags: types::Fdflags::from(&fdstat.flags),
|
||||
}
|
||||
}
|
||||
@@ -735,8 +730,8 @@ impl From<&DirStat> for types::Fdstat {
|
||||
fn from(dirstat: &DirStat) -> types::Fdstat {
|
||||
types::Fdstat {
|
||||
fs_filetype: types::Filetype::Directory,
|
||||
fs_rights_base: types::Rights::from(&dirstat.base_caps),
|
||||
fs_rights_inheriting: types::Rights::from(&dirstat.inheriting_caps),
|
||||
fs_rights_base: types::Rights::from(&dirstat.file_caps),
|
||||
fs_rights_inheriting: types::Rights::from(&dirstat.dir_caps),
|
||||
fs_flags: types::Fdflags::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user