Parcourir la source

fix(syscall): 修复 setdomainname 和 sethostname 系统调用 (#1298)

- 添加 CAP_SYS_ADMIN 权限检查
- 修复字符串处理逻辑
- 确保 UnameTest 测试通过

Signed-off-by: longjin <longjin@DragonOS.org>
LoGin il y a 1 mois
Parent
commit
5946260e1e

+ 54 - 1
kernel/src/process/cred.rs

@@ -17,8 +17,50 @@ int_like!(Kgid, AtomicKgid, usize, AtomicUsize);
 bitflags! {
     pub struct CAPFlags:u64{
         const CAP_EMPTY_SET = 0;
-        const CAP_SETPCAP_BIT = 1 << 8;
         const CAP_FULL_SET = (1 << 41) - 1;
+
+        // 具体的capability定义,与Linux保持一致
+        const CAP_CHOWN = 1 << 0;
+        const CAP_DAC_OVERRIDE = 1 << 1;
+        const CAP_DAC_READ_SEARCH = 1 << 2;
+        const CAP_FOWNER = 1 << 3;
+        const CAP_FSETID = 1 << 4;
+        const CAP_KILL = 1 << 5;
+        const CAP_SETGID = 1 << 6;
+        const CAP_SETUID = 1 << 7;
+        const CAP_SETPCAP = 1 << 8;
+        const CAP_LINUX_IMMUTABLE = 1 << 9;
+        const CAP_NET_BIND_SERVICE = 1 << 10;
+        const CAP_NET_BROADCAST = 1 << 11;
+        const CAP_NET_ADMIN = 1 << 12;
+        const CAP_NET_RAW = 1 << 13;
+        const CAP_IPC_LOCK = 1 << 14;
+        const CAP_IPC_OWNER = 1 << 15;
+        const CAP_SYS_MODULE = 1 << 16;
+        const CAP_SYS_RAWIO = 1 << 17;
+        const CAP_SYS_CHROOT = 1 << 18;
+        const CAP_SYS_PTRACE = 1 << 19;
+        const CAP_SYS_PACCT = 1 << 20;
+        const CAP_SYS_ADMIN = 1 << 21;
+        const CAP_SYS_BOOT = 1 << 22;
+        const CAP_SYS_NICE = 1 << 23;
+        const CAP_SYS_RESOURCE = 1 << 24;
+        const CAP_SYS_TIME = 1 << 25;
+        const CAP_SYS_TTY_CONFIG = 1 << 26;
+        const CAP_MKNOD = 1 << 27;
+        const CAP_LEASE = 1 << 28;
+        const CAP_AUDIT_WRITE = 1 << 29;
+        const CAP_AUDIT_CONTROL = 1 << 30;
+        const CAP_SETFCAP = 1 << 31;
+        const CAP_MAC_OVERRIDE = 1 << 32;
+        const CAP_MAC_ADMIN = 1 << 33;
+        const CAP_SYSLOG = 1 << 34;
+        const CAP_WAKE_ALARM = 1 << 35;
+        const CAP_BLOCK_SUSPEND = 1 << 36;
+        const CAP_AUDIT_READ = 1 << 37;
+        const CAP_PERFMON = 1 << 38;
+        const CAP_BPF = 1 << 39;
+        const CAP_CHECKPOINT_RESTORE = 1 << 40;
     }
 }
 
@@ -193,6 +235,17 @@ impl Cred {
     pub fn getgroups(&self) -> &Vec<Kgid> {
         &self.groups
     }
+
+    /// 检查当前进程是否具有指定的capability
+    pub fn has_capability(&self, cap: CAPFlags) -> bool {
+        // 检查effective capability set中是否包含指定的capability
+        self.cap_effective.contains(cap)
+    }
+
+    /// 检查当前进程是否具有CAP_SYS_ADMIN权限
+    pub fn has_cap_sys_admin(&self) -> bool {
+        self.has_capability(CAPFlags::CAP_SYS_ADMIN)
+    }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Default)]

+ 5 - 4
kernel/src/process/namespace/uts_namespace.rs

@@ -201,10 +201,11 @@ impl UtsNamespace {
     }
 
     /// 检查是否有权限修改 UTS 信息
-    fn check_uts_modify_permission(&self) -> bool {
-        // TODO: 实现完整的 capability 检查
-        // 目前暂时返回 true,后续需要检查 CAP_SYS_ADMIN
-        true
+    pub fn check_uts_modify_permission(&self) -> bool {
+        // 检查当前进程是否具有 CAP_SYS_ADMIN 权限
+        let pcb = ProcessManager::current_pcb();
+        let cred = pcb.cred();
+        cred.has_cap_sys_admin()
     }
 }
 

