From 0648a547da3461bd115f7566c6f2feca14eac6ff Mon Sep 17 00:00:00 2001 From: Jomo Date: Fri, 2 Aug 2024 09:42:34 +0800 Subject: [PATCH] =?UTF-8?q?feat(cred):=20=E5=88=9D=E6=AD=A5=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0Cred=20(#846)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 初步实现Cred * 添加seteuid和setegid * 添加cred测试程序 * 修改Cred::fscmp返回结果为CredFsCmp枚举 * 完善root用户相关信息 --- kernel/src/filesystem/vfs/file.rs | 6 +- kernel/src/process/cred.rs | 170 ++++++++++++++++++++++++++ kernel/src/process/mod.rs | 23 +++- kernel/src/process/syscall.rs | 115 +++++++++++++++-- kernel/src/syscall/mod.rs | 25 ++-- user/apps/test_cred/.gitignore | 1 + user/apps/test_cred/Makefile | 20 +++ user/apps/test_cred/main.c | 42 +++++++ user/dadk/config/test_cred-0.1.0.dadk | 23 ++++ user/sysconfig/etc/group | 1 + user/sysconfig/etc/gshadow | 1 + user/sysconfig/etc/passwd | 1 + user/sysconfig/etc/shadow | 1 + 13 files changed, 405 insertions(+), 24 deletions(-) create mode 100644 kernel/src/process/cred.rs create mode 100644 user/apps/test_cred/.gitignore create mode 100644 user/apps/test_cred/Makefile create mode 100644 user/apps/test_cred/main.c create mode 100644 user/dadk/config/test_cred-0.1.0.dadk diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index d0e8f471..faf020ed 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -20,7 +20,7 @@ use crate::{ event_poll::{EPollItem, EPollPrivateData, EventPoll}, socket::SocketInode, }, - process::ProcessManager, + process::{cred::Cred, ProcessManager}, }; use super::{Dirent, FileType, IndexNode, InodeId, Metadata, SpecialNodeData}; @@ -131,6 +131,8 @@ pub struct File { /// readdir时候用的,暂存的本次循环中,所有子目录项的名字的数组 readdir_subdirs_name: SpinLock>, pub private_data: SpinLock, + /// 文件的凭证 + cred: Cred, } impl File { @@ -154,6 +156,7 @@ impl File { file_type, readdir_subdirs_name: SpinLock::new(Vec::default()), private_data: SpinLock::new(FilePrivateData::default()), + cred: ProcessManager::current_pcb().cred(), }; f.inode.open(f.private_data.lock(), &mode)?; @@ -408,6 +411,7 @@ impl File { file_type: self.file_type, readdir_subdirs_name: SpinLock::new(self.readdir_subdirs_name.lock().clone()), private_data: SpinLock::new(self.private_data.lock().clone()), + cred: self.cred.clone(), }; // 调用inode的open方法,让inode知道有新的文件打开了这个inode if self diff --git a/kernel/src/process/cred.rs b/kernel/src/process/cred.rs new file mode 100644 index 00000000..952cfbfd --- /dev/null +++ b/kernel/src/process/cred.rs @@ -0,0 +1,170 @@ +use core::sync::atomic::AtomicUsize; + +use alloc::vec::Vec; + +const GLOBAL_ROOT_UID: Kuid = Kuid(0); +const GLOBAL_ROOT_GID: Kgid = Kgid(0); +pub static INIT_CRED: Cred = Cred::init(); + +int_like!(Kuid, AtomicKuid, usize, AtomicUsize); +int_like!(Kgid, AtomicKgid, usize, AtomicUsize); + +bitflags! { + pub struct CAPFlags:u64{ + const CAP_EMPTY_SET = 0; + const CAP_FULL_SET = (1 << 41) - 1; + } +} + +pub enum CredFsCmp { + Equal, + Less, + Greater, +} + +/// 凭证集 +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Cred { + /// 进程实际uid + pub uid: Kuid, + /// 进程实际gid + pub gid: Kgid, + /// 进程保存的uid + pub suid: Kuid, + /// 进程保存的gid + pub sgid: Kgid, + /// 进程有效的uid + pub euid: Kuid, + /// 进程有效的gid + pub egid: Kgid, + /// UID for VFS ops + pub fsuid: Kuid, + /// GID for VFS ops + pub fsgid: Kgid, + /// 子进程可以继承的权限 + pub cap_inheritable: CAPFlags, + /// 当前进程被赋予的权限 + pub cap_permitted: CAPFlags, + /// 当前进程实际使用的权限 + pub cap_effective: CAPFlags, + /// capability bounding set + pub cap_bset: CAPFlags, + /// Ambient capability set + pub cap_ambient: CAPFlags, + /// supplementary groups for euid/fsgid + pub group_info: Option, +} + +impl Cred { + pub const fn init() -> Self { + Self { + uid: GLOBAL_ROOT_UID, + gid: GLOBAL_ROOT_GID, + suid: GLOBAL_ROOT_UID, + sgid: GLOBAL_ROOT_GID, + euid: GLOBAL_ROOT_UID, + egid: GLOBAL_ROOT_GID, + fsuid: GLOBAL_ROOT_UID, + fsgid: GLOBAL_ROOT_GID, + cap_inheritable: CAPFlags::CAP_EMPTY_SET, + cap_permitted: CAPFlags::CAP_FULL_SET, + cap_effective: CAPFlags::CAP_FULL_SET, + cap_bset: CAPFlags::CAP_FULL_SET, + cap_ambient: CAPFlags::CAP_FULL_SET, + group_info: None, + } + } + + #[allow(dead_code)] + /// Compare two credentials with respect to filesystem access. + pub fn fscmp(&self, other: Cred) -> CredFsCmp { + if *self == other { + return CredFsCmp::Equal; + } + + if self.fsuid < other.fsuid { + return CredFsCmp::Less; + } + if self.fsuid > other.fsuid { + return CredFsCmp::Greater; + } + + if self.fsgid < other.fsgid { + return CredFsCmp::Less; + } + if self.fsgid > other.fsgid { + return CredFsCmp::Greater; + } + + if self.group_info == other.group_info { + return CredFsCmp::Equal; + } + + if let (Some(ga), Some(gb)) = (&self.group_info, &other.group_info) { + let ga_count = ga.gids.len(); + let gb_count = gb.gids.len(); + + if ga_count < gb_count { + return CredFsCmp::Less; + } + if ga_count > gb_count { + return CredFsCmp::Greater; + } + + for i in 0..ga_count { + if ga.gids[i] < gb.gids[i] { + return CredFsCmp::Less; + } + if ga.gids[i] > gb.gids[i] { + return CredFsCmp::Greater; + } + } + } else { + if self.group_info.is_none() { + return CredFsCmp::Less; + } + if other.group_info.is_none() { + return CredFsCmp::Greater; + } + } + + return CredFsCmp::Equal; + } + + pub fn setuid(&mut self, uid: usize) { + self.uid.0 = uid; + } + + pub fn seteuid(&mut self, euid: usize) { + self.euid.0 = euid; + } + + pub fn setsuid(&mut self, suid: usize) { + self.suid.0 = suid; + } + + pub fn setfsuid(&mut self, fsuid: usize) { + self.fsuid.0 = fsuid; + } + + pub fn setgid(&mut self, gid: usize) { + self.gid.0 = gid; + } + + pub fn setegid(&mut self, egid: usize) { + self.egid.0 = egid; + } + + pub fn setsgid(&mut self, sgid: usize) { + self.sgid.0 = sgid; + } + + pub fn setfsgid(&mut self, fsgid: usize) { + self.fsgid.0 = fsgid; + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct GroupInfo { + pub gids: Vec, +} diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index f3d76ee8..c56702a8 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -13,6 +13,7 @@ use alloc::{ sync::{Arc, Weak}, vec::Vec, }; +use cred::INIT_CRED; use hashbrown::HashMap; use log::{debug, error, info, warn}; use system_error::SystemError; @@ -64,10 +65,11 @@ use crate::{ }; use timer::AlarmTimer; -use self::kthread::WorkerPrivate; +use self::{cred::Cred, kthread::WorkerPrivate}; pub mod abi; pub mod c_adapter; +pub mod cred; pub mod exec; pub mod exit; pub mod fork; @@ -649,6 +651,9 @@ pub struct ProcessControlBlock { /// 进程的robust lock列表 robust_list: RwLock>, + + /// 进程作为主体的凭证集 + cred: SpinLock, } impl ProcessControlBlock { @@ -687,12 +692,16 @@ impl ProcessControlBlock { #[inline(never)] fn do_create_pcb(name: String, kstack: KernelStack, is_idle: bool) -> Arc { - let (pid, ppid, cwd) = if is_idle { - (Pid(0), Pid(0), "/".to_string()) + let (pid, ppid, cwd, cred) = if is_idle { + let cred = INIT_CRED.clone(); + (Pid(0), Pid(0), "/".to_string(), cred) } else { let ppid = ProcessManager::current_pcb().pid(); + let mut cred = ProcessManager::current_pcb().cred(); + cred.cap_permitted = cred.cap_ambient; + cred.cap_effective = cred.cap_ambient; let cwd = ProcessManager::current_pcb().basic().cwd(); - (Self::generate_pid(), ppid, cwd) + (Self::generate_pid(), ppid, cwd, cred) }; let basic_info = ProcessBasicInfo::new(Pid(0), ppid, name, cwd, None); @@ -727,6 +736,7 @@ impl ProcessControlBlock { thread: RwLock::new(ThreadInfo::new()), alarm_timer: SpinLock::new(None), robust_list: RwLock::new(None), + cred: SpinLock::new(cred), }; // 初始化系统调用栈 @@ -879,6 +889,11 @@ impl ProcessControlBlock { return self.basic.read().fd_table().unwrap(); } + #[inline(always)] + pub fn cred(&self) -> Cred { + self.cred.lock().clone() + } + /// 根据文件描述符序号,获取socket对象的Arc指针 /// /// ## 参数 diff --git a/kernel/src/process/syscall.rs b/kernel/src/process/syscall.rs index 86ffe5dd..1a2fec46 100644 --- a/kernel/src/process/syscall.rs +++ b/kernel/src/process/syscall.rs @@ -6,6 +6,7 @@ use system_error::SystemError; use super::{ abi::WaitOption, + cred::{Kgid, Kuid}, exit::kernel_wait4, fork::{CloneFlags, KernelCloneArgs}, resource::{RLimit64, RLimitID, RUsage, RUsageWho}, @@ -286,25 +287,125 @@ impl Syscall { } pub fn getuid() -> Result { - // todo: 增加credit功能之后,需要修改 - return Ok(0); + let pcb = ProcessManager::current_pcb(); + return Ok(pcb.cred.lock().uid.data()); } pub fn getgid() -> Result { - // todo: 增加credit功能之后,需要修改 - return Ok(0); + let pcb = ProcessManager::current_pcb(); + return Ok(pcb.cred.lock().gid.data()); } pub fn geteuid() -> Result { - // todo: 增加credit功能之后,需要修改 - return Ok(0); + let pcb = ProcessManager::current_pcb(); + return Ok(pcb.cred.lock().euid.data()); } pub fn getegid() -> Result { - // todo: 增加credit功能之后,需要修改 + let pcb = ProcessManager::current_pcb(); + return Ok(pcb.cred.lock().egid.data()); + } + + pub fn setuid(uid: usize) -> Result { + let pcb = ProcessManager::current_pcb(); + let mut guard = pcb.cred.lock(); + + if guard.uid.data() == 0 { + guard.setuid(uid); + guard.seteuid(uid); + guard.setsuid(uid); + } else if uid == guard.uid.data() || uid == guard.suid.data() { + guard.seteuid(uid); + } else { + return Err(SystemError::EPERM); + } + return Ok(0); } + pub fn setgid(gid: usize) -> Result { + let pcb = ProcessManager::current_pcb(); + let mut guard = pcb.cred.lock(); + + if guard.egid.data() == 0 { + guard.setgid(gid); + guard.setegid(gid); + guard.setsgid(gid); + guard.setfsgid(gid); + } else if guard.gid.data() == gid || guard.sgid.data() == gid { + guard.setegid(gid); + guard.setfsgid(gid); + } else { + return Err(SystemError::EPERM); + } + + return Ok(0); + } + + pub fn seteuid(euid: usize) -> Result { + let pcb = ProcessManager::current_pcb(); + let mut guard = pcb.cred.lock(); + + if euid == usize::MAX || (euid == guard.euid.data() && euid == guard.fsuid.data()) { + return Ok(0); + } + + if euid != usize::MAX { + guard.seteuid(euid); + } + + let euid = guard.euid.data(); + guard.setfsuid(euid); + + return Ok(0); + } + + pub fn setegid(egid: usize) -> Result { + let pcb = ProcessManager::current_pcb(); + let mut guard = pcb.cred.lock(); + + if egid == usize::MAX || (egid == guard.egid.data() && egid == guard.fsgid.data()) { + return Ok(0); + } + + if egid != usize::MAX { + guard.setegid(egid); + } + + let egid = guard.egid.data(); + guard.setfsgid(egid); + + return Ok(0); + } + + pub fn setfsuid(fsuid: usize) -> Result { + let fsuid = Kuid::new(fsuid); + + let pcb = ProcessManager::current_pcb(); + let mut guard = pcb.cred.lock(); + let old_fsuid = guard.fsuid; + + if fsuid == guard.uid || fsuid == guard.euid || fsuid == guard.suid { + guard.setfsuid(fsuid.data()); + } + + Ok(old_fsuid.data()) + } + + pub fn setfsgid(fsgid: usize) -> Result { + let fsgid = Kgid::new(fsgid); + + let pcb = ProcessManager::current_pcb(); + let mut guard = pcb.cred.lock(); + let old_fsgid = guard.fsgid; + + if fsgid == guard.gid || fsgid == guard.egid || fsgid == guard.sgid { + guard.setfsgid(fsgid.data()); + } + + Ok(old_fsgid.data()) + } + pub fn get_rusage(who: i32, rusage: *mut RUsage) -> Result { let who = RUsageWho::try_from(who)?; let mut writer = UserBufferWriter::new(rusage, core::mem::size_of::(), true)?; diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index c8cd4586..c9600fdf 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -875,7 +875,6 @@ impl Syscall { } SYS_GETTID => Self::gettid().map(|tid| tid.into()), - SYS_GETUID => Self::getuid(), SYS_SYSLOG => { let syslog_action_type = args[0]; @@ -889,27 +888,29 @@ impl Syscall { Self::do_syslog(syslog_action_type, user_buf, len) } + SYS_GETUID => Self::getuid(), SYS_GETGID => Self::getgid(), - SYS_SETUID => { - warn!("SYS_SETUID has not yet been implemented"); - Ok(0) - } - SYS_SETGID => { - warn!("SYS_SETGID has not yet been implemented"); - Ok(0) - } + SYS_SETUID => Self::setuid(args[0]), + SYS_SETGID => Self::setgid(args[0]), + + SYS_GETEUID => Self::geteuid(), + SYS_GETEGID => Self::getegid(), + SYS_SETRESUID => Self::seteuid(args[1]), + SYS_SETRESGID => Self::setegid(args[1]), + + SYS_SETFSUID => Self::setfsuid(args[0]), + SYS_SETFSGID => Self::setfsgid(args[0]), + SYS_SETSID => { warn!("SYS_SETSID has not yet been implemented"); Ok(0) } - SYS_GETEUID => Self::geteuid(), - SYS_GETEGID => Self::getegid(), + SYS_GETRUSAGE => { let who = args[0] as c_int; let rusage = args[1] as *mut RUsage; Self::get_rusage(who, rusage) } - #[cfg(target_arch = "x86_64")] SYS_READLINK => { let path = args[0] as *const u8; diff --git a/user/apps/test_cred/.gitignore b/user/apps/test_cred/.gitignore new file mode 100644 index 00000000..91773eb0 --- /dev/null +++ b/user/apps/test_cred/.gitignore @@ -0,0 +1 @@ +test_cred \ No newline at end of file diff --git a/user/apps/test_cred/Makefile b/user/apps/test_cred/Makefile new file mode 100644 index 00000000..18ce2100 --- /dev/null +++ b/user/apps/test_cred/Makefile @@ -0,0 +1,20 @@ +ifeq ($(ARCH), x86_64) + CROSS_COMPILE=x86_64-linux-musl- +else ifeq ($(ARCH), riscv64) + CROSS_COMPILE=riscv64-linux-musl- +endif + +CC=$(CROSS_COMPILE)gcc + +.PHONY: all +all: main.c + $(CC) -static -o test_cred main.c + +.PHONY: install clean +install: all + mv test_cred $(DADK_CURRENT_BUILD_DIR)/test_cred + +clean: + rm test_cred *.o + +fmt: diff --git a/user/apps/test_cred/main.c b/user/apps/test_cred/main.c new file mode 100644 index 00000000..8e4784d2 --- /dev/null +++ b/user/apps/test_cred/main.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include + +int main() +{ + printf("Current uid: %d, euid: %d, gid: %d, egid: %d\n\n", getuid(), geteuid(), getgid(), getegid()); + + // 测试uid + printf("Set uid 1000\n"); + setuid(1000); + int uid = getuid(); + assert(uid == 1000); + printf("Current uid:%d\n\n", uid); + + // 测试gid + printf("Set gid 1000\n"); + setgid(1000); + int gid = getgid(); + assert(gid == 1000); + printf("Current gid:%d\n\n", gid); + + // 测试euid + printf("Setg euid 1000\n"); + seteuid(1000); + int euid = geteuid(); + assert(euid == 1000); + printf("Current euid:%d\n\n", euid); + + // 测试egid + printf("Set egid 1000\n"); + setegid(1000); + int egid = getegid(); + assert(egid == 1000); + printf("Current egid:%d\n\n", egid); + + // 测试uid在非root用户下无法修改 + printf("Try to setuid for non_root.\n"); + assert(setuid(0) < 0); // 非root用户无法修改uid + printf("Current uid: %d, euid: %d, gid: %d, egid: %d\n", getuid(), geteuid(), getgid(), getegid()); +} \ No newline at end of file diff --git a/user/dadk/config/test_cred-0.1.0.dadk b/user/dadk/config/test_cred-0.1.0.dadk new file mode 100644 index 00000000..8efce9aa --- /dev/null +++ b/user/dadk/config/test_cred-0.1.0.dadk @@ -0,0 +1,23 @@ +{ + "name": "test_cred", + "version": "0.1.0", + "description": "测试cred", + "task_type": { + "BuildFromSource": { + "Local": { + "path": "apps/test_cred" + } + } + }, + "depends": [], + "build": { + "build_command": "make install" + }, + "clean": { + "clean_command": "make clean" + }, + "install": { + "in_dragonos_path": "/bin" + }, + "target_arch": ["x86_64"] +} diff --git a/user/sysconfig/etc/group b/user/sysconfig/etc/group index e69de29b..ce813f1a 100644 --- a/user/sysconfig/etc/group +++ b/user/sysconfig/etc/group @@ -0,0 +1 @@ +root::0: \ No newline at end of file diff --git a/user/sysconfig/etc/gshadow b/user/sysconfig/etc/gshadow index e69de29b..653b2e40 100644 --- a/user/sysconfig/etc/gshadow +++ b/user/sysconfig/etc/gshadow @@ -0,0 +1 @@ +root::: \ No newline at end of file diff --git a/user/sysconfig/etc/passwd b/user/sysconfig/etc/passwd index e69de29b..3891904b 100644 --- a/user/sysconfig/etc/passwd +++ b/user/sysconfig/etc/passwd @@ -0,0 +1 @@ +root::0:0:root:/root:/bin/NovaShell \ No newline at end of file diff --git a/user/sysconfig/etc/shadow b/user/sysconfig/etc/shadow index e69de29b..9c6022a5 100644 --- a/user/sysconfig/etc/shadow +++ b/user/sysconfig/etc/shadow @@ -0,0 +1 @@ +root:::0:99999:7::: \ No newline at end of file