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

守給你的承諾、 提交于 2019-12-10 15:58:08

问题


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()

回答1:


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:

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

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.



来源:https://stackoverflow.com/questions/6211599/root-priv-cant-be-dropped-in-python-even-after-seteuid-a-bug

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!