mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Fix CVE-2022-21658 for WASI
This commit is contained in:
parent
54e22eb7db
commit
cb748a27d2
@ -16,7 +16,7 @@ use crate::sys::time::SystemTime;
|
||||
use crate::sys::unsupported;
|
||||
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 {
|
||||
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 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("ReadDir").finish_non_exhaustive()
|
||||
@ -516,13 +528,7 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
|
||||
opts.directory(true);
|
||||
opts.read(true);
|
||||
let dir = File::open(p, &opts)?;
|
||||
Ok(ReadDir {
|
||||
cookie: Some(0),
|
||||
buf: vec![0; 128],
|
||||
offset: 0,
|
||||
cap: 0,
|
||||
inner: Arc::new(ReadDirInner { dir, root: p.to_path_buf() }),
|
||||
})
|
||||
Ok(ReadDir::new(dir, p.to_path_buf()))
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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…
Reference in New Issue
Block a user