mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-21 00:06:34 +00:00
Support prctl(PR_SET_KEEPCAPS/PR_GET_KEEPCAPS)
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
d72ce0351a
commit
24f1e02b26
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use core::sync::atomic::Ordering;
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
use ostd::sync::{PreemptDisabled, RwLockReadGuard, RwLockWriteGuard};
|
use ostd::sync::{PreemptDisabled, RwLockReadGuard, RwLockWriteGuard};
|
||||||
|
|
||||||
@ -46,6 +46,9 @@ pub(super) struct Credentials_ {
|
|||||||
|
|
||||||
/// Capability that we can actually use
|
/// Capability that we can actually use
|
||||||
effective_capset: AtomicCapSet,
|
effective_capset: AtomicCapSet,
|
||||||
|
|
||||||
|
/// Keep capabilities flag
|
||||||
|
keep_capabilities: AtomicBool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Credentials_ {
|
impl Credentials_ {
|
||||||
@ -67,6 +70,7 @@ impl Credentials_ {
|
|||||||
inheritable_capset: AtomicCapSet::new(capset),
|
inheritable_capset: AtomicCapSet::new(capset),
|
||||||
permitted_capset: AtomicCapSet::new(capset),
|
permitted_capset: AtomicCapSet::new(capset),
|
||||||
effective_capset: AtomicCapSet::new(capset),
|
effective_capset: AtomicCapSet::new(capset),
|
||||||
|
keep_capabilities: AtomicBool::new(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +96,10 @@ impl Credentials_ {
|
|||||||
self.fsuid.load(Ordering::Relaxed)
|
self.fsuid.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn keep_capabilities(&self) -> bool {
|
||||||
|
self.keep_capabilities.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn set_uid(&self, uid: Uid) {
|
pub(super) fn set_uid(&self, uid: Uid) {
|
||||||
if self.is_privileged() {
|
if self.is_privileged() {
|
||||||
self.ruid.store(uid, Ordering::Relaxed);
|
self.ruid.store(uid, Ordering::Relaxed);
|
||||||
@ -99,9 +107,23 @@ impl Credentials_ {
|
|||||||
self.suid.store(uid, Ordering::Relaxed);
|
self.suid.store(uid, Ordering::Relaxed);
|
||||||
self.fsuid.store(uid, Ordering::Relaxed);
|
self.fsuid.store(uid, Ordering::Relaxed);
|
||||||
} else {
|
} else {
|
||||||
|
// Unprivileged processes can only switch between ruid, euid, suid
|
||||||
|
if uid != self.ruid.load(Ordering::Relaxed)
|
||||||
|
&& uid != self.euid.load(Ordering::Relaxed)
|
||||||
|
&& uid != self.suid.load(Ordering::Relaxed)
|
||||||
|
{
|
||||||
|
// No permission to set to this UID
|
||||||
|
return;
|
||||||
|
}
|
||||||
self.euid.store(uid, Ordering::Relaxed);
|
self.euid.store(uid, Ordering::Relaxed);
|
||||||
self.fsuid.store(uid, Ordering::Relaxed);
|
self.fsuid.store(uid, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
if !self.keep_capabilities.load(Ordering::Relaxed) {
|
||||||
|
self.set_permitted_capset(CapSet::empty());
|
||||||
|
self.set_inheritable_capset(CapSet::empty());
|
||||||
|
}
|
||||||
|
// Always clear the effective capabilities when changing the UID
|
||||||
|
self.set_effective_capset(CapSet::empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn set_reuid(&self, ruid: Option<Uid>, euid: Option<Uid>) -> Result<()> {
|
pub(super) fn set_reuid(&self, ruid: Option<Uid>, euid: Option<Uid>) -> Result<()> {
|
||||||
@ -326,6 +348,11 @@ impl Credentials_ {
|
|||||||
self.sgid.store(sgid, Ordering::Relaxed);
|
self.sgid.store(sgid, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn set_keep_capabilities(&self, keep_capabilities: bool) {
|
||||||
|
self.keep_capabilities
|
||||||
|
.store(keep_capabilities, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
// For `setregid`, rgid can *NOT* be set to old sgid,
|
// For `setregid`, rgid can *NOT* be set to old sgid,
|
||||||
// while for `setresgid`, ruid can be set to old sgid.
|
// while for `setresgid`, ruid can be set to old sgid.
|
||||||
fn check_gid_perm(
|
fn check_gid_perm(
|
||||||
@ -444,6 +471,7 @@ impl Clone for Credentials_ {
|
|||||||
inheritable_capset: self.inheritable_capset.clone(),
|
inheritable_capset: self.inheritable_capset.clone(),
|
||||||
permitted_capset: self.permitted_capset.clone(),
|
permitted_capset: self.permitted_capset.clone(),
|
||||||
effective_capset: self.effective_capset.clone(),
|
effective_capset: self.effective_capset.clone(),
|
||||||
|
keep_capabilities: AtomicBool::new(self.keep_capabilities.load(Ordering::Relaxed)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,14 @@ impl<R: TRights> Credentials<R> {
|
|||||||
self.0.fsuid()
|
self.0.fsuid()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets keep capabilities flag.
|
||||||
|
///
|
||||||
|
/// This method requires the `Read` right.
|
||||||
|
#[require(R > Read)]
|
||||||
|
pub fn keep_capabilities(&self) -> bool {
|
||||||
|
self.0.keep_capabilities()
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets uid. If self is privileged, sets the effective, real, saved-set user ids as `uid`,
|
/// Sets uid. If self is privileged, sets the effective, real, saved-set user ids as `uid`,
|
||||||
/// Otherwise, sets effective user id as `uid`.
|
/// Otherwise, sets effective user id as `uid`.
|
||||||
///
|
///
|
||||||
@ -139,6 +147,14 @@ impl<R: TRights> Credentials<R> {
|
|||||||
self.0.set_suid(euid);
|
self.0.set_suid(euid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets keep capabilities flag.
|
||||||
|
///
|
||||||
|
/// This method requires the `Write` right.
|
||||||
|
#[require(R > Write)]
|
||||||
|
pub fn set_keep_capabilities(&self, keep_capabilities: bool) {
|
||||||
|
self.0.set_keep_capabilities(keep_capabilities);
|
||||||
|
}
|
||||||
|
|
||||||
// *********** Gid methods **********
|
// *********** Gid methods **********
|
||||||
|
|
||||||
/// Gets real group id.
|
/// Gets real group id.
|
||||||
|
@ -129,6 +129,7 @@ fn do_execve(
|
|||||||
let credentials = ctx.posix_thread.credentials_mut();
|
let credentials = ctx.posix_thread.credentials_mut();
|
||||||
set_uid_from_elf(process, &credentials, &elf_file)?;
|
set_uid_from_elf(process, &credentials, &elf_file)?;
|
||||||
set_gid_from_elf(process, &credentials, &elf_file)?;
|
set_gid_from_elf(process, &credentials, &elf_file)?;
|
||||||
|
credentials.set_keep_capabilities(false);
|
||||||
|
|
||||||
// set executable path
|
// set executable path
|
||||||
process.set_executable_path(new_executable_path);
|
process.set_executable_path(new_executable_path);
|
||||||
|
@ -41,6 +41,25 @@ pub fn sys_prctl(
|
|||||||
|
|
||||||
// TODO: implement coredump
|
// TODO: implement coredump
|
||||||
}
|
}
|
||||||
|
PrctlCmd::PR_GET_KEEPCAPS => {
|
||||||
|
let keep_cap = {
|
||||||
|
let credentials = ctx.posix_thread.credentials();
|
||||||
|
if credentials.keep_capabilities() {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(SyscallReturn::Return(keep_cap as _));
|
||||||
|
}
|
||||||
|
PrctlCmd::PR_SET_KEEPCAPS(keep_cap) => {
|
||||||
|
if keep_cap > 1 {
|
||||||
|
return_errno!(Errno::EINVAL)
|
||||||
|
}
|
||||||
|
let credentials = ctx.posix_thread.credentials_mut();
|
||||||
|
credentials.set_keep_capabilities(keep_cap != 0);
|
||||||
|
}
|
||||||
PrctlCmd::PR_GET_NAME(write_to_addr) => {
|
PrctlCmd::PR_GET_NAME(write_to_addr) => {
|
||||||
let thread_name = ctx.posix_thread.thread_name().lock();
|
let thread_name = ctx.posix_thread.thread_name().lock();
|
||||||
if let Some(thread_name) = &*thread_name {
|
if let Some(thread_name) = &*thread_name {
|
||||||
@ -70,6 +89,8 @@ const PR_SET_PDEATHSIG: i32 = 1;
|
|||||||
const PR_GET_PDEATHSIG: i32 = 2;
|
const PR_GET_PDEATHSIG: i32 = 2;
|
||||||
const PR_GET_DUMPABLE: i32 = 3;
|
const PR_GET_DUMPABLE: i32 = 3;
|
||||||
const PR_SET_DUMPABLE: i32 = 4;
|
const PR_SET_DUMPABLE: i32 = 4;
|
||||||
|
const PR_GET_KEEPCAPS: i32 = 7;
|
||||||
|
const PR_SET_KEEPCAPS: i32 = 8;
|
||||||
const PR_SET_NAME: i32 = 15;
|
const PR_SET_NAME: i32 = 15;
|
||||||
const PR_GET_NAME: i32 = 16;
|
const PR_GET_NAME: i32 = 16;
|
||||||
const PR_SET_TIMERSLACK: i32 = 29;
|
const PR_SET_TIMERSLACK: i32 = 29;
|
||||||
@ -82,6 +103,8 @@ pub enum PrctlCmd {
|
|||||||
PR_GET_PDEATHSIG(Vaddr),
|
PR_GET_PDEATHSIG(Vaddr),
|
||||||
PR_SET_NAME(Vaddr),
|
PR_SET_NAME(Vaddr),
|
||||||
PR_GET_NAME(Vaddr),
|
PR_GET_NAME(Vaddr),
|
||||||
|
PR_GET_KEEPCAPS,
|
||||||
|
PR_SET_KEEPCAPS(u32),
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
PR_SET_TIMERSLACK(u64),
|
PR_SET_TIMERSLACK(u64),
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -112,6 +135,8 @@ impl PrctlCmd {
|
|||||||
PR_GET_NAME => Ok(PrctlCmd::PR_GET_NAME(arg2 as _)),
|
PR_GET_NAME => Ok(PrctlCmd::PR_GET_NAME(arg2 as _)),
|
||||||
PR_GET_TIMERSLACK => todo!(),
|
PR_GET_TIMERSLACK => todo!(),
|
||||||
PR_SET_TIMERSLACK => todo!(),
|
PR_SET_TIMERSLACK => todo!(),
|
||||||
|
PR_GET_KEEPCAPS => Ok(PrctlCmd::PR_GET_KEEPCAPS),
|
||||||
|
PR_SET_KEEPCAPS => Ok(PrctlCmd::PR_SET_KEEPCAPS(arg2 as _)),
|
||||||
_ => {
|
_ => {
|
||||||
debug!("prctl cmd number: {}", option);
|
debug!("prctl cmd number: {}", option);
|
||||||
return_errno_with_message!(Errno::EINVAL, "unsupported prctl command");
|
return_errno_with_message!(Errno::EINVAL, "unsupported prctl command");
|
||||||
|
@ -10,7 +10,6 @@ TESTS ?= \
|
|||||||
alarm_test \
|
alarm_test \
|
||||||
chmod_test \
|
chmod_test \
|
||||||
chown_test \
|
chown_test \
|
||||||
chroot_test \
|
|
||||||
creat_test \
|
creat_test \
|
||||||
dup_test \
|
dup_test \
|
||||||
epoll_test \
|
epoll_test \
|
||||||
@ -29,6 +28,7 @@ TESTS ?= \
|
|||||||
mount_test \
|
mount_test \
|
||||||
open_create_test \
|
open_create_test \
|
||||||
open_test \
|
open_test \
|
||||||
|
prctl_setuid_test \
|
||||||
pread64_test \
|
pread64_test \
|
||||||
preadv2_test \
|
preadv2_test \
|
||||||
proc_test \
|
proc_test \
|
||||||
|
1
test/syscall_test/blocklists/prctl_setuid_test
Normal file
1
test/syscall_test/blocklists/prctl_setuid_test
Normal file
@ -0,0 +1 @@
|
|||||||
|
PrctlKeepCapsSetuidTest.NoKeepCapsAfterNewUserNamespace
|
Reference in New Issue
Block a user