Skip to content

Commit b6e5bb5

Browse files
committed
Add tests that backslashes in symlinks don't lead to sandbox escape
1 parent 83501b9 commit b6e5bb5

1 file changed

Lines changed: 53 additions & 3 deletions

File tree

tests/rust/wasm32-wasip3/src/bin/filesystem-symbolic-links.rs

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ use wasi::filesystem::types::Descriptor;
2020
use wasi::filesystem::types::{DescriptorFlags, ErrorCode, OpenFlags, PathFlags};
2121

2222
async fn test_symbolic_links(dir: &Descriptor) {
23+
// symlink-at: async func(old-path: string, new-path: string) -> result<_, error-code>;
2324
let ln_s = |from: &str, to: &str| -> _ { dir.symlink_at(from.to_string(), to.to_string()) };
25+
// readlink-at: async func(path: string) -> result<string, error-code>;
2426
let readlink = |path: &str| dir.readlink_at(path.to_string());
2527
let stat_with_flags = |flags: PathFlags, path: &str| dir.stat_at(flags, path.to_string());
2628
let stat_follow = |path: &str| stat_with_flags(PathFlags::SYMLINK_FOLLOW, path);
@@ -42,7 +44,6 @@ async fn test_symbolic_links(dir: &Descriptor) {
4244
};
4345
let rm = |path: &str| dir.unlink_file_at(path.to_string());
4446

45-
// readlink-at: async func(path: string) -> result<string, error-code>;
4647
assert_eq!(readlink("").await, Err(ErrorCode::NoEntry));
4748
assert_eq!(readlink(".").await, Err(ErrorCode::Invalid));
4849
assert_eq!(readlink("a.txt").await, Err(ErrorCode::Invalid));
@@ -58,7 +59,7 @@ async fn test_symbolic_links(dir: &Descriptor) {
5859
Err(ErrorCode::NotDirectory)
5960
);
6061

61-
// https://github.com/WebAssembly/wasi-filesystem/issues/186
62+
// https://github.com/WebAssembly/WASI/issues/718
6263
assert_eq!(
6364
open_r("parent")
6465
.await
@@ -90,7 +91,56 @@ async fn test_symbolic_links(dir: &Descriptor) {
9091

9192
assert_eq!(ln_s("whatever", "").await, Err(ErrorCode::NoEntry));
9293
assert_eq!(ln_s("", "whatever").await, Err(ErrorCode::NoEntry));
93-
// symlink-at: async func(old-path: string, new-path: string) -> result<_, error-code>;
94+
95+
ln_s("..\\.", "parent-link").await.unwrap();
96+
assert_eq!(open_r("parent-link").await.unwrap_err(), ErrorCode::Loop);
97+
match open_r_follow("parent-link/fs-tests.dir").await {
98+
// Backslashes are not separators.
99+
Err(ErrorCode::NoEntry) => (),
100+
// Backslashes are separators.
101+
Err(ErrorCode::NotPermitted) => {
102+
assert_eq!(
103+
stat_follow("parent-link").await.unwrap_err(),
104+
ErrorCode::NotPermitted
105+
);
106+
assert_eq!(
107+
open_r("parent-link/fs-tests.dir/a.txt").await.unwrap_err(),
108+
ErrorCode::NotPermitted
109+
);
110+
assert_eq!(
111+
ln_s("a.txt", "parent-link/fs-tests.dir/q.txt").await,
112+
Err(ErrorCode::NotPermitted)
113+
);
114+
}
115+
Err(e) => panic!("unexpected error: {}", e),
116+
Ok(_) => panic!("unexpected success"),
117+
}
118+
rm("parent-link").await.unwrap();
119+
120+
ln_s("..\\fs-tests.dir", "self-link").await.unwrap();
121+
assert_eq!(open_r("self-link").await.unwrap_err(), ErrorCode::Loop);
122+
match open_r_follow("self-link").await {
123+
// Backslashes are not separators.
124+
Err(ErrorCode::NoEntry) => (),
125+
// Backslashes are separators.
126+
Err(ErrorCode::NotPermitted) => {
127+
assert_eq!(
128+
stat_follow("self-link").await.unwrap_err(),
129+
ErrorCode::NotPermitted
130+
);
131+
assert_eq!(
132+
open_r("self-link/a.txt").await.unwrap_err(),
133+
ErrorCode::NotPermitted
134+
);
135+
assert_eq!(
136+
ln_s("a.txt", "self-link/q.txt").await,
137+
Err(ErrorCode::NotPermitted)
138+
);
139+
}
140+
Err(e) => panic!("unexpected error: {}", e),
141+
Ok(_) => panic!("unexpected success"),
142+
}
143+
rm("self-link").await.unwrap();
94144
}
95145

96146
struct Component;

0 commit comments

Comments
 (0)