容器里一个 setuid 程序能把普通用户变成 root 吗?no-new-privileges 到底挡住了什么、又没挡住什么?这篇用一份 setuid root 的 Python 在两种设置下对比,并验证 docker exec 进去的进程。
/pysuid 的权限:-rwsr-xr-x 1 root root 67168 Oct 10 13:05 /py
默认:
setuid 的 /pysuid → uid=1000 euid=0 gid=0 ['CapEff:\t00000000a80425fb', 'NoNewPrivs:\t0']
普通的 /pynormal → uid=1000 euid=1000 gid=0 ['CapEff:\t0000000000000000', 'NoNewPrivs:\t0']
--security-opt no-new-privileges:
setuid 的 /pysuid → uid=1000 euid=1000 gid=0 ['CapEff:\t0000000000000000', 'NoNewPrivs:\t1']
普通的 /pynormal → uid=1000 euid=1000 gid=0 ['CapEff:\t0000000000000000', 'NoNewPrivs:\t1']
--security-opt no-new-privileges=false:
setuid 的 /pysuid → uid=1000 euid=0 gid=0 ['CapEff:\t00000000a80425fb', 'NoNewPrivs:\t0']
普通的 /pynormal → uid=1000 euid=1000 gid=0 ['CapEff:\t0000000000000000', 'NoNewPrivs:\t0']默认情况下,普通用户运行镜像里 setuid root 的程序,得到 euid=0 和全部 14 个 capability。加了 --security-opt no-new-privileges 后,setuid 位被忽略,euid 仍是 1000。我是自己制造了一份 setuid 的 Python;镜像里本来就有的 setuid 程序(如 su、ping)没有逐个测。
root 用户 + no-new-privileges:uid=0 euid=0 gid=0 ['CapEff:\t00000000a80425fb', 'NoNewPrivs:\t1'] docker exec 进入 no-new-privileges 的容器,运行 /pysuid:uid=1000 euid=1000 gid=0 ['CapEff:\t0000000000000000', 'NoNewPrivs:\t1'] docker exec --user 0 进去:uid=0 euid=0 gid=0 ['CapEff:\t00000000a80425fb', 'NoNewPrivs:\t1'] HostConfig.SecurityOpt = [no-new-privileges]
这个标志不降低已经是 root 的进程的权限;docker exec 进入这个容器的进程同样带着 NoNewPrivs=1。它防止的是「通过 execve 获得比父进程更多的权限」,所以常和 --cap-drop ALL 一起用(见 c40)。