英语

No New Privileges Flag

execve 系统调用可以授予新启动的程序其父进程没有的特权。最明显的例子是 setuid/setgid 程序和文件 capabilities。为了防止父程序也获得这些特权,内核和用户代码必须小心,防止父程序做任何可能破坏子程序的事情。例如

  • 如果程序是 setuid,动态加载器会以不同的方式处理 LD_* 环境变量。

  • chroot 不允许非特权进程使用,因为它允许从继承 chroot 的进程的角度替换 /etc/passwd

  • exec 代码对 ptrace 有特殊的处理。

这些都是临时的修复。no_new_privs 位 (自 Linux 3.5 起) 是一种新的通用机制,使进程可以安全地修改其执行环境,使其在 execve 中保持不变。任何任务都可以设置 no_new_privs。一旦设置了该位,它将在 fork、clone 和 execve 中继承,并且无法取消设置。设置 no_new_privs 后,execve() 承诺不会授予执行 execve 调用无法完成的任何操作的权限。例如,setuid 和 setgid 位将不再更改 uid 或 gid;文件 capabilities 不会添加到允许的集合中,并且 LSM 不会在 execve 之后放宽约束。

要设置 no_new_privs,请使用

prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);

但请注意:LSM 也可能不会在 no_new_privs 模式下加强对 exec 的约束。(这意味着设置一个通用的服务启动器在执行守护进程之前设置 no_new_privs 可能会干扰基于 LSM 的沙箱。)

请注意,no_new_privs 不会阻止不涉及 execve() 的特权更改。具有适当特权的任务仍然可以调用 setuid(2) 并接收 SCM_RIGHTS 数据报。

到目前为止,no_new_privs 有两个主要用例

  • 为 seccomp 模式 2 沙箱安装的过滤器在 execve 中保持不变,并且可以更改新执行的程序的行为。因此,如果设置了 no_new_privs,则只允许非特权用户安装此类过滤器。

  • 就其本身而言,no_new_privs 可用于减少非特权用户可用的攻击面。如果使用给定 uid 运行的所有内容都设置了 no_new_privs,则该 uid 将无法通过直接攻击 setuid、setgid 和使用 fcap 的二进制文件来提升其特权;它首先需要破坏一些未设置 no_new_privs 位的代码。

将来,如果设置了 no_new_privs,则其他潜在的危险内核功能可能会提供给非特权任务。原则上,当设置了 no_new_privs 时,unshare(2)clone(2) 的几个选项将是安全的,并且 no_new_privs + chroot 比 chroot 本身危险性小得多。