Skip to content

Commit bb17882

Browse files
amrbashirlucasfernog
authored andcommitted
fix(endpoints/fs/readDir): don't read symlinks that are not allowed b… (#5123)
1 parent 679abc6 commit bb17882

File tree

4 files changed

+54
-9
lines changed

4 files changed

+54
-9
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": patch
3+
---
4+
5+
Fix `fs.readDir` recursive option reading symlinked directories that are not allowed by the scope.

core/tauri/src/api/dir.rs

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
77
use serde::Serialize;
88
use std::{
9-
fs::{self, metadata},
9+
fs::{self, metadata, symlink_metadata},
1010
path::{Path, PathBuf},
1111
};
1212
use tempfile::{self, tempdir};
@@ -31,8 +31,36 @@ pub fn is_dir<P: AsRef<Path>>(path: P) -> crate::api::Result<bool> {
3131
metadata(path).map(|md| md.is_dir()).map_err(Into::into)
3232
}
3333

34+
fn is_symlink<P: AsRef<Path>>(path: P) -> crate::api::Result<bool> {
35+
// TODO: remove the different implementation once we raise tauri's MSRV to at least 1.58
36+
#[cfg(windows)]
37+
let ret = symlink_metadata(path)
38+
.map(|md| md.is_symlink())
39+
.map_err(Into::into);
40+
41+
#[cfg(not(windows))]
42+
let ret = symlink_metadata(path)
43+
.map(|md| md.file_type().is_symlink())
44+
.map_err(Into::into);
45+
46+
ret
47+
}
48+
3449
/// Reads a directory. Can perform recursive operations.
3550
pub fn read_dir<P: AsRef<Path>>(path: P, recursive: bool) -> crate::api::Result<Vec<DiskEntry>> {
51+
read_dir_with_options(path, recursive, ReadDirOptions { scope: None })
52+
}
53+
54+
#[derive(Clone, Copy)]
55+
pub(crate) struct ReadDirOptions<'a> {
56+
pub scope: Option<&'a crate::FsScope>,
57+
}
58+
59+
pub(crate) fn read_dir_with_options<P: AsRef<Path>>(
60+
path: P,
61+
recursive: bool,
62+
options: ReadDirOptions<'_>,
63+
) -> crate::api::Result<Vec<DiskEntry>> {
3664
let mut files_and_dirs: Vec<DiskEntry> = vec![];
3765
for entry in fs::read_dir(path)? {
3866
let path = entry?.path();
@@ -42,11 +70,16 @@ pub fn read_dir<P: AsRef<Path>>(path: P, recursive: bool) -> crate::api::Result<
4270
files_and_dirs.push(DiskEntry {
4371
path: path.clone(),
4472
children: if flag {
45-
Some(if recursive {
46-
read_dir(&path_as_string, true)?
47-
} else {
48-
vec![]
49-
})
73+
Some(
74+
if recursive
75+
&& (!is_symlink(&path_as_string)?
76+
|| options.scope.map(|s| s.is_allowed(&path)).unwrap_or(true))
77+
{
78+
read_dir_with_options(&path_as_string, true, options)?
79+
} else {
80+
vec![]
81+
},
82+
)
5083
} else {
5184
None
5285
},

core/tauri/src/api/file.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ pub fn read_binary<P: AsRef<Path>>(file: P) -> crate::api::Result<Vec<u8>> {
7474
#[cfg(test)]
7575
mod test {
7676
use super::*;
77+
#[cfg(not(windows))]
7778
use crate::api::Error;
7879
use quickcheck::{Arbitrary, Gen};
7980

core/tauri/src/endpoints/file_system.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,15 @@ impl Cmd {
191191
path,
192192
dir,
193193
)?;
194-
dir::read_dir(&resolved_path, recursive)
195-
.with_context(|| format!("path: {}", resolved_path.display()))
196-
.map_err(Into::into)
194+
dir::read_dir_with_options(
195+
&resolved_path,
196+
recursive,
197+
dir::ReadDirOptions {
198+
scope: Some(&context.window.state::<Scopes>().fs),
199+
},
200+
)
201+
.with_context(|| format!("path: {}", resolved_path.display()))
202+
.map_err(Into::into)
197203
}
198204

199205
#[module_command_handler(fs_copy_file)]

0 commit comments

Comments
 (0)