mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-11 04:26:38 +00:00
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>
This commit is contained in:
parent
6cf8651dc3
commit
961461350c
1 changed files with 23 additions and 10 deletions
|
@ -66,14 +66,16 @@ unsafe impl DataInit for LinuxDirent64 {}
|
||||||
macro_rules! scoped_cred {
|
macro_rules! scoped_cred {
|
||||||
($name:ident, $ty:ty, $syscall_nr:expr) => {
|
($name:ident, $ty:ty, $syscall_nr:expr) => {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct $name;
|
struct $name {
|
||||||
|
old: $ty,
|
||||||
|
}
|
||||||
|
|
||||||
impl $name {
|
impl $name {
|
||||||
// Changes the effective uid/gid of the current thread to `val`. Changes
|
// Changes the effective uid/gid of the current thread to `val`. Changes the thread's
|
||||||
// the thread's credentials back to root when the returned struct is dropped.
|
// credentials back to `old` when the returned struct is dropped.
|
||||||
fn new(val: $ty) -> io::Result<Option<$name>> {
|
fn new(val: $ty, old: $ty) -> io::Result<Option<$name>> {
|
||||||
if val == 0 {
|
if val == old {
|
||||||
// Nothing to do since we are already uid 0.
|
// Nothing to do since we already have the correct value.
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +95,7 @@ macro_rules! scoped_cred {
|
||||||
// check the return value.
|
// check the return value.
|
||||||
let res = unsafe { libc::syscall($syscall_nr, -1, val, -1) };
|
let res = unsafe { libc::syscall($syscall_nr, -1, val, -1) };
|
||||||
if res == 0 {
|
if res == 0 {
|
||||||
Ok(Some($name))
|
Ok(Some($name { old }))
|
||||||
} else {
|
} else {
|
||||||
Err(io::Error::last_os_error())
|
Err(io::Error::last_os_error())
|
||||||
}
|
}
|
||||||
|
@ -102,10 +104,11 @@ macro_rules! scoped_cred {
|
||||||
|
|
||||||
impl Drop for $name {
|
impl Drop for $name {
|
||||||
fn drop(&mut self) {
|
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 {
|
if res < 0 {
|
||||||
error!(
|
error!(
|
||||||
"failed to change credentials back to root: {}",
|
"failed to change credentials back to {}: {}",
|
||||||
|
self.old,
|
||||||
io::Error::last_os_error(),
|
io::Error::last_os_error(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -116,13 +119,23 @@ macro_rules! scoped_cred {
|
||||||
scoped_cred!(ScopedUid, libc::uid_t, libc::SYS_setresuid);
|
scoped_cred!(ScopedUid, libc::uid_t, libc::SYS_setresuid);
|
||||||
scoped_cred!(ScopedGid, libc::gid_t, libc::SYS_setresgid);
|
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(
|
fn set_creds(
|
||||||
uid: libc::uid_t,
|
uid: libc::uid_t,
|
||||||
gid: libc::gid_t,
|
gid: libc::gid_t,
|
||||||
) -> io::Result<(Option<ScopedUid>, Option<ScopedGid>)> {
|
) -> 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
|
// 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.
|
// 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 {
|
fn ebadf() -> io::Error {
|
||||||
|
|
Loading…
Reference in a new issue