Root priv не может быть удалено в python даже после seteuid. Жук? - PullRequest
4 голосов
/ 02 июня 2011

Root priv не может быть удалено в python даже после seteuid.Ошибка?

РЕДАКТИРОВАТЬ Резюме: Я забыл сбросить GID.Однако принятый ответ может вам помочь.

Привет.Я не могу отбросить привилегию root в python 3.2 на моем linux.На самом деле, даже после seteuid (1000), он может читать файлы в 400-режиме, принадлежащие пользователю root.Для 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()

1 Ответ

6 голосов
/ 02 июня 2011

Управлять учетными данными процесса в системах Unix сложно.Я высоко рекомендую получить полное понимание того, как реальные, эффективные и сохраненные пользовательские идентификаторы взаимосвязаны.Очень легко испортить «отбрасывание привилегий».

Что касается ваших конкретных наблюдений ... Мне интересно, есть ли простая причина, которую вы, возможно, упустили из виду.Ваш код выполняет противоречивые тесты, и вы не указали точные права доступа к файлам /etc/sudoers и /etc/group-.Вы могли бы ожидать, что вы будете вести себя точно так же, как вы описали, если /etc/sudoers имеет режим полномочий = 440, uid = root, gid = root (которые являются разрешениями по умолчанию для моей системы) и если /etc/group- имеет mode = 400.

Вы не изменяете GID процесса, поэтому, если /etc/sudoers доступен для чтения в группе, это объясняет, почему он всегда читаемый.fork() не изменяет учетные данные процесса.Однако в вашем примере кода это может выглядеть так, поскольку вы проверяете разные файлы в родительском и дочернем элементах.Если /etc/group- не имеет разрешения на групповое чтение, а /etc/sudoers - это объясняет очевидную проблему.

Если все, что вы пытаетесь сделать, это «удалить привилегии», используйте следующий код:

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

Вообще говоря, вы можете манипулировать эффективным идентификатором пользователя только в том случае, если вашему процессу необходимо включать и выключать свои корневые права в течение срока его службы.Если вам просто нужно выполнить некоторые операции установки с правами суперпользователя, но они вам больше не понадобятся после завершения этих операций установки, просто используйте приведенный выше код, чтобы безвозвратно удалить их.

О, и полезной утилитой отладки для манипулирования учетными данными процессов в Linux является вывод выходных данных /proc/self/status, строки Uid и Gid этого файла отображают реальные, эффективные, сохраненные наборы и идентификаторы файлов.удерживается текущим процессом (в таком порядке).API-интерфейсы Python могут использоваться для извлечения той же информации, но вы можете рассматривать содержимое этого файла как «данные об истинности» и избегать любых возможных осложнений из-за кросс-платформенных API-интерфейсов Python.

...