即使在 seteuid 之后,root priv 也无法在 python 中删除。一个错误?
即使在 seteuid 之后,root priv 也不能在 python 中删除。一个错误?
编辑 摘要:我忘了删除 gid。不过,接受的答案可能会对您有所帮助。
你好。我无法在 Linux 上删除 python 3.2 中的 root 权限。事实上,即使在 seteuid(1000) 之后,它也可以读取 root 拥有的 400 模式文件。 euid肯定设置为1000!
我发现在空 os.fork() 调用后,特权访问被正确拒绝。 (不过只是在父进程中,子进程还是可以非法读取的。) 是python的bug,还是linux也是如此?
尝试下面的代码。注释掉底部三行之一,然后以 root 身份运行。
预先感谢。
#!/usr/bin/python3
# Python seteuid pitfall example.
# Run this __as__ the root.
# Here, access to root-owned files /etc/sudoers and /etc/group- are tried.
# Simple access to them *succeeds* even after seteuid(1000) which should fail.
# Three functions, stillRoot(), forkCase() and workAround() are defined.
# The first two seem wrong. In the last one, access fails, as desired.
# ***Comment out*** one of three lines at the bottom before execution.
# If your python is < 3.2, comment out the entire def of forkCase()
import os
def stillRoot():
"""Open succeeds, but it should fail."""
os.seteuid(1000)
open('/etc/sudoers').close()
def forkCase():
"""Child can still open it. Wow."""
# setresuid needs python 3.2
os.setresuid(1000, 1000, 0)
pid = os.fork()
if pid == 0:
# They're surely 1000, not 0!
print('uid: ', os.getuid(), 'euid: ', os.geteuid())
open('/etc/sudoers').close()
print('open succeeded in child.')
exit()
else:
print('child pid: ', pid)
open('/etc/group-').close()
print('parent succeeded to open.')
def workAround():
"""So, a dummy fork after seteuid is necessary?"""
os.seteuid(1000)
pid = os.fork()
if pid == 0:
exit(0)
else:
os.wait()
open('/etc/group-').close()
## Run one of them.
# stillRoot()
# forkCase()
# workAround()
Root priv can't be dropped in python even after seteuid. A bug?
EDIT Summary: I forgot to drop gid. The accepted answer may help you, though.
Hi. I can't drop the root privilege in python 3.2 on my linux. In fact, even after seteuid(1000), it can read root-owned 400-mode files. The euid is surely set to 1000!
I found after empty os.fork() call, the privileged access is correctly denied. (But it's only in the parent. The child can still read illegitimately.) Is it a bug in python, or is linux so?
Try the code below. Comment out one of the three lines at the bottom, and run as root.
Thanks beforehand.
#!/usr/bin/python3
# Python seteuid pitfall example.
# Run this __as__ the root.
# Here, access to root-owned files /etc/sudoers and /etc/group- are tried.
# Simple access to them *succeeds* even after seteuid(1000) which should fail.
# Three functions, stillRoot(), forkCase() and workAround() are defined.
# The first two seem wrong. In the last one, access fails, as desired.
# ***Comment out*** one of three lines at the bottom before execution.
# If your python is < 3.2, comment out the entire def of forkCase()
import os
def stillRoot():
"""Open succeeds, but it should fail."""
os.seteuid(1000)
open('/etc/sudoers').close()
def forkCase():
"""Child can still open it. Wow."""
# setresuid needs python 3.2
os.setresuid(1000, 1000, 0)
pid = os.fork()
if pid == 0:
# They're surely 1000, not 0!
print('uid: ', os.getuid(), 'euid: ', os.geteuid())
open('/etc/sudoers').close()
print('open succeeded in child.')
exit()
else:
print('child pid: ', pid)
open('/etc/group-').close()
print('parent succeeded to open.')
def workAround():
"""So, a dummy fork after seteuid is necessary?"""
os.seteuid(1000)
pid = os.fork()
if pid == 0:
exit(0)
else:
os.wait()
open('/etc/group-').close()
## Run one of them.
# stillRoot()
# forkCase()
# workAround()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在 Unix 系统上操作进程凭据是很棘手的。我强烈建议彻底了解真实用户 ID、有效用户 ID 和保存集用户 ID 之间的相互关系。 “放弃特权”很容易搞砸。
至于你的具体观察......我想知道是否有一个你可能忽略的简单原因。您的代码正在执行不一致的测试,并且您忽略了在
/etc/sudoers
和/etc/group-
文件上指定确切的文件权限。如果 /etc/sudoers 具有权限 mode=440、uid=root、gid=root (这是我系统上的默认权限)并且如果/etc/group-
的模式=400。您没有修改进程的 GID,因此如果
/etc/sudoers
是组可读的,那就可以解释为什么它总是可读的。fork()
不会修改进程凭据。但是,由于您正在检查父级和子级中的不同文件,因此在示例代码中可能会出现这种情况。如果/etc/group-
没有组读取权限,而/etc/sudoers
则具有组读取权限,这可以解释明显的问题。如果您想要做的只是“放弃权限”,请使用以下代码:
一般来说,如果您的进程需要在进程的生命周期内打开和关闭其 root 权限,那么您只想操作有效用户 ID。过程。如果您只需要使用 root 权限执行一些设置操作,但在这些设置操作完成后不再需要它们,只需使用上面的代码不可撤销地删除它们。
哦,在 Linux 上进行进程凭证操作的一个有用的调试实用程序是打印
/proc/self/status
的输出,该文件的 Uid 和 Gid 行显示真实的、有效的、已保存的设置,以及当前进程持有的文件 ID(按顺序)。 Python API 可用于检索相同的信息,但您可以将此文件的内容视为“真实数据”,并避免 Python 跨平台 API 带来的任何潜在复杂性。Manipulating process credentials on Unix systems is tricky. I highly recommend gaining a thorough understanding of how the Real, Effective, and Saved-Set user ids are interrelated. It's very easy to screw up "dropping privileges".
As to your specific observations... I'm wondering if there's a simple cause you may have overlooked. Your code is preforming a inconsistent tests and you've neglected to specify the exact file permissions on your
/etc/sudoers
and/etc/group-
files. Your could would be expected to behave exactly as you describe if/etc/sudoers
has permissions mode=440, uid=root, gid=root (which are the default permissions on my system) and if/etc/group-
has mode=400.You're not modifying the process's GID so if
/etc/sudoers
is group-readable, that would explain why it's always readable.fork()
does not modify process credentials. However, it could appear to do so in your example code since you're checking different files in the parent and child. If/etc/group-
does not have group read permissions where/etc/sudoers
does, that would explain the apparent problem.If all you're trying to do is "drop privileges", use the following code:
Generally speaking, you'll only want to manipulate the effective user id if your process needs to toggle it's root permissions on and off over the life of the process. If you just need to do some setup operations with root permissions but will no longer require them after those setup operations are complete, just use the code above to irrevokably drop them.
Oh, and a useful debugging utility for process credential manipulation on Linux is to print the output of
/proc/self/status
, the Uid and Gid lines of this file display the real, effective, saved-set, and file ids held by the current process (in that order). The Python APIs can be used to retrieve the same information but you can consider the contents of this file as "truth data" and avoid any potential complications from Python's cross-platform APIs.