summary refs log tree commit diff
path: root/devices/src/virtio/fs/passthrough.rs
diff options
context:
space:
mode:
authorChirantan Ekbote <chirantan@chromium.org>2019-10-19 06:06:17 +0900
committerCommit Bot <commit-bot@chromium.org>2019-11-12 06:31:52 +0000
commit961461350c0b6824e5f20655031bf6c6bf6b7c30 (patch)
tree70432229462c0cca381716e919f52c8b80c4ac26 /devices/src/virtio/fs/passthrough.rs
parent6cf8651dc3aa59c2b6bf76971f6374e66ee02ddf (diff)
downloadcrosvm-961461350c0b6824e5f20655031bf6c6bf6b7c30.tar
crosvm-961461350c0b6824e5f20655031bf6c6bf6b7c30.tar.gz
crosvm-961461350c0b6824e5f20655031bf6c6bf6b7c30.tar.bz2
crosvm-961461350c0b6824e5f20655031bf6c6bf6b7c30.tar.lz
crosvm-961461350c0b6824e5f20655031bf6c6bf6b7c30.tar.xz
crosvm-961461350c0b6824e5f20655031bf6c6bf6b7c30.tar.zst
crosvm-961461350c0b6824e5f20655031bf6c6bf6b7c30.zip
devices: fs: Allow running as users other than root
Don't assume the file system is running as the root user when changing
credentials.  Instead keep track of the thread euid/egid and use those
when restoring thread credentials.

BUG=b:136128319
TEST=`tast run vm.VirtioFs`

Change-Id: I37d59def99cd71de68aa7f94941031a86df54329
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1890584
Tested-by: Chirantan Ekbote <chirantan@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Chirantan Ekbote <chirantan@chromium.org>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-by: Stephen Barber <smbarber@chromium.org>
Diffstat (limited to 'devices/src/virtio/fs/passthrough.rs')
-rw-r--r--devices/src/virtio/fs/passthrough.rs33
1 files changed, 23 insertions, 10 deletions
diff --git a/devices/src/virtio/fs/passthrough.rs b/devices/src/virtio/fs/passthrough.rs
index 4ca7ee6..6b843fc 100644
--- a/devices/src/virtio/fs/passthrough.rs
+++ b/devices/src/virtio/fs/passthrough.rs
@@ -66,14 +66,16 @@ unsafe impl DataInit for LinuxDirent64 {}
 macro_rules! scoped_cred {
     ($name:ident, $ty:ty, $syscall_nr:expr) => {
         #[derive(Debug)]
-        struct $name;
+        struct $name {
+            old: $ty,
+        }
 
         impl $name {
-            // Changes the effective uid/gid of the current thread to `val`.  Changes
-            // the thread's credentials back to root when the returned struct is dropped.
-            fn new(val: $ty) -> io::Result<Option<$name>> {
-                if val == 0 {
-                    // Nothing to do since we are already uid 0.
+            // Changes the effective uid/gid of the current thread to `val`. Changes the thread's
+            // credentials back to `old` when the returned struct is dropped.
+            fn new(val: $ty, old: $ty) -> io::Result<Option<$name>> {
+                if val == old {
+                    // Nothing to do since we already have the correct value.
                     return Ok(None);
                 }
 
@@ -93,7 +95,7 @@ macro_rules! scoped_cred {
                 // check the return value.
                 let res = unsafe { libc::syscall($syscall_nr, -1, val, -1) };
                 if res == 0 {
-                    Ok(Some($name))
+                    Ok(Some($name { old }))
                 } else {
                     Err(io::Error::last_os_error())
                 }
@@ -102,10 +104,11 @@ macro_rules! scoped_cred {
 
         impl Drop for $name {
             fn drop(&mut self) {
-                let res = unsafe { libc::syscall($syscall_nr, -1, 0, -1) };
+                let res = unsafe { libc::syscall($syscall_nr, -1, self.old, -1) };
                 if res < 0 {
                     error!(
-                        "failed to change credentials back to root: {}",
+                        "failed to change credentials back to {}: {}",
+                        self.old,
                         io::Error::last_os_error(),
                     );
                 }
@@ -116,13 +119,23 @@ macro_rules! scoped_cred {
 scoped_cred!(ScopedUid, libc::uid_t, libc::SYS_setresuid);
 scoped_cred!(ScopedGid, libc::gid_t, libc::SYS_setresgid);
 
+thread_local! {
+    // Both these calls are safe because they take no parameters, and only return an integer value.
+    // The kernel also guarantees that they can never fail.
+    static THREAD_EUID: libc::uid_t = unsafe { libc::syscall(libc::SYS_geteuid) as libc::uid_t };
+    static THREAD_EGID: libc::gid_t = unsafe { libc::syscall(libc::SYS_getegid) as libc::gid_t };
+}
+
 fn set_creds(
     uid: libc::uid_t,
     gid: libc::gid_t,
 ) -> io::Result<(Option<ScopedUid>, Option<ScopedGid>)> {
+    let olduid = THREAD_EUID.with(|uid| *uid);
+    let oldgid = THREAD_EGID.with(|gid| *gid);
+
     // We have to change the gid before we change the uid because if we change the uid first then we
     // lose the capability to change the gid.  However changing back can happen in any order.
-    ScopedGid::new(gid).and_then(|gid| Ok((ScopedUid::new(uid)?, gid)))
+    ScopedGid::new(gid, oldgid).and_then(|gid| Ok((ScopedUid::new(uid, olduid)?, gid)))
 }
 
 fn ebadf() -> io::Error {