Fix CVE-2022-21658 for WASI
This commit is contained in:
parent
54e22eb7db
commit
cb748a27d2
1 changed files with 63 additions and 8 deletions
|
@ -16,7 +16,7 @@ use crate::sys::time::SystemTime;
|
||||||
use crate::sys::unsupported;
|
use crate::sys::unsupported;
|
||||||
use crate::sys_common::{AsInner, FromInner, IntoInner};
|
use crate::sys_common::{AsInner, FromInner, IntoInner};
|
||||||
|
|
||||||
pub use crate::sys_common::fs::{remove_dir_all, try_exists};
|
pub use crate::sys_common::fs::try_exists;
|
||||||
|
|
||||||
pub struct File {
|
pub struct File {
|
||||||
fd: WasiFd,
|
fd: WasiFd,
|
||||||
|
@ -130,6 +130,18 @@ impl FileType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ReadDir {
|
||||||
|
fn new(dir: File, root: PathBuf) -> ReadDir {
|
||||||
|
ReadDir {
|
||||||
|
cookie: Some(0),
|
||||||
|
buf: vec![0; 128],
|
||||||
|
offset: 0,
|
||||||
|
cap: 0,
|
||||||
|
inner: Arc::new(ReadDirInner { dir, root }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Debug for ReadDir {
|
impl fmt::Debug for ReadDir {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("ReadDir").finish_non_exhaustive()
|
f.debug_struct("ReadDir").finish_non_exhaustive()
|
||||||
|
@ -516,13 +528,7 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
|
||||||
opts.directory(true);
|
opts.directory(true);
|
||||||
opts.read(true);
|
opts.read(true);
|
||||||
let dir = File::open(p, &opts)?;
|
let dir = File::open(p, &opts)?;
|
||||||
Ok(ReadDir {
|
Ok(ReadDir::new(dir, p.to_path_buf()))
|
||||||
cookie: Some(0),
|
|
||||||
buf: vec![0; 128],
|
|
||||||
offset: 0,
|
|
||||||
cap: 0,
|
|
||||||
inner: Arc::new(ReadDirInner { dir, root: p.to_path_buf() }),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unlink(p: &Path) -> io::Result<()> {
|
pub fn unlink(p: &Path) -> io::Result<()> {
|
||||||
|
@ -716,3 +722,52 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
|
||||||
|
|
||||||
io::copy(&mut reader, &mut writer)
|
io::copy(&mut reader, &mut writer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
|
||||||
|
let (parent, path) = open_parent(path)?;
|
||||||
|
remove_dir_all_recursive(&parent, &path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_dir_all_recursive(parent: &WasiFd, path: &Path) -> io::Result<()> {
|
||||||
|
// Open up a file descriptor for the directory itself. Note that we don't
|
||||||
|
// follow symlinks here and we specifically open directories.
|
||||||
|
//
|
||||||
|
// At the root invocation of this function this will correctly handle
|
||||||
|
// symlinks passed to the top-level `remove_dir_all`. At the recursive
|
||||||
|
// level this will double-check that after the `readdir` call deduced this
|
||||||
|
// was a directory it's still a directory by the time we open it up.
|
||||||
|
//
|
||||||
|
// If the opened file was actually a symlink then the symlink is deleted,
|
||||||
|
// not the directory recursively.
|
||||||
|
let mut opts = OpenOptions::new();
|
||||||
|
opts.lookup_flags(0);
|
||||||
|
opts.directory(true);
|
||||||
|
opts.read(true);
|
||||||
|
let fd = open_at(parent, path, &opts)?;
|
||||||
|
if fd.file_attr()?.file_type().is_symlink() {
|
||||||
|
return parent.unlink_file(osstr2str(path.as_ref())?);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this "root" is only used by `DirEntry::path` which we don't use below so
|
||||||
|
// it's ok for this to be a bogus value
|
||||||
|
let dummy_root = PathBuf::new();
|
||||||
|
|
||||||
|
// Iterate over all the entries in this directory, and travel recursively if
|
||||||
|
// necessary
|
||||||
|
for entry in ReadDir::new(fd, dummy_root) {
|
||||||
|
let entry = entry?;
|
||||||
|
let path = crate::str::from_utf8(&entry.name).map_err(|_| {
|
||||||
|
io::Error::new_const(io::ErrorKind::Uncategorized, &"invalid utf-8 file name found")
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if entry.file_type()?.is_dir() {
|
||||||
|
remove_dir_all_recursive(&entry.inner.dir.fd, path.as_ref())?;
|
||||||
|
} else {
|
||||||
|
entry.inner.dir.fd.unlink_file(path)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once all this directory's contents are deleted it should be safe to
|
||||||
|
// delete the directory tiself.
|
||||||
|
parent.remove_directory(osstr2str(path.as_ref())?)
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue