Sfoglia il codice sorgente

feat(cred): 初步实现Cred (#846)

* 初步实现Cred

* 添加seteuid和setegid

* 添加cred测试程序

* 修改Cred::fscmp返回结果为CredFsCmp枚举

* 完善root用户相关信息
Jomo 7 mesi fa
parent
commit
0648a547da

+ 5 - 1
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<Vec<String>>,
     pub private_data: SpinLock<FilePrivateData>,
+    /// 文件的凭证
+    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

+ 170 - 0
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<GroupInfo>,
+}
+
+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<Kgid>,
+}

+ 19 - 4
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<Option<RobustListHead>>,
+
+    /// 进程作为主体的凭证集
+    cred: SpinLock<Cred>,
 }
 
 impl ProcessControlBlock {
@@ -687,12 +692,16 @@ impl ProcessControlBlock {
 
     #[inline(never)]
     fn do_create_pcb(name: String, kstack: KernelStack, is_idle: bool) -> Arc<Self> {
-        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指针
     ///
     /// ## 参数

+ 108 - 7
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<usize, SystemError> {
-        // todo: 增加credit功能之后,需要修改
-        return Ok(0);
+        let pcb = ProcessManager::current_pcb();
+        return Ok(pcb.cred.lock().uid.data());
     }
 
     pub fn getgid() -> Result<usize, SystemError> {
-        // todo: 增加credit功能之后,需要修改
-        return Ok(0);
+        let pcb = ProcessManager::current_pcb();
+        return Ok(pcb.cred.lock().gid.data());
     }
 
     pub fn geteuid() -> Result<usize, SystemError> {
-        // todo: 增加credit功能之后,需要修改
-        return Ok(0);
+        let pcb = ProcessManager::current_pcb();
+        return Ok(pcb.cred.lock().euid.data());
     }
 
     pub fn getegid() -> Result<usize, SystemError> {
-        // todo: 增加credit功能之后,需要修改
+        let pcb = ProcessManager::current_pcb();
+        return Ok(pcb.cred.lock().egid.data());
+    }
+
+    pub fn setuid(uid: usize) -> Result<usize, SystemError> {
+        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<usize, SystemError> {
+        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<usize, SystemError> {
+        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<usize, SystemError> {
+        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<usize, SystemError> {
+        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<usize, SystemError> {
+        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<usize, SystemError> {
         let who = RUsageWho::try_from(who)?;
         let mut writer = UserBufferWriter::new(rusage, core::mem::size_of::<RUsage>(), true)?;

+ 13 - 12
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;

+ 1 - 0
user/apps/test_cred/.gitignore

@@ -0,0 +1 @@
+test_cred

+ 20 - 0
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:

+ 42 - 0
user/apps/test_cred/main.c

@@ -0,0 +1,42 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+
+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());
+}

+ 23 - 0
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"]
+}

+ 1 - 0
user/sysconfig/etc/group

@@ -0,0 +1 @@
+root::0:

+ 1 - 0
user/sysconfig/etc/gshadow

@@ -0,0 +1 @@
+root:::

+ 1 - 0
user/sysconfig/etc/passwd

@@ -0,0 +1 @@
+root::0:0:root:/root:/bin/NovaShell

+ 1 - 0
user/sysconfig/etc/shadow

@@ -0,0 +1 @@
+root:::0:99999:7:::