我知道这是一个老问题,但是现在有了最新的(>= 4.3)内核,这个问题终于有了一个很好的答案——环境能力。
快速的答案是从git中获取libcap的最新(尚未发布的)版本的副本并编译它。将生成的progs/capsh二进制文件复制到某个地方(/usr/local/bin是一个不错的选择)。然后,作为根用户,使用
/usr/local/bin/capsh --keep=1 --user='your-service-user-name' \
--inh='cap_net_bind_service' --addamb='cap_net_bind_service' \
-- -c 'your-program'
按顺序,我们是
声明当切换用户时,我们希望保持当前的功能集
切换用户和组到“your-service-user-name”
将cap_net_bind_service功能添加到继承的&环境集
派生bash -c 'your-command'(因为capsh会自动用——后面的参数启动bash)
这里隐藏着很多秘密。
Firstly, we are running as root, so by default, we get a full set of capabilities. Included in this is the ability to switch uid & gid with the setuid and setgid syscalls. However, ordinarily when a program does this, it loses its set of capabilities - this is so that the old way of dropping root with setuid still works. The --keep=1 flag tells capsh to issue the prctl(PR_SET_KEEPCAPS) syscall, which disables the dropping of capabilities when changing user. The actual changing of users by capsh happens with the --user flag, which runs setuid and setgid.
The next problem we need to solve is how to set capabilities in a way that carries on after we exec our children. The capabilities system has always had an 'inherited' set of capabilities, which is " a set of capabilities preserved across an execve(2)" [capabilities(7)]. Whilst this sounds like it solves our problem (just set the cap_net_bind_service capability to inherited, right?), this actually only applies for privileged processes - and our process is not privileged anymore, because we already changed user (with the --user flag).
新的环境能力集解决了这个问题——它是“在一个没有特权的程序的执行中保存的一组能力。”通过将cap_net_bind_service放在环境集中,当capsh exec执行我们的服务器程序时,我们的程序将继承此功能,并能够将侦听器绑定到低端口。
如果您有兴趣了解更多信息,功能手册页详细解释了这一点。通过strace运行capsh也是非常有用的!