在 clone(2)、unshare(2) 和 setns(2) 期间将更改哪些 process/thread 功能集?
Which process/thread capabilities sets will be changed during clone(2), unshare(2), and setns(2)?
user_namespaces(7) 的手册页说:
The child process created by clone(2) with the CLONE_NEWUSER flag starts out with a complete set of capabilities in the new user namespace. Likewise, a process that creates a new user namespace using unshare(2) or joins an existing user namespace using setns(2) gains a full set of capabilities in that namespace.
不幸的是,手册页没有说明哪些能力集(或集)会受到影响:一个或多个 effective caps 集,permitted caps set,inheritable caps set,等等。所以我的问题是:哪些功能集将受到 clone(2)、unshare( 2), 和 setns(2)?
注意:user_namespaces(7)的示例部分似乎表明有效和允许的能力集将被完全启用,而继承的能力全部被丢弃。但是,没有明确的迹象表明这是实际实施的行为。此外,没有迹象表明环境上限是否受到影响;并且我假设边界上限不受影响,尤其是因为边界上限只能下降上限。
为了了解 setns(2) 和 unshare(2) 对功能的影响,我创建了以下 Python 3 个小脚本。确保在尝试 运行 之前安装包 nsenter
和 unshare
(pip3 install nsenter
, ...)。
setns(2)
# usernscaps.py: dump all capabilities sets of this process
# when entering a specific (grand)child user namespace.
from nsenter import Namespace
import sys
def dumpcaps(s):
print(s)
with open('/proc/self/status', 'r') as st:
for line in st:
if line.startswith('Cap'):
print(line.rstrip())
if len(sys.argv) != 2:
print('usage: usernscaps.py <PID>')
exit(1)
dumpcaps('initial:')
try:
with Namespace('/proc/%d/ns/user' % int(sys.argv[1]), 'user'):
entered = True
dumpcaps('after setns:')
except PermissionError:
# Switching back to our original user namespace isn't allowed, so ignore the exception.
try:
entered
except NameError:
print('no permission to enter user namespace')
作为一个普通的非特权用户,让我们创建一个新的用户名space,这个用户名将归我们所有,并用休眠进程保持打开状态(注意: 我们把它放到后台):
unshare -U bash -c "readlink /proc/self/ns/user && sleep infinity" &
接下来,运行 上面的 Python 脚本 usernscaps.py
,并告诉它使用 setns(2) 输入我们新创建的用户 space,然后最后转储功能集:
python3 usernscaps.py $(lsns -t user | grep "infinity" | awk '{ print }')
即使对于我们的非特权用户和进程,在 setns(2):
之后
initial:
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
after setns:
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
这似乎表明 setns(2) 实际上不仅提供了 有效上限 的全套功能,还提供了 允许的上限(这是有道理的,因为有效上限必须随时受允许上限的限制)。不过,它似乎并没有达到继承的上限。
克隆(2)
与之前的脚本类似,但这次取消共享(2)ing。
# usernsunsharecaps.py: dump all capabilities sets of this process
# upon unsharing the user namespace.
import unshare
import sys
def dumpcaps(s):
print(s)
with open('/proc/self/status', 'r') as st:
for line in st:
if line.startswith('Cap'):
print(line.rstrip())
dumpcaps('initial:')
unshare.unshare(unshare.CLONE_NEWUSER)
dumpcaps('after unshare:')
简单地运行它python3 usernsunsharecaps.py
:
initial:
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
after unshare:
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
因此,这也会在取消共享后在新用户名space 中提供完整的 permitted 和 effective 功能。
user_namespaces(7) 的手册页说:
The child process created by clone(2) with the CLONE_NEWUSER flag starts out with a complete set of capabilities in the new user namespace. Likewise, a process that creates a new user namespace using unshare(2) or joins an existing user namespace using setns(2) gains a full set of capabilities in that namespace.
不幸的是,手册页没有说明哪些能力集(或集)会受到影响:一个或多个 effective caps 集,permitted caps set,inheritable caps set,等等。所以我的问题是:哪些功能集将受到 clone(2)、unshare( 2), 和 setns(2)?
注意:user_namespaces(7)的示例部分似乎表明有效和允许的能力集将被完全启用,而继承的能力全部被丢弃。但是,没有明确的迹象表明这是实际实施的行为。此外,没有迹象表明环境上限是否受到影响;并且我假设边界上限不受影响,尤其是因为边界上限只能下降上限。
为了了解 setns(2) 和 unshare(2) 对功能的影响,我创建了以下 Python 3 个小脚本。确保在尝试 运行 之前安装包 nsenter
和 unshare
(pip3 install nsenter
, ...)。
setns(2)
# usernscaps.py: dump all capabilities sets of this process
# when entering a specific (grand)child user namespace.
from nsenter import Namespace
import sys
def dumpcaps(s):
print(s)
with open('/proc/self/status', 'r') as st:
for line in st:
if line.startswith('Cap'):
print(line.rstrip())
if len(sys.argv) != 2:
print('usage: usernscaps.py <PID>')
exit(1)
dumpcaps('initial:')
try:
with Namespace('/proc/%d/ns/user' % int(sys.argv[1]), 'user'):
entered = True
dumpcaps('after setns:')
except PermissionError:
# Switching back to our original user namespace isn't allowed, so ignore the exception.
try:
entered
except NameError:
print('no permission to enter user namespace')
作为一个普通的非特权用户,让我们创建一个新的用户名space,这个用户名将归我们所有,并用休眠进程保持打开状态(注意: 我们把它放到后台):
unshare -U bash -c "readlink /proc/self/ns/user && sleep infinity" &
接下来,运行 上面的 Python 脚本 usernscaps.py
,并告诉它使用 setns(2) 输入我们新创建的用户 space,然后最后转储功能集:
python3 usernscaps.py $(lsns -t user | grep "infinity" | awk '{ print }')
即使对于我们的非特权用户和进程,在 setns(2):
之后initial:
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
after setns:
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
这似乎表明 setns(2) 实际上不仅提供了 有效上限 的全套功能,还提供了 允许的上限(这是有道理的,因为有效上限必须随时受允许上限的限制)。不过,它似乎并没有达到继承的上限。
克隆(2)
与之前的脚本类似,但这次取消共享(2)ing。
# usernsunsharecaps.py: dump all capabilities sets of this process
# upon unsharing the user namespace.
import unshare
import sys
def dumpcaps(s):
print(s)
with open('/proc/self/status', 'r') as st:
for line in st:
if line.startswith('Cap'):
print(line.rstrip())
dumpcaps('initial:')
unshare.unshare(unshare.CLONE_NEWUSER)
dumpcaps('after unshare:')
简单地运行它python3 usernsunsharecaps.py
:
initial:
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
after unshare:
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
因此,这也会在取消共享后在新用户名space 中提供完整的 permitted 和 effective 功能。