/rust/registry/src/index.crates.io-6f17d22bba15001f/cap-primitives-3.4.4/src/fs/canonicalize.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! Sandboxed path canonicalization. |
2 | | |
3 | | use crate::fs::canonicalize_impl; |
4 | | #[cfg(racy_asserts)] |
5 | | use crate::fs::{file_path, open, OpenOptions}; |
6 | | use std::path::{Path, PathBuf}; |
7 | | use std::{fs, io}; |
8 | | |
9 | | /// Canonicalize the given path, ensuring that the resolution of the path never |
10 | | /// escapes the directory tree rooted at `start`. |
11 | | #[cfg_attr(not(racy_asserts), allow(clippy::let_and_return))] |
12 | | #[inline] |
13 | 0 | pub fn canonicalize(start: &fs::File, path: &Path) -> io::Result<PathBuf> { |
14 | 0 | // Call the underlying implementation. |
15 | 0 | let result = canonicalize_impl(start, path); |
16 | 0 |
|
17 | 0 | #[cfg(racy_asserts)] |
18 | 0 | check_canonicalize(start, path, &result); |
19 | 0 |
|
20 | 0 | result |
21 | 0 | } |
22 | | |
23 | | #[cfg(racy_asserts)] |
24 | | fn check_canonicalize(start: &fs::File, path: &Path, result: &io::Result<PathBuf>) { |
25 | | if let Ok(canonical_path) = result { |
26 | | let path_result = open(start, path, OpenOptions::new().read(true)); |
27 | | let canonical_result = open(start, canonical_path, OpenOptions::new().read(true)); |
28 | | match (path_result, canonical_result) { |
29 | | (Ok(path_file), Ok(canonical_file)) => assert_same_file!( |
30 | | &path_file, |
31 | | &canonical_file, |
32 | | "we should be able to stat paths that we just canonicalized" |
33 | | ), |
34 | | (Err(path_err), Err(canonical_err)) => { |
35 | | assert_eq!(path_err.to_string(), canonical_err.to_string()) |
36 | | } |
37 | | other => { |
38 | | // TODO: Checking in the case it does end with ".". |
39 | | if !path.to_string_lossy().ends_with("/.") { |
40 | | panic!("inconsistent canonicalize checks: {:?}", other); |
41 | | } |
42 | | } |
43 | | } |
44 | | |
45 | | // On operating systems which can tell us the path of a file descriptor, |
46 | | // assert that the path we computed canonicalizes to the same thing as |
47 | | // the input canonicalizes too. |
48 | | if let Some(start_abspath) = file_path(start) { |
49 | | let check_abspath = start_abspath.join(path); |
50 | | let result_abspath = start_abspath.join(canonical_path); |
51 | | if let Ok(check_abspath) = fs::canonicalize(check_abspath) { |
52 | | let result_abspath = |
53 | | fs::canonicalize(result_abspath).expect("we already canonicalized this"); |
54 | | assert_eq!( |
55 | | check_abspath, |
56 | | result_abspath, |
57 | | "incorrect canonicalization: start='{:?}' path='{}' result='{}'", |
58 | | start, |
59 | | path.display(), |
60 | | canonical_path.display() |
61 | | ); |
62 | | // TODO: When porting to Windows, check whether `start_abspath` not being |
63 | | // a canonicalized path leads to `\\?\` extended path prefix differences. |
64 | | assert!( |
65 | | result_abspath.starts_with(start_abspath), |
66 | | "sandbox escape: start='{:?}' path='{}' result='{}'", |
67 | | start, |
68 | | path.display(), |
69 | | canonical_path.display() |
70 | | ); |
71 | | } |
72 | | } |
73 | | } |
74 | | } |