From b7faf4fdc172460364019c984ef191984db933c1 Mon Sep 17 00:00:00 2001 From: Sergio Lopez Date: Thu, 16 Apr 2020 13:40:04 +0200 Subject: [PATCH] vhost_user_fs: Add the WRITE_KILL_PRIV write flag. Add the WRITE_KILL_PRIV write flag, corresponding to FUSE_WRITE_KILL_PRIV introduced in 7.31, and use to only remove the setuid and setgid bits (by switching credentials) conditionally. Signed-off-by: Sergio Lopez --- vhost_user_fs/src/filesystem.rs | 7 ++++--- vhost_user_fs/src/fuse.rs | 3 +++ vhost_user_fs/src/passthrough.rs | 10 +++++++--- vhost_user_fs/src/server.rs | 2 ++ 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/vhost_user_fs/src/filesystem.rs b/vhost_user_fs/src/filesystem.rs index 0f3104680..018be10ac 100644 --- a/vhost_user_fs/src/filesystem.rs +++ b/vhost_user_fs/src/filesystem.rs @@ -682,11 +682,11 @@ pub trait FileSystem { /// implementation did not return a `Handle` from `open` then the contents of `handle` are /// undefined. /// - /// If the `FsOptions::HANDLE_KILLPRIV` feature is not enabled then then the file system is - /// expected to clear the setuid and setgid bits. - /// /// If `delayed_write` is true then it indicates that this is a write for buffered data. /// + /// If `kill_priv` is true then it indicates that the file system is expected to clear the + /// setuid and setgid bits. + /// /// This method should return exactly the number of bytes requested by the kernel, except in the /// case of error. An exception to this rule is if the file was opened with the "direct I/O" /// option (`libc::O_DIRECT`), in which case the kernel will forward the return code from this @@ -702,6 +702,7 @@ pub trait FileSystem { offset: u64, lock_owner: Option, delayed_write: bool, + kill_priv: bool, flags: u32, ) -> io::Result { Err(io::Error::from_raw_os_error(libc::ENOSYS)) diff --git a/vhost_user_fs/src/fuse.rs b/vhost_user_fs/src/fuse.rs index 1c820b0da..5a7571d39 100644 --- a/vhost_user_fs/src/fuse.rs +++ b/vhost_user_fs/src/fuse.rs @@ -373,6 +373,9 @@ pub const WRITE_CACHE: u32 = 1; /// `lock_owner` field is valid. pub const WRITE_LOCKOWNER: u32 = 2; +/// Kill suid and sgid bits +pub const WRITE_KILL_PRIV: u32 = 4; + // Read flags. pub const READ_LOCKOWNER: u32 = 2; diff --git a/vhost_user_fs/src/passthrough.rs b/vhost_user_fs/src/passthrough.rs index f76478b5d..dceaf6b0a 100644 --- a/vhost_user_fs/src/passthrough.rs +++ b/vhost_user_fs/src/passthrough.rs @@ -998,11 +998,15 @@ impl FileSystem for PassthroughFs { offset: u64, _lock_owner: Option, _delayed_write: bool, + kill_priv: bool, _flags: u32, ) -> io::Result { - // We need to change credentials during a write so that the kernel will remove setuid or - // setgid bits from the file if it was written to by someone other than the owner. - let (_uid, _gid) = set_creds(ctx.uid, ctx.gid)?; + if kill_priv { + // We need to change credentials during a write so that the kernel will remove setuid + // or setgid bits from the file if it was written to by someone other than the owner. + let (_uid, _gid) = set_creds(ctx.uid, ctx.gid)?; + } + let data = self .handles .read() diff --git a/vhost_user_fs/src/server.rs b/vhost_user_fs/src/server.rs index 2ac8f8f30..d9ad408ca 100644 --- a/vhost_user_fs/src/server.rs +++ b/vhost_user_fs/src/server.rs @@ -636,6 +636,7 @@ impl Server { }; let delayed_write = write_flags & WRITE_CACHE != 0; + let kill_priv = write_flags & WRITE_KILL_PRIV != 0; let data_reader = ZCReader(r); @@ -648,6 +649,7 @@ impl Server { offset, owner, delayed_write, + kill_priv, flags, ) { Ok(count) => {