关注了就能看到更多这么棒的文章哦~
A crop of new capabilities
By Jonathan Corbet
June 8, 2020
原文来自:https://lwn.net/Articles/822362/
主译:DeepL
Linux capability赋予用户可以执行一组特定的特权操作的权力,这样就不需要给他授予全部root权限了。可以参见capability的man手册来查看当前capability的列表以及它们控制了什么。自从2014年3.16版本中合入了 CAP_AUDIT_RED
后,内核中一直没有增加任何capability。不过随着5.8版本的发布,这种情况即将发生改变,5.8版本将包含两个新的capability;还有一个capability目前正在开发中。
New capabilties in 5.8
第一个新增capability是 CAP_PERFMON
,去年2月在这里(https://lwn.net/Articles/812719/ )详细介绍过。有这个capability后,用户可以执行性能监控、把BPF程序attach到tracecepoints上、以及其他类似的操作。在当前的内核中,这类性能监控需要一个覆盖范围过于广泛的 CAP_SYS_ADMIN
capability,今后,可以用这个capability来避免给用户过多不需要的权限。当然,拥有 CAP_SYS_ADMIN
的进程仍然也能进行性能监控,如果能从 CAP_SYS_ADMIN
中移除这种权力就更好了,但这样做很可能会破坏现有系统。
另一个新的capability是CAP_BPF,它控制着许多可以用bpf()系统调用进行的操作。在过去的一年里,这个capability一直是许多激烈讨论的主题,请看这里(https://lwn.net/ml/netdev/20190627201923.2589391-1-songliubraving@fb.com/ )或这里(https://lwn.net/ml/netdev/20190827205213.456318-1-ast@kernel.org/) 等等。最初的想法是提供一个叫做 /dev/bpf 的特殊设备,用来控制对 BPF 功能的访问,但这个建议没有被采纳。这里需求的本质实际上是一种新的capability,所以capability似乎是一个更好的解决方案。
目前的 CAP_BPF
控制了一些BPF特定的操作,包括创建BPF maps、使用一些高级的BPF程序功能(bounded loops, cross-program function calls等)、访问BPF type format(BTF)数据等。虽然最初的计划是不用管原有 CAP_SYS_ADMIN
的进程的向后兼容性,以避免Alexei Starovoitov所描述的 "deprecated mess",但实际合并后的代码确实仍能识别 CAP_SYS_ADMIN
。
CAP_BPF
的一个有趣的方面是,就其本身而言,它并没有赋予做很多有用的事情的能力。尤其是,只用 CAP_BPF
仍然无法加载大多数类型的BPF程序,除了它之外,进程必须持有与感兴趣的子系统相关的其他capability。例如,只有当进程也同时持有 CAP_PERFMON
时,才能加载用于tracepoints、kprobes或perf事件的BPF program。大多数与网络有关的program types(例如packet classifiers, XDP programs等)都需要 CAP_NET_ADMIN
。如果用户要加载一个调用 bpf_trace_printk()
的网络相关函数的BPF program,那么就同时需要 CAP_NET_ADMIN
和 CAP_PERFMON
。因此,需要把 CAP_BPF
与其他capability组合使用,才赋予了在各种特定情况下使用BPF的能力。
此外,有些BPF操作仍然需要 CAP_SYS_ADMIN
。举例来说,将BPF program offload到硬件里面就需要这个权限。此外,另一个例子是遍历迭代BPF object(program, map等等)来查看系统中加载了什么东西时。比如说,查询某个map的capability,可能会被一个进程用来改变属于其他用户的map,从而导致各种混乱问题。因此,这类动作的门槛更高。
这项工作的最终结果是,在没有完整root(甚至也不需要获取 CAP_SYS_ADMIN
)权限的情况下,就可以进行相当多的网络管理、性能监控和tracing工作。
CAP_RESTORE
CAP_RESTORE这个提案是5月底提出来的,目的是允许没有系统管理员权限的进程来进行checkpoint和恢复。patch作者Adrian Reber指出,经过多年开发工作的checkpoint/restore in user space (CRIU)功能已经基本可用了。不过还存在一些障碍,其中之一就是process ID。理想情况下,一个进程可以抓取checkpoint或被恢复出来,也可以是在另一个系统上恢复,进程本身甚至没有注意到发生了什么事情。不过,如果PID发生了变化,那可能会导致一些意外结果。因此,CRIU的开发者希望能够使用一个进程在被快照时的相同PID(多线程情况下希望各个线程的PID也都不变)来还原,当然,前提是所需的ID是没被占用的。
通过clone3()就可以可以设置新进程的PID,但非特权用户无法使用这个功能。因为如果能够任意指定PID来创建进程,会使一些攻击变得更容易进行,所以ID的设置当然只限于有 CAP_SYS_ADMIN
capability的进程。管理员往往会拒绝给人授予这个权限,所以CRIU的用户一直在采用一些变通方法,Reber列出了几个方法,有的比较合理,有的就很吓人了:
使用container容器的话,当然可以在用户空间在自己的namespace内来控制其使用的PID了,这里完全没有困难,但是显然这并不是个适合所有人的通用解决方案。
一些高性能计算用户则通过使用setuid wrapper运行CRIU来获得这个功能。
有些用户采用了一个类似于fork bomb的方法,快速创建(和杀死)进程,不断尝试直到拿到所需的PID。
Java虚拟机开发者显然希望使用CRIU来缩短他们漫长的启动时间。他们一直都是简单把kernel里的
CAP_SYS_ADMIN
检查给改掉(这种变通方法导致Casey Schaufler惊呼:"这不是变通方法,而是违反了规则。Bad JVM! No biscuit!")。
Reber认为,当然应该找到比上述这些更好的解决方案,他表示CAP_RESTORE将会是一个很好的选择。
对这个patch的讨论集中在几个问题上,首先是是否确实有这个需要。Schaufler非常想知道,新的capability能得到什么好处,是否真的足以进行checkpoint和restore操作,而完全不再需要 CAP_SYS_ADMIN
。他说,如果只是把一些东西从 CAP_SYS_ADMIN
中拆出来,这是没有好处的:
如果我们把
CAP_SYS_ADMIN
适当地拆分出来,我们就会有几百种capability,从而没有人能够搞得清楚要做某件事需要哪些capability。仅仅只是分解CAP_SYS_ADMIN
的话,尤其是如果进程无论如何都会需要其他capability的时候,你什么好处也得不到。
不过看起来CAP_RESTORE本身就足够完成这个任务,所以Schaufler的反对意见似乎后来也就不再提了。
人们提出的另一个问题是:有了这个新capability的话,还能实现哪些其他用法?patch中暗示还有其他的功能,但它们尚未实现出来。主要一个功能可能就是能够读取/proc/pid/map_files中的entry来在checkpoint过程中能把各个mapping都正确dump出来。下一个版本的patch就会实现这个功能。一些开发者想知道是否应该有两个新的capability,就是也新增一个是CAP_CHECKPOINT,以分别处理各个CHECKPOINT和RESTORE这两个步骤中的具体需求。不过,如果没有更多的理由出现的话,很可能不会这么做。
这个patch的最终版本还有待观察。与安全相关的改动可能需要经过大量的讨论和修改才能合入mainline。但这种capability似乎很有用处,最终应该会合入的,顶多拖得久一点或者换个形式。
全文完
LWN文章遵循CC BY-SA 4.0许可协议。
欢迎分享、转载及基于现有协议再创作~
长按下面二维码关注,关注LWN深度文章以及开源社区的各种新近言论~