9

我以 root 用户身份登录到终端。

然后在 Python 中:

os.setuid(471)能够切换到子根,但是当我尝试使用切换回根用户os.setuid(0)时出现以下错误:Operation not permitted

请让我知道如何从 subroot 切换回 root 用户。

4

3 回答 3

10

在子进程中调用os.fork()并切换到非root用户。“切换回来”只需在子节点中退出并等待子节点在父节点中退出。例如:

pid = os.fork()
if pid == 0:
    # child - do the work and exit
    try:
        os.setuid(471)
        ... do the work here
    finally:
        os._exit(0)

# parent - wait for the child to do its work and keep going as root
os.waitpid(pid, 0)
于 2013-01-09T07:57:40.533 回答
8

这不是 setuid 的工作方式。当 root 自身降级时,无法重新获得 root 是设计使然。一旦你放弃 root (在这种情况下),它就消失了。

如果您以 root 身份使用 setuid,则无法返回。

我假设 os.setuid 是一个通过 C 级调用的瘦代理。从手册页:

如果用户是 root 或程序是 set-user-ID-root,则必须特别小心。setuid() 函数检查调用者的有效用户 ID,如果它是超级用户,则所有与进程相关的用户 ID 都设置为 uid。发生这种情况后,程序就不可能重新获得 root 权限。


至于为什么无法重新获得root,考虑一个典型的使用。想象一个 Apache 服务器下降到www(或某种非特权用户)来处理实际请求。如果您可以重新获得 root,Python 脚本(或 PHP/Perl/CGI/等)可以重新获得 root 并造成绝对的破坏。


至于解决方案,您可以改用 seteuid (os.seteuid - 再一次,一个简单的代理到 C 级seteuid)。关于 setuid 和 seteuid 的 python 文档看起来很糟糕,但是有大量关于系统调用的文档。

至于暂时掉根和恢复的安全性......你需要非常小心。如果恶意代码有机会获得根,你就完蛋了。出于这个原因,最好派生一个子进程(正如 user4815162342 所建议的那样)。子进程将无法重新root。可以在此处找到有关这些问题的更多信息。更多关于 setuid 的一般奇怪之处在这里

这个想法是使用 seteuid 设置有效的用户 ID 并产生一个新进程。由于 exec 的工作方式,有效的用户 id 将被复制到新进程保存的 uid 中。由于保存的 uid 不再是 root,因此无法将 root 改回。更多有趣的文档可以在这里找到。

最相关的部分:

如果在 filename 指向的程序文件上设置了 set-user-ID 位,并且底层文件系统没有挂载 nosuid(mount(2) 的 MS_NOSUID 标志),并且调用进程没有被 ptrace,那么调用进程的有效用户ID更改为程序文件所有者的有效用户ID。类似地,当设置程序文件的set-group-ID位时,调用进程的有效组ID被设置为程序文件的组。

进程的有效用户ID复制到保存的set-user-ID;类似地,有效组 ID 被复制到保存的 set-group-ID 中。此复制发生在由于 set-user-ID 和 set-group-ID 权限位而发生的任何有效 ID 更改之后。

于 2013-01-09T07:47:31.663 回答
5

Use seteuid() instead to set the effective ID but maintain the privilege:

import os
os.seteuid(471)
...
os.seteuid(os.getuid())
于 2013-01-23T09:09:29.670 回答