fix(fs): validate symlink in set_files

Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
fufesou
2026-04-03 20:30:57 +08:00
parent b50bcfb158
commit 4b6eb8f909

View File

@@ -626,6 +626,11 @@ impl TransferJob {
#[inline]
pub fn set_files(&mut self, files: Vec<FileEntry>) -> ResultType<()> {
validate_transfer_file_names(&files)?;
if let DataSource::FilePath(base) = &self.data_source {
for file in &files {
validate_no_symlink_components(base, &file.name)?;
}
}
self.files = files;
Ok(())
}
@@ -1704,4 +1709,49 @@ mod tests {
.expect_err("drive-letter absolute path must be rejected");
assert_err_contains(err, "absolute path");
}
#[test]
fn set_files_rejects_symlink_path_component() {
let tmp_root = unique_temp_dir("rustdesk_set_files_symlink");
let downloads = tmp_root.join("downloads");
let outside = tmp_root.join("outside");
std::fs::create_dir_all(&downloads).expect("create downloads dir");
std::fs::create_dir_all(&outside).expect("create outside dir");
let symlink_path = downloads.join("link");
#[cfg(unix)]
{
use std::os::unix::fs::symlink;
if symlink(&outside, &symlink_path).is_err() {
let _ = std::fs::remove_dir_all(&tmp_root);
return;
}
}
#[cfg(windows)]
{
use std::os::windows::fs::symlink_dir;
if symlink_dir(&outside, &symlink_path).is_err() {
let _ = std::fs::remove_dir_all(&tmp_root);
return;
}
}
let mut job = TransferJob::new_write(
107,
JobType::Generic,
"/fake/remote".to_string(),
DataSource::FilePath(downloads),
0,
false,
true,
Vec::new(),
false,
);
let err = job
.set_files(vec![new_file_entry("link/escape.txt")])
.expect_err("symlink component must be rejected");
assert_err_contains(err, "symlink");
let _ = std::fs::remove_dir_all(&tmp_root);
}
}