传统的unix权限模型将进程分为root用户进程(有效用户id为0)和普通用户进程。普通用户需要root权限的某些功能,通常通过setuid系统调用实现。但普通用户并不需要root的所有权限,可能仅仅需要修改系统时间的权限而已。这种粗放的权限管理方式势必会带来一定的安全隐患。
linux内核中引入了capability,用于消除需要执行某些操作的程序对root权限的依赖。
capability用于分割root用户的权限,将root的权限分割为不同的能力,每一种能力代表一定的特权操作。例如,CAP_SYS_MODULE用于表示用户加载内核模块的特权操作。根据进程具有的能力来进行特权操作的访问控制。
只有进程和可执行文件才有能力,每个进程拥有以下几组能力集(set)。
- cap_effective: 进程当前可用的能力集
- cap_inheritable: 进程可以传递给子进程的能力集
- cap_permitted: 进程可拥有的最大能力集
- cap_ambient: Linux 4.3后引入的能力集,
- cap_bounding: 用于进一步限制能力的获取
可以通过/proc/${pid}/status文件中的CapInh CapPrm CapEff CapBnd CapAmb来表示,每个字段为8个字节即64bit,每个比特表示一种能力,这几个字段存放在进程的内核数据结构task_struct中,由此可见capability的最小单位为线程,而不是进程。
example 1 设置进程能力
在执行下面程序之前需要安装yum install libcap-devel
| |
并执行如下操作:
| |
example 2 获取进程能力
| |
可以通过capget命令获取进程的能力
| |
工具
- getcap用于获取程序文件所具有的能力。
- getpcaps用于获取进程所具有的能力。
- setcap用于设置程序文件所具有的能力。
- capsh 查看和设置程序的能力
| |
runc项目中的应用
runc的容器配置文件spec.Process.Capabilities可以定义各个能力集的能力,用来限制容器的能力。
docker中的应用
docker默认情况下给容器去掉了一些比较危险的capabilities,比如cap_sys_admin。
例如在docker中使用gdb命令默认是不允许的,这是因为docker已经将SYS_PTRACE相关的能力给去掉了。
在docker中使用--cap-add和--cap-drop命令来增加和删除capabilities,
可以使用--privileged赋予容器所有的capabilities,该操作谨慎使用。