+ 1 - 1
kernel/src/process/syscall/sys_cap_get_set.rs

@@ -125,7 +125,7 @@ impl Syscall for SysCapset {
         // - 拥有 CAP_SETPCAP:pI_new ⊆ (pI_old ∪ pP_old) ∩ bset
         // - 不拥有:pI_new ⊆ (pI_old ∪ pP_old) 且 pI_new ⊆ (pI_old ∪ bset)
         // 使用公开常量 CAP_SETPCAP_BIT 判定是否拥有 CAP_SETPCAP
-        let has_setpcap = p_e_old.contains(CAPFlags::CAP_SETPCAP_BIT);
+        let has_setpcap = p_e_old.contains(CAPFlags::CAP_SETPCAP);
         if has_setpcap {
             let inh_cap_allow = (p_i_old | p_p_old) & bset;
             if (p_i_new & !inh_cap_allow) != 0 {

+ 13 - 4
kernel/src/process/syscall/sys_setdomainname.rs

@@ -30,19 +30,28 @@ impl Syscall for SysSetdomainname {
         let name_ptr = Self::name(args);
         let len = Self::len(args);
 
+        // 获取当前进程的 UTS namespace
+        let uts_ns = ProcessManager::current_utsns();
+
+        // 检查权限(需要 CAP_SYS_ADMIN)- 权限检查应该在长度验证之前
+        if !uts_ns.check_uts_modify_permission() {
+            return Err(SystemError::EPERM);
+        }
+
         // 检查长度是否合法
         if len == 0 || len >= NewUtsName::MAXLEN {
             return Err(SystemError::EINVAL);
         }
-        let s = check_and_clone_cstr(name_ptr, Some(NewUtsName::MAXLEN + 1))?;
 
+        // 使用check_and_clone_cstr安全地从用户空间读取字符串,但限制长度为len
+        let s = check_and_clone_cstr(name_ptr, Some(core::cmp::min(len, NewUtsName::MAXLEN) + 1))?;
         let ss = s.to_str().map_err(|_| SystemError::EINVAL)?;
 
-        // 获取当前进程的 UTS namespace
-        let uts_ns = ProcessManager::current_utsns();
+        // 截断到指定长度
+        let truncated = if ss.len() > len { &ss[..len] } else { ss };
 
         // 设置域名
-        uts_ns.set_domainname(ss)?;
+        uts_ns.set_domainname(truncated)?;
 
         Ok(0)
     }

+ 13 - 4
kernel/src/process/syscall/sys_sethostname.rs

@@ -30,19 +30,28 @@ impl Syscall for SysSethostname {
         let name_ptr = Self::name(args);
         let len = Self::len(args);
 
+        // 获取当前进程的 UTS namespace
+        let uts_ns = ProcessManager::current_utsns();
+
+        // 检查权限(需要 CAP_SYS_ADMIN)- 权限检查应该在长度验证之前
+        if !uts_ns.check_uts_modify_permission() {
+            return Err(SystemError::EPERM);
+        }
+
         // 检查长度是否合法
         if len == 0 || len >= NewUtsName::MAXLEN {
             return Err(SystemError::EINVAL);
         }
-        let s = check_and_clone_cstr(name_ptr, Some(NewUtsName::MAXLEN + 1))?;
 
+        // 使用check_and_clone_cstr安全地从用户空间读取字符串,但限制长度为len
+        let s = check_and_clone_cstr(name_ptr, Some(core::cmp::min(len, NewUtsName::MAXLEN) + 1))?;
         let ss = s.to_str().map_err(|_| SystemError::EINVAL)?;
 
-        // 获取当前进程的 UTS namespace
-        let uts_ns = ProcessManager::current_utsns();
+        // 截断到指定长度
+        let truncated = if ss.len() > len { &ss[..len] } else { ss };
 
         // 设置主机名
-        uts_ns.set_hostname(ss)?;
+        uts_ns.set_hostname(truncated)?;
 
         Ok(0)
     }

+ 3 - 0
user/apps/tests/syscall/gvisor/blocklists/uname_test

@@ -0,0 +1,3 @@
+# 需要添加SYS_CLONE3之后,才能开始验证这个测试,否则内核会panic
+UnameTest.UnshareUTS
+

+ 1 - 0
user/apps/tests/syscall/gvisor/whitelist.txt

@@ -6,6 +6,7 @@
 read_test
 chdir_test
 bad_test
+uname_test
 
 # 文件系统相关测试
 #stat_test