![无法使 upstart 服务满足功能要求(7)](https://linux22.com/image/859379/%E6%97%A0%E6%B3%95%E4%BD%BF%20upstart%20%E6%9C%8D%E5%8A%A1%E6%BB%A1%E8%B6%B3%E5%8A%9F%E8%83%BD%E8%A6%81%E6%B1%82(7).png)
我正在开发一个由 upstart(Ubuntu 14.04)启动的守护进程,它需要以非特权用户身份运行(为了安全),但绑定特权端口 443。
我用它setcap
来设置CAP_NET_BIND_SERVICE
可执行文件(不是脚本)的功能。我在允许、有效和继承集(setcap 'cap_net_bind_service+eip' EXEC
)中设置它。
我可以su
将其交给非特权用户,并直接运行它,它运行完美。它正确绑定了端口,并/proc/PID/status
显示了设置了位的正确功能掩码0x400
。
但是当我通过 upstart 启动服务时,它无法使用为二进制文件指定的功能运行,并且bind()
会失败(EPERM)。/proc/PID/status
显示功能掩码全部为 0。
有任何想法吗?
答案1
我现在认为这是一个错误,与 upstart 使用“expect daemon”启动服务的方式有关(即启动时分叉两次的服务)。我注意到,如果我对使用 capabilities(7) 的进程使用 strace,功能也会被忽略。我怀疑 upstart 为了确定要等待的 PID,会跟踪使用“expect daemon”指定的服务足够长的时间以获取 PID,这会导致内核功能机制失败。因此,错误在于功能与进程跟踪交互的方式,以及 upstart 在用“expect daemon”启动服务时使用进程跟踪的事实(这是假设)。
作为一个简单的测试:
- 写一个小C程序绑定到端口 443(不能使用具有功能(7)的解释型语言,如 python)。
- 以非root身份运行它,并发现由于缺乏权限而绑定失败。
- 为您的程序(以 root 身份运行
setcap 'cap_net_bind_service+epi' PROGRAM
) - 以非root身份运行它,并看到它现在已成功。
- 现在用 strace 运行它,发现它现在失败了。
i
(请注意,在步骤 3 中,严格来说,不需要为该测试修改继承的功能集(标志),但对于forks()
诸如我的守护进程之类的进程则需要修改)。
此行为对于避免特权攻击是必要的,但会使 Upstart 行为与功能不兼容。