Skip to content

Commit 828e86c

Browse files
committed
Start to trim down filesystem::primitives
This commit is an attempt to start trimming down the vendored `cap-primitives` implementation with fewer layers of indirection and, ideally, more based on `std`-defined types rather than redefining everything in this crate. This for now starts to remove some of the smaller modules that no longer serve much purpose and instead inline the implementations directly (or `pub use` them). This additionally trims the reexports of the `primitives` module to only `pub(crate)`-define items actually used by `wasmtime-wasi`. Internal helpers are now no longer exported from the module.
1 parent 92f238b commit 828e86c

15 files changed

Lines changed: 154 additions & 363 deletions

File tree

crates/wasi/src/filesystem/primitives/create_dir.rs

Lines changed: 0 additions & 14 deletions
This file was deleted.

crates/wasi/src/filesystem/primitives/follow_symlinks.rs

Lines changed: 0 additions & 16 deletions
This file was deleted.

crates/wasi/src/filesystem/primitives/hard_link.rs

Lines changed: 0 additions & 19 deletions
This file was deleted.

crates/wasi/src/filesystem/primitives/mod.rs

Lines changed: 146 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -17,70 +17,172 @@
1717
reason = "preexisting from when cap-primitives was imported"
1818
)]
1919

20-
mod create_dir;
20+
use std::path::{Path, PathBuf};
21+
use std::{fs, io};
22+
2123
mod dir_entry;
2224
mod dir_options;
2325
mod file_type;
24-
mod follow_symlinks;
25-
mod hard_link;
2626
mod maybe_owned_file;
2727
mod metadata;
28-
mod open;
29-
mod open_dir;
3028
mod open_options;
3129
mod open_unchecked_error;
3230
mod read_dir;
33-
mod read_link;
34-
mod remove_dir;
35-
mod remove_file;
36-
mod rename;
37-
mod set_times;
38-
mod stat;
39-
mod symlink;
40-
41-
pub(crate) mod errors;
42-
pub(crate) mod manually;
43-
pub(crate) mod via_parent;
4431

45-
use maybe_owned_file::MaybeOwnedFile;
32+
mod errors;
33+
mod manually;
34+
mod via_parent;
4635

47-
pub(crate) use open_unchecked_error::*;
36+
#[cfg(test)]
37+
mod tests;
4838

4939
#[cfg(not(windows))]
5040
mod rustix;
5141
#[cfg(not(windows))]
52-
pub(crate) use self::rustix::fs::*;
42+
use self::rustix::fs as sys;
5343
#[cfg(windows)]
5444
mod windows;
5545
#[cfg(windows)]
56-
pub(crate) use self::windows::fs::*;
46+
use self::windows::fs as sys;
5747

