Skip to content
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

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

Open
socketpair opened this issue Dec 10, 2022 · 1 comment
Open
Labels
stdlib Python modules in the Lib dir 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

@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
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 type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

2 participants