在 Linux 内核版本 2.2 开始,Linux 将一系列的超级管理员权限细分成了一个个可以单独开启关闭的单元,以提供更细粒度的权限控制,这些单元,就被称之为 capabilities。详细的 capabilities 列表可以参考 Man Page Capabilities(7)
部分内容引用自Code Life, 谢谢!


CAP_NET_BIND_SERVICE

拥有这个 capability 的程序,就可以绑定端口号在 1024 以下的特权端口。

setcap

那么,该如何控制每个 capability 呢?答案就是 setcap 命令。上文所提到的命令,就是给指定的这个二进制程序增加 CAP_NET_BIND_SERVICE 这个 capability。

在 capability 名后面,用加号相连接的,则是开启这个 capability 的模式。模式有如下三种:

e: Effective,意为这个 capability 是启用的。

p: Permitted,意为这个 capability 是允许被使用的。

i: inherited,意为这个 capability 可以被其子进程继承。

setcap 命令中,使用加号来开启这个模式,或者使用减号来关闭这个模式。

Eg: sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/caddy

有什么副作用

这个方法确实有一些副作用,或者说是限制:
这个方法对脚本无效。如果要使某个脚本拥有这个能力,则需要为其解释器赋予这个能力,而这明显是一个巨大的安全隐患。
Linux 会为使用了 setcap 或 suid 的程序禁用掉 LD_LIBRARY_PATH。

Systemd
Systemd 也支持在 service 的配置文件中指定 capabilities,其用法示例如下:

[Service] 
# 该服务仅可以使用哪些capabilities 
CapabilityBoundingSet=CAP_NET_BIND_SERVICE 
# 以非特权用户运行程序时需要设定此参数 
AmbientCapabilities=CAP_NET_BIND_SERVICE