我以root用户身份登录终端。
然后在Python中:
os.setuid(471)
能够切换到subroot,但当我尝试使用os.setuid(0)
切换回root用户时,我收到以下错误:Operation not permitted
请告诉我如何从subroot切换回root用户。
答案 0 :(得分:9)
调用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)
答案 1 :(得分:8)
这不是setuid的工作方式。当root降级时,设计根本无法重新获得。一旦你放弃root(在这种情况下),它就消失了。
如果您以root身份使用setuid,则无法返回。
我假设os.setuid是通过C级调用的瘦代理。来自man页面:
如果用户是root用户或程序是set-user-ID-root,则必须特别小心。 setuid()函数检查调用者的有效用户ID,如果是超级用户,则所有与进程相关的用户ID都设置为uid。发生这种情况后,程序无法重新获得root权限。
至于为什么 root无法重新获得,请考虑典型用法。想象一下,Apache服务器下降到www
(或某种非特权用户)来处理实际请求。如果你能重新获得root,那么Python脚本(或者PHP / Perl / CGI /等)可能会重获根源并造成绝对的破坏。
对于解决方案,您可以使用seteuid(os.seteuid - 再一次,简单代理到C级seteuid)。关于setuid和seteuid的python文档看起来很糟糕,但是有大量关于系统调用的文档。
关于暂时掉根和恢复的安全性......你需要非常小心。如果恶意代码有机会获得root权限,那你就搞砸了。出于这个原因,分叉到子进程是一个好主意(如建议用户4815162342)。子进程将无法重新root。有关这些问题的更多信息可以在here找到。关于setuid的一般奇怪性的更多信息是here。
我们的想法是使用seteuid设置有效用户ID并生成新进程。由于exec的工作方式,有效的用户ID将被复制到新进程的已保存的uid中。由于保存的uid不再是root,因此无法将root更改回。然而,可以找到更有趣的文档here。
最相关的部分:
如果在filename指向的程序文件上设置了set-user-ID位,并且未安装基础文件系统nosuid(mount(2)的MS_NOSUID标志),并且调用进程未被ptraced ,然后将调用进程的有效用户ID更改为程序文件所有者的有效用户ID。同样,当设置程序文件的set-group-ID位时,调用进程的有效组ID被设置为程序文件的组。
将进程的有效用户ID复制到已保存的set-user-ID;类似地,有效组ID被复制到保存的集合组ID。此复制发生在由于set-user-ID和set-group-ID权限位而发生的任何有效ID更改之后。
答案 2 :(得分:3)
使用seteuid()代替设置有效ID但保留权限:
import os
os.seteuid(471)
...
os.seteuid(os.getuid())