From 4ec807b1bbcfaa67f85d0c2659b1f439c2f540b4 Mon Sep 17 00:00:00 2001 From: Anderson Toshiyuki Sasaki Date: Fri, 24 Jun 2022 16:25:54 +0200 Subject: [PATCH] permissions: Set supplementary groups when dropping privileges This allows the agent to run with the user primary group and have the access given by the supplementary groups. Fixes: #414 Signed-off-by: Anderson Toshiyuki Sasaki --- src/permissions.rs | 70 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/src/permissions.rs b/src/permissions.rs index 279a6dd..86e3fae 100644 --- a/src/permissions.rs +++ b/src/permissions.rs @@ -2,7 +2,7 @@ // Copyright 2021 Keylime Authors use crate::error::{Error, Result}; -use libc::{gid_t, uid_t}; +use libc::{c_char, c_int, gid_t, uid_t}; use log::*; use std::os::unix::ffi::OsStrExt; use std::{ @@ -13,10 +13,9 @@ use std::{ ptr, }; -#[derive(Debug)] pub(crate) struct UserIds { - uid: uid_t, - gid: gid_t, + passwd: libc::passwd, + group: libc::group, } pub(crate) fn get_gid() -> gid_t { @@ -47,14 +46,14 @@ impl TryFrom<&str> for UserIds { let group = parts[1]; // Get gid from group name - let gid = if let Ok(g_cstr) = CString::new(group.as_bytes()) { + let grnam = if let Ok(g_cstr) = CString::new(group.as_bytes()) { let p = unsafe { libc::getgrnam(g_cstr.as_ptr()) }; if p.is_null() { let e = io::Error::last_os_error(); error!("Could not get group {}: {}", group, e); return Err(Error::Conversion(e.to_string())); } - unsafe { (*p).gr_gid } + unsafe { (*p) } } else { return Err(Error::Conversion(format!( "Failed to convert {} to CString", @@ -63,14 +62,14 @@ impl TryFrom<&str> for UserIds { }; // Get uid from user name - let uid = if let Ok(u_cstr) = CString::new(user.as_bytes()) { + let passwd = if let Ok(u_cstr) = CString::new(user.as_bytes()) { let p = unsafe { libc::getpwnam(u_cstr.as_ptr()) }; if p.is_null() { let e = io::Error::last_os_error(); error!("Could not get user {}: {}", user, e); return Err(Error::Conversion(e.to_string())); } - unsafe { (*p).pw_uid } + unsafe { (*p) } } else { return Err(Error::Conversion(format!( "Failed to convert {} to CString", @@ -78,7 +77,10 @@ impl TryFrom<&str> for UserIds { ))); }; - Ok(UserIds { uid, gid }) + Ok(UserIds { + passwd, + group: grnam, + }) } } @@ -88,22 +90,51 @@ impl TryFrom<&str> for UserIds { pub(crate) fn run_as(user_group: &str) -> Result<()> { let ids: UserIds = user_group.try_into()?; - // Drop supplementary groups - if unsafe { libc::setgroups(0, ptr::null()) } != 0 { + // Set gid + if unsafe { libc::setgid(ids.group.gr_gid) } != 0 { let e = io::Error::last_os_error(); - error!("Could not drop supplementary groups: {}", e); + error!("Could not set group id: {}", e); return Err(Error::Permission); } - // Set gid - if unsafe { libc::setgid(ids.gid) } != 0 { + // Get list of supplementary groups + let mut sup_groups: [gid_t; 32] = [0u32; 32]; + let mut ngroups: c_int = 32; + if unsafe { + libc::getgrouplist( + ids.passwd.pw_name, + ids.group.gr_gid, + sup_groups.as_mut_ptr(), + &mut ngroups, + ) + } < 0 + { + // Allocate a Vec and try again + let mut sup_groups: Vec = Vec::with_capacity(ngroups as usize); + if unsafe { + libc::getgrouplist( + ids.passwd.pw_name, + ids.group.gr_gid, + sup_groups.as_mut_ptr(), + &mut ngroups, + ) + } < 0 + { + error!("Could not get list of supplementary groups"); + return Err(Error::Permission); + } + } + + // Set supplementary groups + if unsafe { libc::setgroups(ngroups as usize, sup_groups.as_ptr()) } != 0 + { let e = io::Error::last_os_error(); - error!("Could not set group id: {}", e); + error!("Could not set supplementary groups: {}", e); return Err(Error::Permission); } // Set uid - if unsafe { libc::setuid(ids.uid) } != 0 { + if unsafe { libc::setuid(ids.passwd.pw_uid) } != 0 { let e = io::Error::last_os_error(); error!("Could not set user id: {}", e); return Err(Error::Permission); @@ -126,9 +157,12 @@ pub(crate) fn chown(user_group: &str, path: &Path) -> Result<()> { return Err(Error::Permission); } - // change directory owner to root + // change directory owner let c_path = CString::new(path.as_os_str().as_bytes())?; - if unsafe { libc::chown(c_path.as_ptr(), ids.uid, ids.gid) } != 0 { + if unsafe { + libc::chown(c_path.as_ptr(), ids.passwd.pw_uid, ids.group.gr_gid) + } != 0 + { error!("Failed to change file {} owner.", path.display()); return Err(Error::Permission); }