Canonicalize sandbox paths to prevent symlink bypass
Richard Feldman
created 1 month ago
Resolve symlinks via std::fs::canonicalize on all sandbox paths
before applying the OS-level sandbox. Without this, a symlink
pointing outside the intended sandbox boundary would be followed
and the target would be accessible.
project_dir canonicalization failure logs a warning. System and
additional paths silently fall back to the original path if they
don't exist (handled gracefully downstream).
Change summary
crates/terminal/src/sandbox_exec.rs | 3 +
crates/terminal/src/terminal_settings.rs | 29 ++++++++++++++++++++++++++
2 files changed, 31 insertions(+), 1 deletion(-)
Detailed changes
@@ -139,7 +139,8 @@ pub fn sandbox_exec_main(config_json: &str, shell_args: &[String]) -> ! {
std::process::exit(1);
}
- let sandbox_config = config.to_sandbox_config();
+ let mut sandbox_config = config.to_sandbox_config();
+ sandbox_config.canonicalize_paths();
// Step 1: Filter environment variables.
// Keep only allowed vars + a few Zed-specific ones.
@@ -403,4 +403,33 @@ impl SandboxConfig {
.unwrap_or_else(Self::default_allowed_env_vars),
}
}
+
+ pub fn canonicalize_paths(&mut self) {
+ match std::fs::canonicalize(&self.project_dir) {
+ Ok(canonical) => self.project_dir = canonical,
+ Err(err) => log::warn!(
+ "Failed to canonicalize project dir {:?}: {}",
+ self.project_dir,
+ err
+ ),
+ }
+ canonicalize_path_list(&mut self.system_paths.executable);
+ canonicalize_path_list(&mut self.system_paths.read_only);
+ canonicalize_path_list(&mut self.system_paths.read_write);
+ canonicalize_path_list(&mut self.additional_executable_paths);
+ canonicalize_path_list(&mut self.additional_read_only_paths);
+ canonicalize_path_list(&mut self.additional_read_write_paths);
+ }
+}
+
+fn try_canonicalize(path: &mut PathBuf) {
+ if let Ok(canonical) = std::fs::canonicalize(&*path) {
+ *path = canonical;
+ }
+}
+
+fn canonicalize_path_list(paths: &mut Vec<PathBuf>) {
+ for path in paths.iter_mut() {
+ try_canonicalize(path);
+ }
}