4

即使在 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()
4

1 回答 1

7

在 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 带来的任何潜在并发症。

于 2011-06-02T13:45:12.833 回答