即使在 seteuid 之后,也不能在 python 中删除 root priv.一个错误? [英] Root priv can't be dropped in python even after seteuid. A bug?

查看:66
本文介绍了即使在 seteuid 之后,也不能在 python 中删除 root priv.一个错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

即使在 seteuid 之后,也不能在 python 中删除 root priv.一个错误?

Root priv can't be dropped in python even after seteuid. A bug?

编辑 总结:我忘了放下 gid.不过,接受的答案可能会对您有所帮助.

EDIT Summary: I forgot to drop gid. The accepted answer may help you, though.

嗨.我无法在我的 linux 上删除 python 3.2 中的 root 权限.事实上,即使在 seteuid(1000) 之后,它也可以读取 root 拥有的 400 模式文件.euid 肯定设置为 1000!

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!

我发现在空 os.fork() 调用后,特权访问被正确拒绝.(但仅限于父级,子级仍然可以非法阅读.)是python中的错误,还是linux中的错误?

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?

试试下面的代码.注释掉底部的三行之一,并以 root 身份运行.

Try the code below. Comment out one of the three lines at the bottom, and run as 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()

推荐答案

在 Unix 系统上操作进程凭据很棘手.我强烈建议您彻底了解真实、有效和保存的用户 ID 如何相互关联.很容易搞砸放弃特权".

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".

至于您的具体观察...我想知道您是否忽略了一个简单的原因.您的代码正在执行不一致的测试,并且您忽略了对 /etc/sudoers/etc/group- 文件指定确切的文件权限.如果 /etc/sudoers 具有权限 mode=440、uid=root、gid=root(这是我系统上的默认权限)并且 /etc/group- 的 mode=400.

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.

您没有修改进程的 GID,所以如果 /etc/sudoers 是组可读的,这将解释为什么它总是可读的.fork() 不会修改进程凭据.但是,在您的示例代码中似乎是这样做的,因为您正在检查父级和子级中的不同文件.如果 /etc/group- 没有 /etc/sudoers 有的组读取权限,那就可以解释明显的问题.

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:

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

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

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.

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

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.

这篇关于即使在 seteuid 之后,也不能在 python 中删除 root priv.一个错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