即使在seteuid之后,也不能在python中删除root priv。一个bug?

时间:2011-06-02 07:17:10

标签: python privilege

即使在seteuid之后,也无法在python中删除root priv。一个错误?

编辑摘要:我忘了放弃gid。但是,接受的答案可能对你有所帮助。

您好。我不能在我的linux上删除python 3.2中的root权限。实际上,即使在seteuid(1000)之后,它也可以读取root拥有的400模式文件。 euid肯定会设置为1000!

我在空的os.fork()调用后发现,正确拒绝了特权访问。 (但它只在父母身上。孩子仍然可以非法阅读。)这是python中的错误,还是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()

1 个答案:

答案 0 :(得分:6)

在Unix系统上操作进程凭据非常棘手。我高度建议全面了解Real,Effective和Saved-set用户ID是如何相互关联的。搞砸“权限”非常容易。

至于你的具体观察......我想知道是否有一个你可能忽略的简单原因。您的代码正在执行不一致的测试,并且您忽略了在/etc/sudoers/etc/group-文件上指定确切的文件权限。如果/etc/sudoers具有权限模式= 440,uid = root,gid = root(这是我系统的默认权限),并且/etc/group-具有模式=,则可以预期您的行为与您描述的完全相同400。

你没有修改进程的GID,所以如果/etc/sudoers是组可读的,那就可以解释为什么它总是可读的。 fork()不会修改进程凭据。但是,您可能会在示例代码中执行此操作,因为您正在检查父级和子级中的不同文件。如果/etc/group-没有/etc/sudoers所在的群组阅读权限,则可以解释明显的问题。

如果您要做的只是“删除权限”,请使用以下代码:

os.setgid( NEW_GID )
os.setuid( NEW_UID )

一般来说,如果您的流程需要在流程的整个生命周期内打开和关闭其root权限,那么您只需要操纵有效的用户ID。如果您只需要使用root权限进行一些设置操作,但在完成这些设置操作后将不再需要它们,只需使用上面的代码就可以不可撤销地删除它们。

哦,Linux上用于进程凭据操作的有用调试实用程序是打印/proc/self/status的输出,此文件的Uid和Gid行显示真实,有效,已保存集和文件ID按当前流程(按此顺序)。 Python API可用于检索相同的信息,但您可以将此文件的内容视为“真实数据”,并避免Python跨平台API的任何潜在复杂情况。