PEP 446 – Neue Dateideskriptoren standardmäßig nicht vererbbar machen
- Autor:
- Victor Stinner <vstinner at python.org>
- Status:
- Final
- Typ:
- Standards Track
- Erstellt:
- 05-Aug-2013
- Python-Version:
- 3.4
- Ersetzt:
- 433
Inhaltsverzeichnis
- Zusammenfassung
- Begründung
- Vererbung von Dateideskriptoren
- Vererbung von Dateideskriptoren unter Windows
- Nur einige Handles unter Windows vererben
- Vererbung von Dateideskriptoren unter UNIX
- Probleme mit vererbbaren Dateideskriptoren
- Sicherheitslücke
- Im subprocess-Modul behobene Probleme
- Atomare Erstellung nicht vererbbarer Dateideskriptoren
- Status von Python 3.3
- Schließen aller offenen Dateideskriptoren
- Vorschlag
- Abwärtskompatibilität
- Verwandte Arbeiten
- Abgelehnte Alternativen
- Python-Probleme
- Urheberrecht
Zusammenfassung
Leckende Dateideskriptoren in Kindprozessen verursachen verschiedene ärgerliche Probleme und stellen eine bekannte, schwerwiegende Sicherheitslücke dar. Die Verwendung des Moduls subprocess mit dem Parameter close_fds auf True gesetzt, ist nicht in allen Fällen möglich.
Dieses PEP schlägt vor, alle von Python erstellten Dateideskriptoren standardmäßig nicht vererbbar zu machen, um das Risiko dieser Probleme zu reduzieren. Dieses PEP behebt auch eine Race Condition in Multithreading-Anwendungen auf Betriebssystemen, die atomare Flags zur Erstellung nicht vererbbarer Dateideskriptoren unterstützen.
Uns ist bewusst, dass dies wahrscheinlich zu Codebrüchen führen wird, und wir tun es trotzdem für das Wohl der Menschheit. (Details in der Sektion „Abwärtskompatibilität“ unten.)
Begründung
Vererbung von Dateideskriptoren
Jedes Betriebssystem behandelt die Vererbung von Dateideskriptoren unterschiedlich. Windows erstellt standardmäßig nicht vererbbare Handles, während UNIX und die POSIX-API unter Windows standardmäßig vererbbare Dateideskriptoren erstellen. Python bevorzugt die POSIX-API gegenüber der nativen Windows-API, um eine einzige Codebasis zu haben und den gleichen Typ für Dateideskriptoren zu verwenden, und erstellt daher vererbbare Dateideskriptoren.
Es gibt eine Ausnahme: os.pipe() erstellt unter Windows nicht vererbbare Pipes, während es unter UNIX vererbbare Pipes erstellt. Der Grund ist ein Implementierungsartefakt: os.pipe() ruft unter Windows CreatePipe() (native API) auf, während es unter UNIX pipe() (POSIX-API) aufruft. Der Aufruf von CreatePipe() wurde 1994 in Python hinzugefügt, vor der Einführung von pipe() in der POSIX-API unter Windows 98. Das Issue #4708 schlägt vor, os.pipe() unter Windows so zu ändern, dass es vererbbare Pipes erstellt.
Vererbung von Dateideskriptoren unter Windows
Unter Windows ist der native Typ von Datei-Objekten Handles (C-Typ HANDLE). Diese Handles haben ein Flag HANDLE_FLAG_INHERIT, das bestimmt, ob ein Handle in einem Kindprozess vererbt werden kann oder nicht. Für die POSIX-API stellt die C-Laufzeitbibliothek (CRT) auch Dateideskriptoren bereit (C-Typ int). Das Handle eines Dateideskriptors kann mit der Funktion _get_osfhandle(fd) abgerufen werden. Ein Dateideskriptor kann mit der Funktion _open_osfhandle(handle) aus einem Handle erstellt werden.
Bei Verwendung von CreateProcess() werden Handles nur vererbt, wenn ihr Vererbungsflag (HANDLE_FLAG_INHERIT) gesetzt ist und der Parameter bInheritHandles von CreateProcess() auf TRUE gesetzt ist; alle Dateideskriptoren außer den Standard-Streams (0, 1, 2) werden im Kindprozess geschlossen, auch wenn bInheritHandles auf TRUE gesetzt ist. Bei Verwendung der Funktion spawnv() werden alle vererbbaren Handles und alle vererbbaren Dateideskriptoren im Kindprozess vererbt. Diese Funktion verwendet die undokumentierten Felder cbReserved2 und lpReserved2 der STARTUPINFO-Struktur, um ein Array von Dateideskriptoren zu übergeben.
Um Standard-Streams (stdin, stdout, stderr) mit CreateProcess() zu ersetzen, muss das Flag STARTF_USESTDHANDLES im Feld dwFlags der STARTUPINFO-Struktur gesetzt sein und der Parameter bInheritHandles von CreateProcess() muss auf TRUE gesetzt sein. Wenn also mindestens ein Standard-Stream ersetzt wird, werden alle vererbbaren Handles vom Kindprozess geerbt.
Der Standardwert des Parameters close_fds des subprocess-Prozesses ist True (bInheritHandles=FALSE), wenn die Parameter stdin, stdout und stderr None sind, andernfalls False (bInheritHandles=TRUE).
Siehe auch
Nur einige Handles unter Windows vererben
Seit Windows Vista unterstützt CreateProcess() eine Erweiterung der STARTUPINFO-Struktur: die STARTUPINFOEX Struktur. Mit dieser neuen Struktur ist es möglich, eine Liste der zu vererbenden Handles anzugeben: PROC_THREAD_ATTRIBUTE_HANDLE_LIST. Lesen Sie Programmatische Steuerung, welche Handles von neuen Prozessen in Win32 vererbt werden (Raymond Chen, Dez 2011) für weitere Informationen.
Vor Windows Vista ist es möglich, Handles vererbbar zu machen und CreateProcess() mit bInheritHandles=TRUE aufzurufen. Diese Option funktioniert, wenn alle anderen Handles nicht vererbbar sind. Es gibt eine Race Condition: Wenn ein anderer Thread CreateProcess() mit bInheritHandles=TRUE aufruft, werden Handles auch im zweiten Prozess vererbt.
Microsoft schlägt vor, eine Sperre zu verwenden, um die Race Condition zu vermeiden: Lesen Sie Q315939: PRB: Kind erbt unbeabsichtigte Handles während CreateProcess Aufruf (letzte Überprüfung: November 2006). Das Python Issue #16500 „Fügen Sie ein atfork-Modul hinzu“ schlägt vor, eine solche Sperre hinzuzufügen, sie kann verwendet werden, um Handles ohne Race Condition nicht vererbbar zu machen. Eine solche Sperre schützt nur vor einer Race Condition zwischen Python-Threads; C-Threads sind nicht geschützt.
Eine weitere Option ist das Duplizieren von Handles, die vererbt werden müssen, und das Übergeben der Werte der duplizierten Handles an den Kindprozess, damit der Kindprozess duplizierte Handles mit DuplicateHandle() mit DUPLICATE_CLOSE_SOURCE stehlen kann. Handle-Werte ändern sich zwischen dem Eltern- und dem Kindprozess, da die Handles dupliziert werden (zweimal); der Eltern- und/oder der Kindprozess müssen angepasst werden, um diese Änderung zu handhaben. Wenn das Kindprogramm nicht geändert werden kann, kann ein Zwischenprogramm verwendet werden, um Handles vom Elternprozess zu stehlen, bevor das endgültige Kindprogramm gestartet wird. Das Zwischenprogramm muss das Handle vom Kindprozess an den Elternprozess übergeben. Der Elternprozess muss möglicherweise duplizierte Handles schließen, wenn nicht alle Handles gestohlen wurden, z. B. wenn das Zwischenprogramm fehlschlägt. Wenn die Befehlszeile verwendet wird, um die Handle-Werte zu übergeben, muss die Befehlszeile geändert werden, wenn Handles dupliziert werden, da sich deren Werte ändern.
Dieses PEP enthält keine Lösung für dieses Problem, da es keine perfekte Lösung gibt, die auf allen Windows-Versionen funktioniert. Dieser Punkt wird aufgeschoben, bis Anwendungsfälle, die auf der Vererbung von Handles oder Dateideskriptoren unter Windows basieren, bekannt sind, damit wir die beste Lösung auswählen und ihre Implementierung sorgfältig testen können.
Vererbung von Dateideskriptoren unter UNIX
POSIX stellt ein close-on-exec Flag für Dateideskriptoren bereit, um einen Dateideskriptor automatisch zu schließen, wenn die C-Funktion execv() aufgerufen wird. Dateideskriptoren mit dem close-on-exec Flag gelöscht werden im Kindprozess vererbt, Dateideskriptoren mit dem gesetzten Flag werden im Kindprozess geschlossen.
Das Flag kann in zwei Systemaufrufen (einer zum Abrufen der aktuellen Flags, ein zweiter zum Setzen der neuen Flags) mit fcntl() gesetzt werden.
int flags, res;
flags = fcntl(fd, F_GETFD);
if (flags == -1) { /* handle the error */ }
flags |= FD_CLOEXEC;
/* or "flags &= ~FD_CLOEXEC;" to clear the flag */
res = fcntl(fd, F_SETFD, flags);
if (res == -1) { /* handle the error */ }
FreeBSD, Linux, Mac OS X, NetBSD, OpenBSD und QNX unterstützen auch das Setzen des Flags in einem einzigen Systemaufruf mittels ioctl()
int res;
res = ioctl(fd, FIOCLEX, 0);
if (!res) { /* handle the error */ }
HINWEIS: Das close-on-exec Flag hat keine Auswirkung auf fork(): Alle Dateideskriptoren werden vom Kindprozess geerbt. Das Python Issue #16500 „Fügen Sie ein atfork-Modul hinzu“ schlägt vor, ein neues atfork-Modul hinzuzufügen, um Code beim Fork auszuführen, was zum automatischen Schließen von Dateideskriptoren verwendet werden kann.
Probleme mit vererbbaren Dateideskriptoren
In den meisten Fällen werden vererbbare Dateideskriptoren, die an Kindprozesse „geleakt“ werden, nicht bemerkt, da sie keine größeren Fehler verursachen. Das bedeutet nicht, dass diese Fehler nicht behoben werden dürfen.
Zwei gängige Probleme mit geerbten Dateideskriptoren
- Unter Windows kann ein Verzeichnis nicht gelöscht werden, bevor alle in dem Verzeichnis geöffneten Dateihandles geschlossen sind. Das gleiche Problem kann bei Dateien auftreten, es sei denn, die Datei wurde mit dem Flag
FILE_SHARE_DELETE(O_TEMPORARYModus füropen()) erstellt. - Wenn ein lauschender Socket an einen Kindprozess weitergegeben wird, kann die Socket-Adresse erst wiederverwendet werden, wenn der Eltern- und der Kindprozess beendet sind. Zum Beispiel, wenn ein Webserver ein neues Programm zur Bearbeitung eines Prozesses startet und der Server neu startet, während das Programm noch nicht fertig ist, kann der Server nicht starten, da der TCP-Port noch in Verwendung ist.
Beispiele für Probleme in Open-Source-Projekten
- Mozilla (Firefox): Offen seit 2002-05
- dbus-Bibliothek: behoben in 2008-05 (dbus Commit), schließt Dateideskriptoren im Kindprozess
- autofs: behoben in 2009-02, setzt das CLOEXEC-Flag
- qemu: behoben in 2009-12 (qemu Commit), setzt das CLOEXEC-Flag
- Tor: behoben in 2010-12, setzt das CLOEXEC-Flag
- OCaml: Offen seit 2011-04, „PR#5256: Prozesse, die über Unix.open_process* geöffnet werden, erben alle geöffneten Dateideskriptoren (einschließlich Sockets)“
- ØMQ: Offen seit 2012-08
- Squid: Offen seit 2012-07
Siehe auch: Entschuldigen Sie, Sohn, aber Ihr Code leckt !!! (Dan Walsh, März 2012) für SELinux-Probleme mit geleckten Dateideskriptoren.
Sicherheitslücke
Das Lecken sensibler Dateihandles und Dateideskriptoren kann zu Sicherheitslücken führen. Ein nicht vertrauenswürdiger Kindprozess könnte sensible Daten wie Passwörter lesen oder die Kontrolle über den Elternprozess durch einen geleckten Dateideskriptor übernehmen. Mit einem geleckten lauschenden Socket kann ein Kindprozess neue Verbindungen annehmen, um sensible Daten zu lesen.
Beispiele für Lücken
- Übernahme von Apache https durch mod_php (2003)
- Apache: Apr sollte FD_CLOEXEC setzen, wenn APR_FOPEN_NOCLEANUP nicht gesetzt ist: behoben in 2009
- PHP: system() (und ähnliche) bereinigen nicht die geöffneten Handles von Apache: offen seit 2006
- CWE-403: Offenlegung von Dateideskriptoren für unbeabsichtigte Kontrollsphären (2008)
- OpenSSH Sicherheitsberatung: portable-keysign-rand-helper.adv (2011)
Lesen Sie auch die CERT Secure Coding Standards: FIO42-C. Stellen Sie sicher, dass Dateien ordnungsgemäß geschlossen werden, wenn sie nicht mehr benötigt werden.
Im subprocess-Modul behobene Probleme
Geerbte Dateideskriptoren verursachten 4 Probleme im Modul subprocess
- Issue #2320: Race Condition im subprocess mit stdin (eröffnet in 2008)
- Issue #3006: subprocess.Popen lässt Socket nach dem Schließen offen (eröffnet in 2008)
- Issue #7213: subprocess leckt offene Dateideskriptoren zwischen Popen-Instanzen, was zu Hängen führt (eröffnet in 2009)
- Issue #12786: subprocess wait() hängt, wenn stdin geschlossen ist (eröffnet in 2011)
Diese Probleme wurden in Python 3.2 durch 4 verschiedene Änderungen im Modul subprocess behoben.
- Pipes sind jetzt nicht vererbbar;
- Der Standardwert des Parameters close_fds ist jetzt
True, mit einer Ausnahme unter Windows: Der Standardwert istFalse, wenn mindestens ein Standard-Stream ersetzt wird; - Ein neuer Parameter pass_fds wurde hinzugefügt;
- Erstellung eines in C implementierten Moduls
_posixsubprocess.
Atomare Erstellung nicht vererbbarer Dateideskriptoren
In einer Multithreading-Anwendung kann ein vererbbarer Dateideskriptor kurz vor dem Start eines neuen Programms erstellt werden, bevor der Dateideskriptor nicht vererbbar gemacht wird. In diesem Fall wird der Dateideskriptor an den Kindprozess geleakt. Diese Race Condition könnte vermieden werden, wenn der Dateideskriptor direkt nicht vererbbar erstellt würde.
FreeBSD, Linux, Mac OS X, Windows und viele andere Betriebssysteme unterstützen die atomare Erstellung nicht vererbbarer Dateideskriptoren mit gesetztem Vererbungsflag.
Ein neues Flag WSA_FLAG_NO_HANDLE_INHERIT für WSASocket() wurde in Windows 7 SP1 und Windows Server 2008 R2 SP1 hinzugefügt, um nicht vererbbare Sockets zu erstellen. Wenn dieses Flag auf einer älteren Windows-Version (z. B. Windows XP SP3) verwendet wird, schlägt WSASocket() mit WSAEPROTOTYPE fehl.
Unter UNIX wurden neue Flags für Dateien und Sockets hinzugefügt.
O_CLOEXEC: Verfügbar unter Linux (2.6.23), FreeBSD (8.3), Mac OS 10.8, OpenBSD 5.0, Solaris 11, QNX, BeOS, nächste NetBSD-Veröffentlichung (6.1?). Dieses Flag ist Teil von POSIX.1-2008.SOCK_CLOEXECFlag fürsocket()undsocketpair(), verfügbar unter Linux 2.6.27, OpenBSD 5.2, NetBSD 6.0.fcntl():F_DUPFD_CLOEXECFlag, verfügbar unter Linux 2.6.24, OpenBSD 5.0, FreeBSD 9.1, NetBSD 6.0, Solaris 11. Dieses Flag ist Teil von POSIX.1-2008.fcntl():F_DUP2FD_CLOEXECFlag, verfügbar unter FreeBSD 9.1 und Solaris 11.recvmsg():MSG_CMSG_CLOEXEC, verfügbar unter Linux 2.6.23, NetBSD 6.0.
Unter Linux älter als 2.6.23 wird das Flag O_CLOEXEC einfach ignoriert. Daher muss fcntl() aufgerufen werden, um zu prüfen, ob der Dateideskriptor nicht vererbbar ist: O_CLOEXEC wird nicht unterstützt, wenn das Flag FD_CLOEXEC fehlt. Unter Linux älter als 2.6.27 schlagen socket() oder socketpair() mit errno auf EINVAL gesetzt fehl, wenn das Flag SOCK_CLOEXEC im Socket-Typ gesetzt ist.
Neue Funktionen
dup3(): verfügbar unter Linux 2.6.27 (und glibc 2.9)pipe2(): verfügbar unter Linux 2.6.27 (und glibc 2.9)accept4(): verfügbar unter Linux 2.6.28 (und glibc 2.10)
Unter Linux älter als 2.6.28 schlägt accept4() mit errno auf ENOSYS gesetzt fehl.
Zusammenfassung
| Betriebssystem | Atomare Datei | Atomarer Socket |
|---|---|---|
| FreeBSD | 8.3 (2012) | X |
| Linux | 2.6.23 (2007) | 2.6.27 (2008) |
| Mac OS X | 10.8 (2012) | X |
| NetBSD | 6.1 (?) | 6.0 (2012) |
| OpenBSD | 5.0 (2011) | 5.2 (2012) |
| Solaris | 11 (2011) | X |
| Windows | XP (2001) | Seven SP1 (2011), 2008 R2 SP1 (2011) |
Legende
- „Atomare Datei“: erste Version des Betriebssystems, die die atomare Erstellung eines nicht vererbbaren Dateideskriptors mittels
open()unterstützt - „Atomarer Socket“: erste Version des Betriebssystems, die die atomare Erstellung eines nicht vererbbaren Sockets unterstützt
- „X“: noch nicht unterstützt
Siehe auch
- Sichere Dateideskriptor-Behandlung (Ulrich Drepper, 2008)
- Geister der Unix-Vergangenheit, Teil 2: Vermischte Designs (Neil Brown, 2010) erklärt die Geschichte der Flags
O_CLOEXECundO_NONBLOCK - Änderungen an der Dateideskriptor-Behandlung in 2.6.27
- FreeBSD: Atomare Close-on-Exec
Status von Python 3.3
Python 3.3 erstellt auf allen Plattformen vererbbare Dateideskriptoren, mit Ausnahme von os.pipe(), das unter Windows nicht vererbbare Dateideskriptoren erstellt.
Neue Konstanten und Funktionen im Zusammenhang mit der atomaren Erstellung nicht vererbbarer Dateideskriptoren wurden in Python 3.3 hinzugefügt: os.O_CLOEXEC, os.pipe2() und socket.SOCK_CLOEXEC.
Unter UNIX schließt das Modul subprocess standardmäßig alle Dateideskriptoren im Kindprozess, außer den Standard-Streams (0, 1, 2) und den Dateideskriptoren des Parameters pass_fds. Wenn der Parameter close_fds auf False gesetzt ist, werden alle vererbbaren Dateideskriptoren im Kindprozess vererbt.
Unter Windows schließt das Modul subprocess standardmäßig alle Handles und Dateideskriptoren im Kindprozess. Wenn mindestens ein Standard-Stream (stdin, stdout oder stderr) ersetzt wird (z. B. in eine Pipe umgeleitet), werden alle vererbbaren Handles und die Dateideskriptoren 0, 1 und 2 im Kindprozess vererbt.
Bei Verwendung der Funktionen der Familien os.execv*() und os.spawn*() werden alle vererbbaren Handles und alle vererbbaren Dateideskriptoren vom Kindprozess geerbt.
Unter UNIX verwendet das Modul multiprocessing os.fork(), sodass alle Dateideskriptoren von Kindprozessen geerbt werden.
Unter Windows werden alle vererbbaren Handles und die Dateideskriptoren 0, 1 und 2 vom Kindprozess über das Modul multiprocessing geerbt, alle Dateideskriptoren außer den Standard-Streams werden geschlossen.
Zusammenfassung
| Modul | FD unter UNIX | Handles unter Windows | FD unter Windows |
|---|---|---|---|
| subprocess, Standard | STD, pass_fds | keine | STD |
| subprocess, stdout ersetzen | STD, pass_fds | alle | STD |
| subprocess, close_fds=False | alle | alle | STD |
| multiprocessing | nicht anwendbar | alle | STD |
| os.execv(), os.spawn() | alle | alle | alle |
Legende
- „alle“: alle vererbbaren Dateideskriptoren oder Handles werden im Kindprozess vererbt
- „keine“: alle Handles werden im Kindprozess geschlossen
- „STD“: nur Dateideskriptoren 0 (stdin), 1 (stdout) und 2 (stderr) werden im Kindprozess vererbt
- „pass_fds“: Dateideskriptoren des Parameters pass_fds des subprocess werden vererbt
- „nicht anwendbar“: unter UNIX verwendet das multiprocessing
fork(), daher ist dieser Fall von diesem PEP nicht betroffen.
Schließen aller offenen Dateideskriptoren
Unter UNIX schließt das Modul subprocess fast alle Dateideskriptoren im Kindprozess. Diese Operation erfordert MAXFD Systemaufrufe, wobei MAXFD die maximale Anzahl von Dateideskriptoren ist, auch wenn nur wenige Dateideskriptoren geöffnet sind. Dieses Maximum kann gelesen werden mit: os.sysconf("SC_OPEN_MAX").
Die Operation kann langsam sein, wenn MAXFD groß ist. Zum Beispiel dauerte die Operation auf einem FreeBSD Buildbot mit MAXFD=655.000 300 ms: siehe Issue #11284: langsame Schließung von Dateideskriptoren.
Unter Linux ruft Python 3.3 die Liste aller offenen Dateideskriptoren von /proc/<PID>/fd/ ab, daher hängt die Leistung von der Anzahl der geöffneten Dateideskriptoren und nicht von MAXFD ab.
Siehe auch
- Python Issue #1663329: subprocess close_fds schlecht performant, wenn
SC_OPEN_MAXhoch ist - Squid Bug #837033: Squid sollte CLOEXEC auf geöffneten FDs setzen. „32k+ close() Aufrufe in jedem Kindprozess dauern lange ([12-56] Sekunden) in Xen PV Guests.“
Vorschlag
Nicht vererbbare Dateideskriptoren
Die folgenden Funktionen wurden modifiziert, um neu erstellte Dateideskriptoren standardmäßig nicht vererbbar zu machen.
asyncore.dispatcher.create_socket()io.FileIOio.open()open()os.dup()os.fdopen()os.open()os.openpty()os.pipe()select.devpoll()select.epoll()select.kqueue()socket.socket()socket.socket.accept()socket.socket.dup()socket.socket.fromfd()socket.socketpair()
os.dup2() erstellt standardmäßig immer noch vererbbare Handles, siehe unten.
Wenn verfügbar, werden atomare Flags verwendet, um Dateideskriptoren nicht vererbbar zu machen. Die Atomarität ist nicht garantiert, da ein Fallback erforderlich ist, wenn atomare Flags nicht verfügbar sind.
Neue Funktionen und Methoden
Neue Funktionen auf allen Plattformen verfügbar
os.get_inheritable(fd: int): GibtTruezurück, wenn der Dateideskriptor von Kindprozessen geerbt werden kann, andernfallsFalse.os.set_inheritable(fd: int, inheritable: bool): Setzt das Vererbungsflag des angegebenen Dateideskriptors.
Neue Funktionen nur unter Windows verfügbar
os.get_handle_inheritable(handle: int): GibtTruezurück, wenn das Handle von Kindprozessen geerbt werden kann, andernfallsFalse.os.set_handle_inheritable(handle: int, inheritable: bool): Setzt das Vererbungsflag des angegebenen Handles.
Neue Methoden
socket.socket.get_inheritable(): GibtTruezurück, wenn der Socket von Kindprozessen geerbt werden kann, andernfallsFalse.socket.socket.set_inheritable(inheritable: bool): Setzt das Vererbungsflag des angegebenen Sockets.
Andere Änderungen
Unter UNIX macht subprocess Dateideskriptoren des Parameters pass_fds vererbbar. Der Dateideskriptor wird im Kindprozess nach dem fork() und vor execv() vererbbar gemacht, sodass das Vererbungsflag der Dateideskriptoren im Elternprozess unverändert bleibt.
os.dup2() hat einen neuen optionalen Parameter inheritable: os.dup2(fd, fd2, inheritable=True). fd2 wird standardmäßig vererbbar erstellt, aber nicht vererbbar, wenn inheritable auf False gesetzt ist.
os.dup2() verhält sich anders als os.dup(), da der häufigste Anwendungsfall von os.dup2() die Ersetzung der Dateideskriptoren der Standard-Streams ist: stdin (0), stdout (1) und stderr (2). Standard-Streams werden erwartet, dass sie von Kindprozessen geerbt werden.
Abwärtskompatibilität
Dieses PEP bricht Anwendungen, die auf der Vererbung von Dateideskriptoren basieren. Entwickler werden ermutigt, das High-Level-Python-Modul subprocess wiederzuverwenden, das die Vererbung von Dateideskriptoren auf portable Weise handhabt.
Anwendungen, die das Modul subprocess mit dem Parameter pass_fds verwenden oder nur os.dup2() zur Umleitung von Standard-Streams verwenden, sollten nicht betroffen sein.
Python entspricht nicht mehr POSIX, da Dateideskriptoren nun standardmäßig nicht vererbbar sind. Python wurde nicht entwickelt, um POSIX zu entsprechen, sondern um portable Anwendungen zu entwickeln.
Abgelehnte Alternativen
Hinzufügen einer neuen Funktion open_noinherit()
Im Juni 2007 schlug Henning von Bargen in der python-dev Mailingliste vor, eine neue Funktion open_noinherit() hinzuzufügen, um Probleme mit geerbten Dateideskriptoren in Kindprozessen zu beheben. Zu dieser Zeit war der Standardwert des Parameters close_fds des subprocess Moduls False.
Lesen Sie den Mail-Thread: [Python-Dev] Proposal for a new function “open_noinherit” to avoid problems with subprocesses and security risks.
PEP 433
PEP 433, „Einfachere Unterdrückung der Vererbung von Dateideskriptoren“, war ein früherer Versuch, der verschiedene andere Alternativen vorschlug, aber es konnte kein Konsens erzielt werden.
Python-Probleme
- #10115: Unterstützung für accept4() zur atomaren Einstellung von Flags bei der Socket-Erstellung
- #12105: open() kann keine Flags wie O_CLOEXEC setzen
- #12107: TCP-Listening-Sockets werden ohne FD_CLOEXEC-Flag erstellt
- #16850: Hinzufügen des Modus „e“ zu open(): close-and-exec (O_CLOEXEC) / O_NOINHERIT
- #16860: Verwendung von O_CLOEXEC im tempfile-Modul
- #16946: subprocess: _close_open_fd_range_safe() setzt das close-on-exec-Flag unter Linux < 2.6.23 nicht, wenn O_CLOEXEC definiert ist
- #17070: Verwendung des neuen cloexec zur Verbesserung der Sicherheit und Vermeidung von Fehlern
- #18571: Implementierung von PEP 446: nicht erblich vererbbare Dateideskriptoren
Urheberrecht
Dieses Dokument wurde in den öffentlichen Bereich gestellt.
Quelle: https://github.com/python/peps/blob/main/peps/pep-0446.rst
Zuletzt geändert: 2025-02-01 08:59:27 GMT