我正在开发一个由(Ubuntu 14.04)启动的守护进程upstart
,它需要以非特权用户身份运行(为了安全),但绑定特权端口 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
我现在认为这是一个错误,并且与新贵使用“期望守护进程”启动服务的方式有关(即启动时分叉两次的服务)。我注意到,如果我在使用功能(7)的进程上使用 strace,功能也会被忽略。我怀疑暴发户为了确定要等待的 PID,会跟踪使用“expect daemon”指定的服务足够长的时间来获取 PID,这会导致内核功能机制失败。因此,错误在于功能与进程跟踪交互的方式,以及 upstart 在使用“expect daemon”启动服务时使用进程跟踪的事实(这是假设)。
作为一个简单的测试:
- 写一个小C程序绑定到端口 443(您不能使用解释语言,例如具有功能(7)的 python)。
- 以非 root 身份运行它,并看到它由于缺乏权限而无法绑定。
- 为您的应用程序设置 CAP_NET_BIND_SERVICE 功能程序(以 root 身份运行
setcap 'cap_net_bind_service+epi' PROGRAM
) - 以非 root 身份运行它,并看到它现在成功了。
- 现在用 strace 运行它,看看它现在失败了。
i
(请注意,严格来说,在步骤 3 中,不需要为此测试修改继承功能集(标志),但对于forks()
诸如我的守护程序之类的进程则需要修改)。
我将针对此问题向内核提交一个错误,因为功能(7)手册页上没有任何内容表明它不应该与进程跟踪一起使用。
答案2
一种解决方法是不使用expect fork 或expect daemon,而只是使您的守护进程成为前台进程。那么Upstart根本就不会追踪它。