如何让非特权进程监听特权端口(下)

上回书说了一小撮别有用心的其它操作系统,现在要说广大人民群众喜闻乐见的 Linux 了。

Linux 下用 POSIX.1e capabilities(能力) [PRIVS]_ 来实现我们的需求。这个 patch 已经集成进 mainstream 了。

pam_cap

一开始的 linux-privs 只支持基于进程的能力控制,这对我们的要求并没有什么帮助,因为仍然需要从特权身份启动来降低权限。理论上,可以编写一个利用了能力模型的 pam 模块,来指定哪些用户的会话继承哪些权限,但和早期内核配套的 libcap 包里并没有这样的模块,直到后面的 libcap2 才有 pam_cap 实现此功能。

  • /etc/pam.d/login 里加入
auth    optional                        pam_cap.so

注意一定要加在任何 auth sufficient 之前,否则就被跳过了。当然,在 Debian 上可以加到 /etc/pam.d/common-auth 里——也可以运行 pam-auth-update 来生成。这是针对 login 用户的,如果是 su 用户,还需要改相应的 pam 文件,因为 @common-auth 在 su 里排在后面。

  • /etc/security/capability.conf 里加入对应用户的设置,比如
cap_net_bind_service    adoal

表示以用户 adoal 身份运行的进程可以绑定到特权端口……且慢,经过实验,这样设置仍然不起作用,还需要再设置文件系统的能力才行。

文件系统能力

从 2.6.24 内核开始, linux-privs 又支持了基于文件系统的能力功能,能够给文件系统里特定的可执行程序指定一个能力,详见 [FCAP]_ 。简而言之执行

$ sudo setcap cap_net_bind_service=ep /usr/sbin/httpd

之后,任何用户(当然前提是对 /usr/bin/httpdx 权限)都可以启动 apache 监听 80 端口而不需要特权身份。

如果把命令里的 ep 改成 ei ,那么就只有在 /etc/security/capability.conf 里设定好的用户才可以了,其它用户无效——这里 i 表示的是继承(inheritance),也就是程序执行时继承用户的对应能力,而非像 p 那样不管用户是否有对应能力都直接设定。也就是说,如果需要为特定用户设置特定程序的特定能力,需要对用户和程序都做对应设置,缺一不可。

杯具的 RHEL5 和 SUSE

非常值得一提的是,在企业用户里很流行的 Red Hat Enterprise Linux 5 由于生命周期太长而又坚持 ABI 不变动的原则,于是其古老的内核并不能支持基于文件系统的能力模型。所以这里说的方法对 RHEL5 用户(以及 CentOS 5 之类的派生版用户)只能是梦想了。

RHEL6 里内核和 libcap 都更新了,已经可以支持上面两种方法。

SUSE 系(SLES/SLED 和 OpenSUSE)虽然内核支持,并且有 libcap2 包,但是 libcap2 打包时并没有构建 pam_cap.so 所以也不行。