Skip to content

Commit 8977b05

Browse files
committed
Allow setting custom mount flags
1 parent 22cf6a6 commit 8977b05

File tree

3 files changed

+119
-1
lines changed

3 files changed

+119
-1
lines changed

src/transport/fusedev/linux_session.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ pub struct FuseSession {
5656
target_mntns: Option<libc::pid_t>,
5757
// fusermount binary, default to fusermount3
5858
fusermount: String,
59+
mount_flags: Option<MsFlags>,
5960
}
6061

6162
impl FuseSession {
@@ -97,6 +98,7 @@ impl FuseSession {
9798
target_mntns: None,
9899
fusermount: FUSERMOUNT_BIN.to_string(),
99100
allow_other: true,
101+
mount_flags: None,
100102
})
101103
}
102104

@@ -133,6 +135,21 @@ impl FuseSession {
133135
self.file = Some(file);
134136
}
135137

138+
/// Set custom mount flags for the session.
139+
/// If not set, default flags (MS_NOSUID | MS_NODEV | MS_NOATIME) will be
140+
/// used. MS_RDONLY will be added automatically if the session is readonly.
141+
/// Not setting MS_NOSUID and MS_NODEV will probably get ignored by
142+
/// fusermount3 for security reasons, so it means you need to be root to
143+
/// mount the FS.
144+
pub fn set_mount_flags(&mut self, flags: MsFlags) {
145+
self.mount_flags = Some(flags);
146+
}
147+
148+
/// Get the currently configured mount flags, or None if using defaults.
149+
pub fn get_mount_flags(&self) -> Option<MsFlags> {
150+
self.mount_flags
151+
}
152+
136153
/// Clone fuse file using ioctl FUSE_DEV_IOC_CLONE.
137154
pub fn clone_fuse_file(&self) -> Result<File> {
138155
let mut old_fd = self
@@ -184,7 +201,9 @@ impl FuseSession {
184201

185202
/// Mount the fuse mountpoint, building connection with the in kernel fuse driver.
186203
pub fn mount(&mut self) -> Result<()> {
187-
let mut flags = MsFlags::MS_NOSUID | MsFlags::MS_NODEV | MsFlags::MS_NOATIME;
204+
let mut flags = self.mount_flags.unwrap_or(
205+
MsFlags::MS_NOSUID | MsFlags::MS_NODEV | MsFlags::MS_NOATIME
206+
);
188207
if self.readonly {
189208
flags |= MsFlags::MS_RDONLY;
190209
}

tests/example/passthroughfs.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::thread;
1111
use fuse_backend_rs::api::{server::Server, Vfs, VfsOptions};
1212
use fuse_backend_rs::passthrough::{Config, PassthroughFs};
1313
use fuse_backend_rs::transport::{FuseChannel, FuseSession};
14+
use nix::mount::MsFlags;
1415

1516
/// A fusedev daemon example
1617
#[allow(dead_code)]
@@ -19,6 +20,7 @@ pub struct Daemon {
1920
server: Arc<Server<Arc<Vfs>>>,
2021
thread_cnt: u32,
2122
session: Option<FuseSession>,
23+
mount_flags: Option<MsFlags>,
2224
}
2325

2426
#[allow(dead_code)]
@@ -47,14 +49,25 @@ impl Daemon {
4749
server: Arc::new(Server::new(Arc::new(vfs))),
4850
thread_cnt,
4951
session: None,
52+
mount_flags: None,
5053
})
5154
}
5255

56+
/// Set custom mount flags to pass to the session
57+
pub fn set_mount_flags(&mut self, flags: MsFlags) {
58+
self.mount_flags = Some(flags);
59+
}
60+
5361
/// Mounts a fusedev daemon to the mountpoint, then start service threads to handle
5462
/// FUSE requests.
5563
pub fn mount(&mut self) -> Result<()> {
5664
let mut se =
5765
FuseSession::new(Path::new(&self.mountpoint), "passthru_example", "", false).unwrap();
66+
67+
if let Some(flags) = self.mount_flags {
68+
se.set_mount_flags(flags);
69+
}
70+
5871
se.mount().unwrap();
5972
for _ in 0..self.thread_cnt {
6073
let mut server = FuseServer {

tests/smoke.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ mod fusedev_tests {
1515
use std::path::Path;
1616
use std::process::Command;
1717

18+
use nix::mount::MsFlags;
1819
use vmm_sys_util::tempdir::TempDir;
1920

2021
use crate::example::passthroughfs;
@@ -79,6 +80,55 @@ mod fusedev_tests {
7980
return Ok(stdout.to_string());
8081
}
8182

83+
/// Validates that the mounted filesystem has the expected mount flags
84+
fn validate_mount_flags(mountpoint: &str, expected_flags: MsFlags) -> bool {
85+
// Use findmnt to get the mount flags
86+
let cmd = format!("findmnt -no OPTIONS {}", mountpoint);
87+
let output = match exec(&cmd) {
88+
Ok(out) => out,
89+
Err(_) => return false,
90+
};
91+
92+
// Convert the expected flags to a string representation
93+
let expected_flags_str = msflags_to_string_set(expected_flags);
94+
95+
// Check if all expected flags are present in the output
96+
for flag in expected_flags_str {
97+
if !output.contains(&flag) {
98+
error!("Expected flag '{}' not found in mount options: {}", flag, output);
99+
return false;
100+
}
101+
}
102+
103+
true
104+
}
105+
106+
/// Converts MsFlags to a set of string representations
107+
fn msflags_to_string_set(flags: MsFlags) -> Vec<String> {
108+
let mut result = Vec::new();
109+
110+
if flags.contains(MsFlags::MS_RDONLY) {
111+
result.push("ro".to_string());
112+
}
113+
if flags.contains(MsFlags::MS_NOSUID) {
114+
result.push("nosuid".to_string());
115+
}
116+
if flags.contains(MsFlags::MS_NODEV) {
117+
result.push("nodev".to_string());
118+
}
119+
if flags.contains(MsFlags::MS_NOEXEC) {
120+
result.push("noexec".to_string());
121+
}
122+
if flags.contains(MsFlags::MS_SYNCHRONOUS) {
123+
result.push("sync".to_string());
124+
}
125+
if flags.contains(MsFlags::MS_NOATIME) {
126+
result.push("noatime".to_string());
127+
}
128+
129+
result
130+
}
131+
82132
#[test]
83133
#[ignore] // it depends on privileged mode to pass through /dev/fuse
84134
fn integration_test_tree_gitrepo() -> Result<()> {
@@ -99,4 +149,40 @@ mod fusedev_tests {
99149
daemon.umount().unwrap();
100150
Ok(())
101151
}
152+
153+
#[test]
154+
#[ignore]
155+
fn integration_test_mount_flags() -> Result<()> {
156+
// Test custom mount flags
157+
let src = Path::new(".").canonicalize().unwrap();
158+
let src_dir = src.to_str().unwrap();
159+
let tmp_dir = TempDir::new().unwrap();
160+
let mnt_dir = tmp_dir.as_path().to_str().unwrap();
161+
info!(
162+
"test mount flags src {:?} mountpoint {}",
163+
src_dir, mnt_dir
164+
);
165+
166+
// Create a set of custom mount flags
167+
let custom_flags = MsFlags::MS_NODEV | MsFlags::MS_NOSUID | MsFlags::MS_NOEXEC;
168+
169+
let mut daemon = passthroughfs::Daemon::new(src_dir, mnt_dir, 2).unwrap();
170+
171+
// Set the custom mount flags
172+
daemon.set_mount_flags(custom_flags);
173+
174+
// Mount the filesystem
175+
daemon.mount().unwrap();
176+
177+
// Wait for the mount to complete
178+
std::thread::sleep(std::time::Duration::from_millis(100));
179+
180+
// Validate that the mounted filesystem has the expected flags
181+
assert!(validate_mount_flags(mnt_dir, custom_flags));
182+
183+
// Unmount the filesystem
184+
daemon.umount().unwrap();
185+
186+
Ok(())
187+
}
102188
}

0 commit comments

Comments
 (0)