10000 subprocess.call(..., user=xx, group=xxx) is not able to gain privileges · Issue #100163 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

subprocess.call(..., user=xx, group=xxx) is not able to gain privileges #100163

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
socketpair opened this issue Dec 10, 2022 · 4 comments
Open
Labels
stdlib Python modules in the Lib dir topic-subprocess Subprocess issues. type-bug An unexpected behavior, bug, or error

Comments

@socketpair
Copy link
Contributor
socketpair commented Dec 10, 2022
#!/usr/bin/python3

from os import getresuid, initgroups, setresgid, setresuid
from pwd import getpwnam
from subprocess import check_call


def drop_permissions():
    user = 'nobody'
    info = getpwnam(user)
    uid = info.pw_uid
    gid = info.pw_gid

    assert uid
    assert gid

    initgroups(user, gid)
    setresgid(gid, gid, gid)
    setresuid(uid, uid, 0)


def run_privileged_proc():
    def restore():
        setresuid(0, 0, 0)
        setresgid(0, 0, 0)
        initgroups('root', 0)

    check_call(['id'], preexec_fn=restore)


def main():
    assert getresuid() == (0, 0, 0)
    # This on works (dropping permissions in child process)
    check_call(['id'], user=65534, group=65534)
    drop_permissions()

    # This one works:
    run_privileged_proc()

    # This does not:
    check_call(['id'], user=0, group=0)


main()

for the last subprocess, strace of child process:

set_robust_list(0x7eff7bfaea20, 24)     = 0
close(7)                                = 0
close(9)                                = 0
close(11)                               = 0
dup2(6, 0)                              = 0
dup2(8, 1)                              = 1
dup2(10, 2)                             = 2
rt_sigaction(SIGPIPE, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK, sa_restorer=0x7eff7b83ea30}, {sa
rt_sigaction(SIGXFSZ, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK, sa_restorer=0x7eff7b83ea30}, {sa
setgroups(0, [])                        = -1 EPERM (Операция не позволена)
write(12, "OSError:", 8)                = 8
write(12, "1", 1)                       = 1
write(12, ":", 1)                       = 1
write(12, "noexec", 6)                  = 6
exit_group(255)                         = ?
+++ exited with 255 +++

Python 3.10.7

Linked PRs

@socketpair socketpair added the type-bug An unexpected behavior, bug, or error label Dec 10, 2022
@socketpair
Copy link
Contributor Author
socketpair commented Dec 10, 2022

Why?

Because sequences to up and down privileges are DIFFERENT (reversed order of functions call).

To down privileges (this logic is hard-coded in Python now):

# have to find username by uid or....
# we definitely have to drop supplementary groups. either to empty list or new user's groups
initgroups(username, gid) 
setresgid(gid, gid, gid)
setresuid(uid, uid, uid)

To up:

setresuid(0, 0, 0)
setresgid(0, 0, 0)
initgroups('root', 0)  # or, replace with os.setgroups([])

I think, Python should detect what caller wants (up or down) and chose the correct sequence.

Possibly add as_superuser: bool = False (I don't like adding one more kwarg to subprocess)

@iritkatriel iritkatriel added the stdlib Python modules in the Lib dir label Nov 24, 2023
@vstinner vstinner added the topic-subprocess Subprocess issues. label Jul 8, 2024
@duaneg
Copy link
Contributor
duaneg commented May 20, 2025

Because sequences to up and down privileges are DIFFERENT (reversed order of functions call).

That is true, but is not the only issue...

The _posixsubprocess.c code uses setreuid not setresuid, so even if we switch around the order when switching to uid 0 and make the setreuid call first it will still fail. To make this work we would have to change the code to using setresuid/setresgid instead of setreuid/setregid as well as changing the uid first when switching from an unprivileged user to root.

I have a WIP patch which does all that but I'm not completely confident this won't have any unintended side-effects, won't change behaviour of any existing working code, and is worth the extra complexity/risk. If the maintainers (CC @giampaolo and @gpshead) think it might be worth doing I'll polish it off and push it out for consideration. If not this should probably be closed as "not planned": anyone needing to drop and then reacquire perms can always do it manually, e.g. by using preexec_fn as in the OP's example.

@gpshead
Copy link
Member
gpshead commented May 20, 2025

Yeah, preexec_fn= is a workaround... that we don't want but do not have a nice way to get rid of despite its footgun reliabiity/deadlock problems.

@duaneg - Could you make a Draft PR for what you were thinking at least for reference here even before anything has been decided?

@duaneg
Copy link
Contributor
duaneg commented May 21, 2025

Right, that workaround does seem inherently unsafe. I've polished up the change and will push it out shortly. Unfortunately I don't think it is practical to unit test, as it requires root privileges.

duaneg added a commit to duaneg/cpython that referenced this issue May 21, 2025
This is a preparatory refactoring which should have no semantic effect in
itself but will hopefully make the real changes coming in subsequent patches
easier to review.
duaneg added a commit to duaneg/cpython that referenced this issue May 21, 2025
Setting the saved user/group-ID allows the code to re-assume privileges after
dropping them.
duaneg added a commit to duaneg/cpython that referenced this issue May 21, 2025
When dropping privileges we need to set the new effective UID last, so we have
permission to change the gid/groups. When re-assuming root privileges we need
to do the opposite: set the UID first so we then have permission to change
gid/groups.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stdlib Python modules in the Lib dir topic-subprocess Subprocess issues. type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

5 participants
0