58-
pub use create_dir::create_dir;
59-
pub use dir_entry::DirEntry;
60-
pub use dir_options::DirOptions;
6148
#[cfg(windows)]
62-
pub use file_type::_WindowsFileTypeExt;
63-
pub use file_type::FileType;
49+
use file_type::_WindowsFileTypeExt;
50+
use maybe_owned_file::MaybeOwnedFile;
51+
use open_unchecked_error::*;
52+
use sys::read_link_impl as read_link_contents;
53+
use sys::*;
54+
55+
pub(crate) use dir_entry::DirEntry;
56+
pub(crate) use dir_options::DirOptions;
57+
pub(crate) use file_type::FileType;
6458
#[cfg(any(unix, target_os = "vxworks"))]
65-
pub use file_type::FileTypeExt;
66-
pub use follow_symlinks::FollowSymlinks;
67-
pub use hard_link::hard_link;
59+
pub(crate) use file_type::FileTypeExt;
6860
#[cfg(windows)]
69-
pub use metadata::_WindowsByHandle;
70-
pub use metadata::{Metadata, MetadataExt};
71-
pub use open::open;
72-
pub use open_dir::*;
73-
pub use open_options::*;
74-
pub use read_dir::read_base_dir;
75-
pub use read_link::read_link;
76-
pub use remove_dir::remove_dir;
77-
pub use remove_file::remove_file;
78-
pub use rename::rename;
79-
pub use set_times::{set_times, set_times_nofollow};
80-
pub use stat::stat;
61+
pub(crate) use metadata::_WindowsByHandle;
62+
pub(crate) use metadata::{Metadata, MetadataExt};
63+
pub(crate) use open_options::*;
64+
pub(crate) use read_dir::read_base_dir;
65+
pub(crate) use sys::create_dir_impl as create_dir;
66+
pub(crate) use sys::hard_link_impl as hard_link;
67+
pub(crate) use sys::open_ambient_dir_impl as open_ambient_dir;
68+
pub(crate) use sys::open_impl as open;
69+
pub(crate) use sys::remove_dir_impl as remove_dir;
70+
pub(crate) use sys::remove_file_impl as remove_file;
71+
pub(crate) use sys::rename_impl as rename;
72+
pub(crate) use sys::set_times_impl as set_times;
73+
pub(crate) use sys::set_times_nofollow_impl as set_times_nofollow;
74+
pub(crate) use sys::stat_impl as stat;
75+
76+
/// Should symlinks be followed in the last component of a path?
77+
///
78+
/// This doesn't affect path components other than the last. So for example in
79+
/// "foo/bar/baz", if "foo" or "bar" are symlinks, they will always be
80+
/// followed. This enum value only determines whether "baz" is followed.
81+
///
82+
/// Instead of passing bare `bool`s as parameters, pass a distinct enum so that
83+
/// the intent is clear.
84+
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
85+
pub(crate) enum FollowSymlinks {
86+
/// Yes, do follow symlinks in the last component of a path.
87+
Yes,
88+
89+
/// No, do not follow symlinks in the last component of a path.
90+
No,
91+
}
92+
93+
/// Like [`read_link_contents`], but additionally verifies that the link target
94+
/// is not absolute.
95+
#[inline]
96+
pub(crate) fn read_link(start: &fs::File, path: &Path) -> io::Result<PathBuf> {
97+
let contents = read_link_contents(start, path)?;
98+
99+
// Don't allow reading symlinks to absolute paths. This isn't strictly
100+
// necessary to preserve the sandbox, since `open` will refuse to follow
101+
// absolute paths in any case. However, it is useful to enforce this
102+
// restriction to avoid leaking information about the host filesystem
103+
// outside the sandbox.
104+
if contents.has_root() {
105+
return Err(errors::escape_attempt());
106+
}
107+
108+
Ok(contents)
109+
}
110+
111+
/// Perform a `symlinkat`-like operation, ensuring that the resolution of the
112+
/// path never escapes the directory tree rooted at `start`. An error is
113+
/// returned if the target path is absolute.
81114
#[cfg(not(windows))]
82-
pub use symlink::symlink;
115+
#[inline]
116+
pub(crate) fn symlink(old_path: &Path, new_start: &fs::File, new_path: &Path) -> io::Result<()> {
117+
// Don't allow creating symlinks to absolute paths. This isn't strictly
118+
// necessary to preserve the sandbox, since `open` will refuse to follow
119+
// absolute symlinks in any case. However, it is useful to enforce this
120+
// restriction so that a WASI program can't trick some other non-WASI
121+
// program into following an absolute path.
122+
if old_path.has_root() {
123+
return Err(errors::escape_attempt());
124+
}
125+
126+
sys::symlink_impl(old_path, new_start, new_path)
127+
}
128+
129+
/// Perform a `symlink_file`-like operation, ensuring that the resolution of
130+
/// the path never escapes the directory tree rooted at `start`.
83131
#[cfg(windows)]
84-
pub use symlink::{symlink_dir, symlink_file};
85-
#[cfg(test)]
86-
mod tests;
132+
#[inline]
133+
pub(crate) fn symlink_file(
134+
old_path: &Path,
135+
new_start: &fs::File,
136+
new_path: &Path,
137+
) -> io::Result<()> {
138+
// As above, don't allow creating symlinks to absolute paths.
139+
if old_path.has_root() {
140+
return Err(errors::escape_attempt());
141+
}
142+
143+
sys::symlink_file_impl(old_path, new_start, new_path)
144+
}
145+
146+
/// Perform a `symlink_dir`-like operation, ensuring that the resolution of the
147+
/// path never escapes the directory tree rooted at `start`.
148+
#[cfg(windows)]
149+
#[inline]
150+
pub(crate) fn symlink_dir(
151+
old_path: &Path,
152+
new_start: &fs::File,
153+
new_path: &Path,
154+
) -> io::Result<()> {
155+
// As above, don't allow creating symlinks to absolute paths.
156+
if old_path.has_root() {
157+
return Err(errors::escape_attempt());
158+
}
159+
160+
sys::symlink_dir_impl(old_path, new_start, new_path)
161+
}
162+
163+
/// Open a directory by performing an `openat`-like operation, ensuring that
164+
/// the resolution of the path never escapes the directory tree rooted at
165+
/// `start`.
166+
#[inline]
167+
fn open_dir(start: &fs::File, path: &Path) -> io::Result<fs::File> {
168+
open(start, path, &dir_options())
169+
}
170+
171+
/// Open a directory by performing an unsandboxed `openat`-like operation.
172+
#[inline]
173+
#[allow(dead_code)]
174+
fn open_dir_unchecked(start: &fs::File, path: &Path) -> io::Result<fs::File> {
175+
open_unchecked(start, path, &dir_options()).map_err(Into::into)
176+
}
177+
178+
/// Like `open_dir_unchecked`, but additionally request the ability to read the
179+
/// directory entries.
180+
#[inline]
181+
#[allow(dead_code)]
182+
fn open_dir_for_reading_unchecked(
183+
start: &fs::File,
184+
path: &Path,
185+
follow: FollowSymlinks,
186+
) -> io::Result<fs::File> {
187+
open_unchecked(start, path, readdir_options().follow(follow)).map_err(Into::into)
188+
}

crates/wasi/src/filesystem/primitives/open.rs

Lines changed: 0 additions & 14 deletions
This file was deleted.

crates/wasi/src/filesystem/primitives/open_dir.rs

Lines changed: 0 additions & 49 deletions
This file was deleted.

crates/wasi/src/filesystem/primitives/read_link.rs

Lines changed: 0 additions & 36 deletions
This file was deleted.

crates/wasi/src/filesystem/primitives/remove_dir.rs

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)