diff --git a/src/channel.rs b/src/channel.rs index add5c831..fae35afb 100644 --- a/src/channel.rs +++ b/src/channel.rs @@ -1,4 +1,12 @@ -use std::{fs::File, io, os::unix::prelude::AsRawFd, sync::Arc}; +use std::{ + fs::File, + io, + os::{ + fd::{AsFd, BorrowedFd}, + unix::prelude::AsRawFd, + }, + sync::Arc, +}; use libc::{c_int, c_void, size_t}; @@ -8,6 +16,12 @@ use crate::reply::ReplySender; #[derive(Debug)] pub struct Channel(Arc); +impl AsFd for Channel { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + impl Channel { /// Create a new communication channel to the kernel driver by mounting the /// given path. The kernel driver will delegate filesystem operations of diff --git a/src/lib.rs b/src/lib.rs index d1f126bd..e3d8dcf9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,7 +40,7 @@ pub use reply::{ ReplyStatfs, ReplyWrite, }; pub use request::Request; -pub use session::{BackgroundSession, Session, SessionUnmounter}; +pub use session::{BackgroundSession, Session, SessionACL, SessionUnmounter}; #[cfg(feature = "abi-7-28")] use std::cmp::max; #[cfg(feature = "abi-7-13")] diff --git a/src/session.rs b/src/session.rs index 44919264..9f9e742d 100644 --- a/src/session.rs +++ b/src/session.rs @@ -9,7 +9,8 @@ use libc::{EAGAIN, EINTR, ENODEV, ENOENT}; use log::{info, warn}; use nix::unistd::geteuid; use std::fmt; -use std::path::{Path, PathBuf}; +use std::os::fd::{AsFd, BorrowedFd, OwnedFd}; +use std::path::Path; use std::sync::{Arc, Mutex}; use std::thread::{self, JoinHandle}; use std::{io, ops::DerefMut}; @@ -31,10 +32,15 @@ pub const MAX_WRITE_SIZE: usize = 16 * 1024 * 1024; /// up to MAX_WRITE_SIZE bytes in a write request, we use that value plus some extra space. const BUFFER_SIZE: usize = MAX_WRITE_SIZE + 4096; -#[derive(Debug, Eq, PartialEq)] -pub(crate) enum SessionACL { +#[derive(Default, Debug, Eq, PartialEq)] +/// How requests should be filtered based on the calling UID. +pub enum SessionACL { + /// Allow requests from any user. Corresponds to the `allow_other` mount option. All, + /// Allow requests from root. Corresponds to the `allow_root` mount option. RootAndOwner, + /// Allow requests from the owning UID. This is FUSE's default mode of operation. + #[default] Owner, } @@ -47,8 +53,6 @@ pub struct Session { ch: Channel, /// Handle to the mount. Dropping this unmounts. mount: Arc>>, - /// Mount point - mountpoint: PathBuf, /// Whether to restrict access to owner, root + owner, or unrestricted /// Used to implement allow_root and auto_unmount pub(crate) allowed: SessionACL, @@ -64,6 +68,12 @@ pub struct Session { pub(crate) destroyed: bool, } +impl AsFd for Session { + fn as_fd(&self) -> BorrowedFd<'_> { + self.ch.as_fd() + } +} + impl Session { /// Create a new session by mounting the given filesystem to the given mountpoint pub fn new>( @@ -101,7 +111,6 @@ impl Session { filesystem, ch, mount: Arc::new(Mutex::new(Some(mount))), - mountpoint: mountpoint.to_owned(), allowed, session_owner: geteuid().as_raw(), proto_major: 0, @@ -111,9 +120,21 @@ impl Session { }) } - /// Return path of the mounted filesystem - pub fn mountpoint(&self) -> &Path { - &self.mountpoint + /// Wrap an existing /dev/fuse file descriptor. This doesn't mount the + /// filesystem anywhere; that must be done separately. + pub fn from_fd(filesystem: FS, fd: OwnedFd, acl: SessionACL) -> Self { + let ch = Channel::new(Arc::new(fd.into())); + Session { + filesystem, + ch, + mount: Arc::new(Mutex::new(None)), + allowed: acl, + session_owner: geteuid().as_raw(), + proto_major: 0, + proto_minor: 0, + initialized: false, + destroyed: false, + } } /// Run the session loop that receives kernel requests and dispatches them to method @@ -210,14 +231,11 @@ impl Drop for Session { self.filesystem.destroy(); self.destroyed = true; } - info!("Unmounted {}", self.mountpoint().display()); } } /// The background session data structure pub struct BackgroundSession { - /// Path of the mounted filesystem - pub mountpoint: PathBuf, /// Thread guard of the background session pub guard: JoinHandle>, /// Object for creating Notifiers for client use @@ -232,7 +250,6 @@ impl BackgroundSession { /// session loop in a background thread. If the returned handle is dropped, /// the filesystem is unmounted and the given session ends. pub fn new(se: Session) -> io::Result { - let mountpoint = se.mountpoint().to_path_buf(); #[cfg(feature = "abi-7-11")] let sender = se.ch.sender(); // Take the fuse_session, so that we can unmount it @@ -243,7 +260,6 @@ impl BackgroundSession { se.run() }); Ok(BackgroundSession { - mountpoint, guard, #[cfg(feature = "abi-7-11")] sender, @@ -253,7 +269,6 @@ impl BackgroundSession { /// Unmount the filesystem and join the background thread. pub fn join(self) { let Self { - mountpoint: _, guard, #[cfg(feature = "abi-7-11")] sender: _, @@ -274,10 +289,6 @@ impl BackgroundSession { // thread_scoped::JoinGuard impl fmt::Debug for BackgroundSession { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - write!( - f, - "BackgroundSession {{ mountpoint: {:?}, guard: JoinGuard<()> }}", - self.mountpoint - ) + write!(f, "BackgroundSession {{ guard: JoinGuard<()> }}",) } }