Container和VM的隔离性分析 (2) Capabilities

1,000 阅读7分钟

capabilities 机制属于进程管理的一部分。 Linux内核中的capabilities机制是由一个名为capable()的函数实现的。这个函数用于判断当前进程是否具有某个指定的权限。如果具有,则返回0,否则返回一个错误码。capable()函数中的权限信息是保存在一个名为struct cred的结构体中的。这个结构体表示了一个进程的身份认证信息,包括uidgid、supplementary groups、capabilities等。在Linux内核中,每个进程都有自己的cred结构体,其指针保存在进程的task_struct结构体中。当进程创建时,它的cred结构体被初始化为拥有最大权限的状态。当进程需要获取某个资源时,内核会调用相应的权限检查函数,判断进程是否具有访问该资源的权限。这些权限检查函数都是基于cred结构体中的权限信息来实现的。主要实现在 security/commoncap.c 文件中。
在该文件中,定义了许多函数和数据结构,主要用于实现 capabilities 机制的相关操作。其中一些重要的函数和数据结构如下:

-   struct kernel_cap_struct:定义了 Linux 内核中的 capabilities 数据结构,用于表示一组能力集合。
-   struct cred:定义了进程的凭证(credential)结构体,其中包括了当前进程的 capabilities 集合。
-   capable():用于判断当前进程是否拥有某个指定的能力。
-   capable_wrt_inode_uidgid():用于判断当前进程是否拥有对某个 inode 节点的指定权限。
-   cap_capable():用于判断当前进程是否拥有某个指定的能力,但与 capable() 不同的是,该函数可以传入一个 struct cred 结构体,用于在给定的凭证中判断是否拥有该能力。
-   cap_set_flag():用于设置当前进程的 capabilities 标志。
-   cap_set_proc():用于设置当前进程的 capabilities 集合。

在具体的实现中,内核会利用这些函数和数据结构来实现 capabilities 机制的相关功能。具体来说,内核会在进程的创建、权限检查、文件访问控制等过程中,使用这些函数和数据结构来实现 capabilities 机制的相关功能。例如,在进程的创建过程中,内核会使用 cap_set_proc() 函数来设置新进程的 capabilities 集合;在权限检查的过程中,内核会使用 cap_capable() 函数来判断当前进程是否拥有某个指定的能力;在文件访问控制的过程中,内核会使用 capable_wrt_inode_uidgid() 函数来判断当前进程是否拥有对某个 inode 节点的指定权限。总之,security/commoncap.c 文件中定义的函数和数据结构,是实现 capabilities 机制的重要组成部分,内核会利用这些组件来实现 capabilities 机制的相关功能。
在Linux内核中,capabilities机制对以下几种系统资源的权限控制实现:

  1. 系统调用:Linux内核中的capabilities机制通过为每个系统调用指定一组对应的capability bit来实现对系统调用的权限控制。在执行系统调用之前,内核会检查进程是否具有执行该系统调用所需的capability bit,如果不具备,则会返回EPERM错误。例如,当一个进程调用reboot()系统调用时,内核会检查该进程是否具有CAP_SYS_REBOOT这个capability bit,如果没有,则返回EPERM错误。实现代码位于内核源码的security/commoncap.c文件中。
  2. 网络协议:Linux内核中的capabilities机制可以通过对网络命名空间的隔离来实现对网络协议的权限控制。通过将进程限制在特定的网络命名空间中,可以限制进程对特定网络协议的访问权限。例如,在默认情况下,普通用户进程无法使用ICMP协议,因为ICMP协议对应的网络命名空间默认被设为仅能由超级用户进程使用。实现代码位于内核源码的net/core/net_namespace.c文件中。
  3. 文件系统:Linux内核中的capabilities机制可以通过对文件的权限位进行扩展来实现对文件系统的权限控制。通过设置文件的capability bit,可以实现对某个特定的文件进行细粒度的权限控制,例如限制进程对/dev/mem文件的读写操作。实现代码位于内核源码的security/commoncap.c文件中。
  4. 进程管理:Linux内核中的capabilities机制可以通过为每个进程指定一组对应的capability bit来实现对进程管理的权限控制。例如,如果一个进程具有CAP_KILL这个capability bit,则可以向其他进程发送信号,从而实现对其他进程的管理。实现代码位于内核源码的security/commoncap.c文件中。
  5. 系统资源:Linux内核中的capabilities机制可以通过设置每个进程的rlimit来实现对系统资源的权限控制。通过设置rlimit的值,可以限制进程对CPU、内存等系统资源的使用。实现代码位于内核源码的kernel/sys.c文件中。总之,Linux内核中的capabilities机制可以对多个系统资源进行细粒度的权限控制,从而实现对进程访问系统资源的精确控制。

