4 Stimmen

Die Root-Berechtigung kann auch nach dem Setzen von seteuid in Python nicht verworfen werden. Ein Bug?

Root-Privilegien können in Python auch nach Setzen von seteuid nicht fallen gelassen werden. Ein Bug?

BEARBEITEN Zusammenfassung: Ich habe vergessen, die gid abzulegen. Die akzeptierte Antwort könnte Ihnen dennoch helfen.

Hallo. Ich kann in Python 3.2 auf meinem Linux die Root-Berechtigung nicht ablegen. Tatsächlich kann es selbst nach seteuid(1000) root-eigene Dateien mit 400-Berechtigungen lesen. Die euid ist definitiv auf 1000 gesetzt!

Ich habe herausgefunden, dass der privilegierte Zugriff nach einem leeren os.fork() -Aufruf korrekt verweigert wird. (Aber das passiert nur im Elternprozess. Das Kind kann immer noch ungerechtmäßig lesen.) Ist das ein Bug in Python oder liegt es an Linux?

Probieren Sie den untenstehenden Code aus. Kommentieren Sie eine der drei Zeilen am Ende aus und führen Sie ihn als Root aus.

Vorab vielen Dank.

#!/usr/bin/python3

# Beispiel für ein Problem mit Python seteuid.
# Führen Sie dies als den Root aus.

# Hier wird versucht, auf root-eigene Dateien /etc/sudoers und /etc/group zuzugreifen.
# Einfacher Zugriff auf sie *gelingt* auch nach seteuid(1000), was fehlschlagen sollte.

# Drei Funktionen, stillRoot(), forkCase() und workAround(), sind definiert.
# Die ersten beiden scheinen falsch zu sein. In der letzten funktioniert der Zugriff wie gewünscht.

# ***Kommentieren Sie*** eine der drei Zeilen am Ende aus, bevor Sie es ausführen.

# Wenn Ihr Python < 3.2 ist, kommentieren Sie die gesamte Definition von forkCase() aus.

import os

def stillRoot():
    """Das Öffnen gelingt, obwohl es fehlschlagen sollte."""
    os.seteuid(1000)
    open('/etc/sudoers').close()

def forkCase():
    """Das Kind kann es immer noch öffnen. Wow."""
    # setresuid benötigt Python 3.2
    os.setresuid(1000, 1000, 0)
    pid = os.fork()
    if pid == 0:
        # Sie sind sicherlich 1000, nicht 0!
        print('UID: ', os.getuid(), 'EUID: ', os.geteuid())
        open('/etc/sudoers').close()
        print('Öffnen im Kind erfolgreich.')
        exit()
    else:
        print('Kind-PID: ', pid)
        open('/etc/group').close()
        print('Elternprozess konnte öffnen.')

def workAround():
    """Also, ist ein Dummy-Fork nach seteuid notwendig?"""
    os.seteuid(1000)
    pid = os.fork()
    if pid == 0:
        exit(0)
    else:
        os.wait()

    open('/etc/group').close()

## Führen Sie eine von ihnen aus.

# stillRoot()
# forkCase()
# workAround()

7voto

Rakis Punkte 7629

Die Manipulation von Prozessanmeldeinformationen auf Unix-Systemen ist knifflig. Ich empfehle dringend, ein gründliches Verständnis dafür zu erlangen, wie die Real-, Effektiv- und Gesetzt-Benutzer-IDs miteinander zusammenhängen. Es ist sehr einfach, beim "Herabsetzen von Privilegien" Fehler zu machen.

Zu Ihren spezifischen Beobachtungen... Ich frage mich, ob es eine einfache Ursache gibt, die Sie übersehen haben. Ihr Code führt inkonsistente Tests durch und Sie haben die genauen Dateiberechtigungen auf Ihren /etc/sudoers und /etc/group- Dateien nicht angegeben. Ihr Code würde sich genau so verhalten, wie Sie es beschreiben, wenn /etc/sudoers die Berechtigungen mode=440, uid=root, gid=root hat (was die Standardberechtigungen auf meinem System sind) und wenn /etc/group- mode=400 hat.

Sie ändern die GID des Prozesses nicht, daher wäre es erklärbar, warum er immer lesbar ist, wenn /etc/sudoers gruppenlesbar ist. fork() ändert keine Prozessanmeldeinformationen. Allerdings könnte es in Ihrem Beispielcode so erscheinen, da Sie unterschiedliche Dateien im Eltern- und Kindprozess überprüfen. Wenn /etc/group- keine Gruppenleseberechtigungen hat, während /etc/sudoers sie hat, würde das das scheinbare Problem erklären.

Wenn alles, was Sie versuchen, ist, "Privilegien abzusenken", verwenden Sie den folgenden Code:

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

Im Allgemeinen sollten Sie nur die effektive Benutzer-ID manipulieren, wenn Ihr Prozess während seiner Laufzeit seine Root-Berechtigungen ein- und ausschalten muss. Wenn Sie nur einige Einrichtungsvorgänge mit Root-Berechtigungen durchführen müssen, diese aber nach Abschluss dieser Vorgänge nicht mehr benötigen, verwenden Sie einfach den obigen Code, um sie unwiderruflich zu verwerfen.

Ach, und ein nützliches Debugging-Hilfsprogramm für die Manipulation von Prozessanmeldeinformationen auf Linux ist das Ausdrucken der Ausgabe von /proc/self/status, die Uid- und Gid-Zeilen dieser Datei zeigen die realen, effektiven, gesetzten und Datei-IDs, die vom aktuellen Prozess gehalten werden (in dieser Reihenfolge). Die Python-APIs können verwendet werden, um die gleichen Informationen abzurufen, aber Sie können den Inhalt dieser Datei als "Wahrheitsdaten" betrachten und mögliche Komplikationen durch die plattformübergreifenden APIs von Python vermeiden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X