File 0002-Fix-CVE-2022-21658-for-WASI.patch of Package rust1.55.22465
From e278518f1f8ae1afd64048668b894dcdac1723d3 Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Tue, 4 Jan 2022 08:44:15 -0800
Subject: [PATCH 2/2] Fix CVE-2022-21658 for WASI
---
library/std/src/sys/wasi/fs.rs | 71 ++++++++++++++++++++++++++++++----
1 file changed, 63 insertions(+), 8 deletions(-)
diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs
index 8ffa1c88d88..c34b7bb75b4 100644
--- a/library/std/src/sys/wasi/fs.rs
+++ b/library/std/src/sys/wasi/fs.rs
@@ -14,7 +14,7 @@
use crate::sys::unsupported;
use crate::sys_common::FromInner;
-pub use crate::sys_common::fs::{remove_dir_all, try_exists};
+pub use crate::sys_common::fs::try_exists;
pub struct File {
fd: WasiFd,
@@ -128,6 +128,18 @@ pub fn bits(&self) -> wasi::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()
@@ -482,13 +494,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<()> {
@@ -682,3 +688,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())?)
+}
--
2.34.1