应用程序可以通过系统调用来访问capabilities机制。这些系统调用包括capget()、capset()、capsetp()、prctl()等。其中,capget()和capset()函数用于获取和设置当前进程的capabilities。这两个函数都需要传入一个指向cap_user_header_t结构体的指针和一个指向cap_user_data_t结构体的指针,分别表示capabilities的头部和数据部分。通过这两个结构体,可以获取和设置当前进程的capabilities。capsetp()函数和capset()函数类似,但是可以设置指定进程的capabilities。 prctl()函数可以用于获取和设置某个进程的capabilities。这个函数需要传入一个特定的参数,指示要获取或设置哪个进程的capabilities。

以下是一个简单的程序示例,展示了如何使用capget和capset系统调用查询和修改进程的capabilities设置:

#include <stdio.h>#include <sys/capability.h>  
int main() {    
    // 查询当前进程的capabilities设置    
    cap_t caps = cap_get_proc();    
    if (caps == NULL) {
        perror("cap_get_proc");        
        return -1;    }  
    // 打印capabilities设置    
    printf("Current capabilities: %s\n", cap_to_text(caps, NULL));  
    return 0;
    }  
gcc test.c -o test -lcaproot

@n192-191-015:~# ./test Current process capabilities: = cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read+ep 

在 Linux 操作系统中,每个进程都有一组 capability 权限,它们定义了进程可以执行的特权操作的范围。以下是常见的 capability 权限列表:

  1. CAP_CHOWN:修改文件拥有者
  2. CAP_DAC_OVERRIDE:忽略文件权限限制
  3. CAP_DAC_READ_SEARCH:读取任何文件和目录,搜索任何目录
  4. CAP_FOWNER:在文件系统级别创建任何文件和目录,修改任何文件和目录的权限
  5. CAP_FSETID:在任何文件上设置 setuid 和 setgid 位
  6. CAP_KILL:发送信号给任何进程
  7. CAP_SETGID:修改进程组 ID
  8. CAP_SETUID:修改进程用户 ID
  9. CAP_SETPCAP:修改进程的 capability
  10. CAP_LINUX_IMMUTABLE:修改文件的 "immutable" 标志
  11. CAP_NET_BIND_SERVICE:绑定到低于 1024 的端口
  12. CAP_NET_BROADCAST:广播访问
  13. CAP_NET_ADMIN:进行网络配置
  14. CAP_NET_RAW:进行原始套接字访问
  15. CAP_IPC_LOCK:锁定共享内存段
  16. CAP_IPC_OWNER:设置共享内存段所有者
  17. CAP_SYS_MODULE:加载或卸载内核模块
  18. CAP_SYS_RAWIO:进行 I/O 端口访问和内存映射
  19. CAP_SYS_CHROOT:进行 chroot 操作
  20. CAP_SYS_PTRACE:进行进程跟踪和调试
  21. CAP_SYS_PACCT:启用进程记账
  22. CAP_SYS_ADMIN:执行系统级别的管理操作
  23. CAP_SYS_BOOT:重启系统
  24. CAP_SYS_NICE:设置进程 nice 值
  25. CAP_SYS_RESOURCE:设置进程资源限制
  26. CAP_SYS_TIME:更改系统时间
  27. CAP_SYS_TTY_CONFIG:更改 TTY 设备的配置
  28. CAP_MKNOD:创建字符设备和块设备
  29. CAP_LEASE:创建和管理文件租约
  30. CAP_AUDIT_WRITE:写入审计日志
  31. CAP_AUDIT_CONTROL:控制审计配置
  32. CAP_SETFCAP:设置文件 capability
  33. CAP_MAC_OVERRIDE:在系统中覆盖 MAC 策略
  34. CAP_MAC_ADMIN:管理 MAC 策略和进程标签
  35. CAP_SYSLOG:配置系统日志
  36. CAP_WAKE_ALARM:启用 RTC 闹钟
  37. CAP_BLOCK_SUSPEND:阻止系统进入挂起状态
  38. CAP_AUDIT_READ:读取审计规则和日志这些 capability 权限对系统安全至关重要,因为它们允许系统管理员控制进程对系统资源的访问级。