Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 446 – 새로 생성되는 파일 디스크립터를 상속되지 않도록 설정

Author:
Victor Stinner <vstinner at python.org>
Status:
Final
Type:
Standards Track
Created:
05-Aug-2013
Python-Version:
3.4
Replaces:
433

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

초록

자식 프로세스에서 파일 디스크립터가 누출되면 여러 성가신 문제가 발생하며, 이는 잘 알려진 주요 보안 취약점입니다. subprocess 모듈에서 close_fds매개변수를 True로 설정하여 사용하는 것은 모든 경우에 가능하지 않습니다.

이 PEP는 이러한 문제의 위험을 줄이기 위해 Python이 생성하는 모든 파일 디스크립터를 기본적으로 상속되지 않도록 설정할 것을 제안합니다. 이 PEP는 비상속 파일 디스크립터를 생성하기 위한 원자적 플래그를 지원하는 운영 체제에서 다중 스레드 애플리케이션의 경쟁 조건도 수정합니다.

이로 인해 발생할 가능성이 높은 코드 손상을 알고 있지만, 인류의 이익을 위해 이를 추진합니다. (자세한 내용은 아래의 “하위 호환성” 섹션을 참조하십시오.)

근거

파일 디스크립터의 상속

각 운영 체제는 파일 디스크립터의 상속을 서로 다르게 처리합니다. Windows는 기본적으로 상속되지 않는 핸들을 생성하는 반면, UNIX와 Windows의 POSIX API는 기본적으로 상속되는 파일 디스크립터를 생성합니다. Python은 단일 코드베이스를 유지하고 파일 디스크립터에 동일한 형식을 사용하기 위해 Windows 네이티브 API보다 POSIX API를 선호하므로, 상속되는 파일 디스크립터를 생성합니다.

한 가지 예외가 있습니다. os.pipe()는 Windows에서 상속되지 않는 파이프를 생성하는 반면, UNIX에서는 상속되는 파이프를 생성합니다. 그 이유는 구현상의 산물 때문입니다. os.pipe()는 Windows에서 CreatePipe()(네이티브 API)를 호출하는 반면, UNIX에서는 pipe()(POSIX API)를 호출합니다. CreatePipe() 호출은 Windows 98의 POSIX API에 pipe()가 도입되기 전인 1994년에 Python에 추가되었습니다. issue #4708에서는 Windows의 os.pipe()가 상속되는 파이프를 생성하도록 변경할 것을 제안합니다.

Windows에서의 파일 디스크립터 상속

Windows에서 파일 객체의 네이티브 형식은 핸들(C 형식 HANDLE)입니다. 이러한 핸들에는 핸들을 자식 프로세스에서 상속할 수 있는지 여부를 정의하는 HANDLE_FLAG_INHERIT 플래그가 있습니다. POSIX API의 경우 C 런타임(CRT)도 파일 디스크립터(C 형식 int)를 제공합니다. 파일 디스크립터의 핸들은 _get_osfhandle(fd) 함수를 사용하여 가져올 수 있습니다. _open_osfhandle(handle) 함수를 사용하여 핸들로부터 파일 디스크립터를 생성할 수 있습니다.

CreateProcess()를 사용하면, 핸들은 상속 가능한 플래그(HANDLE_FLAG_INHERIT)가 설정되어 있고 bInheritHandles 매개변수가 CreateProcess()TRUE인 경우에만 상속됩니다. 표준 스트림(0, 1, 2)을 제외한 모든 파일 디스크립터는 bInheritHandlesTRUE인 경우에도 자식 프로세스에서 닫힙니다. spawnv() 함수를 사용하면 상속 가능한 모든 핸들과 상속 가능한 모든 파일 디스크립터가 자식 프로세스에 상속됩니다. 이 함수는 STARTUPINFO 구조체의 문서화되지 않은 cbReserved2lpReserved2 필드를 사용하여 파일 디스크립터 배열을 전달합니다.

CreateProcess()를 사용하여 표준 스트림(stdin, stdout, stderr)을 교체하려면 STARTUPINFO 구조체의 dwFlags 필드에서 STARTF_USESTDHANDLES 플래그를 설정하고 CreateProcess()bInheritHandles 매개변수를 TRUE로 설정해야 합니다. 따라서 하나 이상의 표준 스트림이 교체되면 상속 가능한 모든 핸들이 자식 프로세스에 상속됩니다.

subprocess 프로세스의 close_fds매개변수 기본값은 stdin, stdout, stderr 매개변수가 None인 경우 True(bInheritHandles=FALSE)이고, 그렇지 않은 경우 False(bInheritHandles=TRUE)입니다.

다음도 참조하십시오:

Windows에서 일부 핸들만 상속

Windows Vista부터 CreateProcess()는 STARTUPINFO 구조체의 확장 기능인 STARTUPINFOEX 구조체를 지원합니다. 이 새로운 구조체를 사용하면 상속할 핸들 목록인 PROC_THREAD_ATTRIBUTE_HANDLE_LIST를 지정할 수 있습니다. 자세한 내용은 Win32에서 새 프로세스가 상속하는 핸들을 프로그래밍 방식으로 제어하기 (Raymond Chen, 2011년 12월)를 읽으십시오.

Windows Vista 이전에는 핸들을 상속 가능하게 만든 후 bInheritHandles=TRUE와 함께 CreateProcess()를 호출할 수 있습니다. 다른 모든 핀이 상속 불가능한 경우 이 옵션이 작동합니다. 경쟁 조건이 발생합니다. 다른 스레드가 bInheritHandles=TRUE와 함께 CreateProcess()를 호출하면 두 번째 프로세스에도 핸들이 상속됩니다.

Microsoft는 경쟁 조건을 방지하기 위해 잠금을 사용할 것을 제안합니다. Q315939: PRB: CreateProcess 호출 중 자식이 의도하지 않은 핸들을 상속함 (최종 검토: 2006년 11월)을 읽으십시오. Python 이슈 #16500 “atfork 모듈 추가”는 이러한 잠금을 추가할 것을 제안하며, 이를 사용하면 경쟁 조건 없이 핸들을 상속 불가능하게 만들 수 있습니다. 이러한 잠금은 Python 스레드 간의 경쟁 조건만 방지하며, C 스레드는 보호하지 않습니다.

또 다른 방법은 상속해야 하는 핸들을 복제하고, 복제된 핸들의 값을 자식 프로세스에 전달하여 자식 프로세스가 DuplicateHandle()를 사용해 DUPLICATE_CLOSE_SOURCE와 함께 복제된 핸들을 가져가도록 하는 것입니다. 핸들이 두 번 복제되므로 부모 프로세스와 자식 프로세스 사이에서 핸들 값이 변경됩니다. 부모 프로세스 및 자식 프로세스는 이 변경을 처리하도록 조정해야 합니다. 자식 프로그램을 수정할 수 없다면 최종 자식 프로그램을 생성하기 전에 중간 프로그램을 사용하여 부모 프로세스에서 핸들을 가져갈 수 있습니다. 중간 프로그램은 자식 프로세스의 핸들을 부모 프로세스에 전달해야 합니다. 모든 핸들을 가져가지 못한 경우, 예를 들어 중간 프로세스가 실패한 경우 부모는 복제된 핸들을 닫아야 할 수 있습니다. 핸들 값을 전달하는 데 명령줄을 사용하는 경우 핸들이 복제될 때 그 값이 변경되므로 명령줄을 수정해야 합니다.

이 PEP에는 이 문제에 대한 해결책이 포함되어 있지 않습니다. 모든 Windows 버전에서 작동하는 완벽한 해결책이 없기 때문입니다. 이 문제는 Windows에서 핸들 또는 파일 디스크립터 상속에 의존하는 사용 사례가 잘 알려질 때까지 보류하며, 그때 최선의 해결책을 선택하고 구현을 신중하게 테스트할 수 있습니다.

UNIX에서의 파일 디스크립터 상속

POSIX는 C 함수 execv()가 호출될 때 파일 디스크립터를 자동으로 닫도록 파일 디스크립터에 close-on-exec 플래그를 제공합니다. close-on-exec 플래그가 해제된 파일 디스크립터는 자식 프로세스에 상속되고, 플래그가 설정된 파일 디스크립터는 자식 프로세스에서 닫힙니다.

fcntl()을 사용하여 두 번의 시스템 호출(현재 플래그를 가져오는 호출과 새 플래그를 설정하는 호출)로 플래그를 설정할 수 있습니다.:

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 및 QNX는 ioctl()을 사용하여 한 번의 시스템 호출로 플래그를 설정하는 것도 지원합니다.:

int res;
res = ioctl(fd, FIOCLEX, 0);
if (!res) { /* handle the error */ }

참고: close-on-exec 플래그는 fork()에 영향을 주지 않습니다. 모든 파일 디스크립터가 자식 프로세스에 상속됩니다. Python 이슈 #16500 “atfork 모듈 추가”는 fork 시 코드를 실행할 새 atfork 모듈을 추가할 것을 제안하며, 이를 사용하여 파일 디스크립터를 자동으로 닫을 수 있습니다.

상속 가능한 파일 디스크립터 관련 문제

대부분의 경우 자식 프로세스에 “유출된” 상속 가능한 파일 디스크립터는 큰 버그를 일으키지 않으므로 발견되지 않습니다. 그렇다고 해서 이러한 버그를 수정하지 않아도 된다는 의미는 아닙니다.

상속된 파일 디스크립터와 관련된 일반적인 문제는 다음과 같습니다.

  • Windows에서는 디렉터리에서 열려 있는 모든 파일 핸들을 닫기 전에는 해당 디렉터리를 제거할 수 없습니다. 파일이 FILE_SHARE_DELETE 플래그(open()O_TEMPORARY 모드)로 생성된 경우를 제외하면 파일에서도 동일한 문제가 발생합니다.
  • 수신 대기 소켓이 자식 프로세스에 유출되면 부모 프로세스와 자식 프로세스가 종료되기 전에는 소켓 주소를 재사용할 수 없습니다. 예를 들어 웹 서버가 프로세스를 처리하기 위해 새 프로그램을 생성하고 해당 프로그램이 아직 끝나지 않은 동안 서버가 재시작되면, TCP 포트가 여전히 사용 중이므로 서버를 시작할 수 없습니다.

오픈 소스 프로젝트의 이슈 예시는 다음과 같습니다:

  • Mozilla (Firefox): 2002-05부터 미해결 상태입니다
  • dbus library: 2008-05에 수정되었습니다 (dbus commit), 자식 프로세스에서 파일 디스크립터를 닫습니다
  • autofs: 2009-02에 수정되었으며, CLOEXEC 플래그를 설정합니다
  • qemu: 2009-12에 수정되었습니다 (qemu commit), CLOEXEC 플래그를 설정합니다
  • Tor: 2010-12에 수정되었으며, CLOEXEC 플래그를 설정합니다
  • OCaml: 2011-04부터 미해결 상태이며, “PR#5256: Unix.open_process*를 사용하여 열린 프로세스가 소켓을 포함한 모든 열린 파일 디스크립터를 상속합니다”
  • ØMQ: 2012-08부터 미해결 상태입니다
  • Squid: 2012-07부터 미해결 상태입니다

다음도 참조하십시오: Excuse me son, but your code is leaking !!! (Dan Walsh, 2012년 3월). 파일 디스크립터 누출과 관련된 SELinux 이슈를 다룹니다.

보안 취약점

민감한 파일 핸들과 파일 디스크립터가 누출되면 보안 취약점이 발생할 수 있습니다. 신뢰할 수 없는 자식 프로세스가 누출된 파일 디스크립터를 통해 비밀번호와 같은 민감한 데이터를 읽거나 부모 프로세스를 제어할 수 있습니다. 수신 대기 소켓이 누출되면 자식 프로세스가 새 연결을 수락하여 민감한 데이터를 읽을 수 있습니다.

취약점의 예시는 다음과 같습니다:

CERT Secure Coding Standards도 참고하십시오: FIO42-C. Ensure files are properly closed when they are no longer needed.

subprocess 모듈에서 수정된 문제

상속된 파일 디스크립터로 인해 subprocess 모듈에서 4개의 이슈가 발생했습니다:

이러한 이슈는 subprocess 모듈의 4가지 변경 사항을 통해 Python 3.2에서 수정되었습니다:

  • 이제 파이프는 상속되지 않습니다;
  • 이제 close_fds 매개변수의 기본값은 True입니다. 단, Windows에서는 표준 스트림이 하나 이상 교체된 경우 기본값이 False라는 예외가 있습니다;
  • 새로운 pass_fds 매개변수가 추가되었습니다;
  • C로 구현된 _posixsubprocess 모듈의 생성입니다.

상속되지 않는 파일 디스크립터의 원자적 생성

다중 스레드 애플리케이션에서는 파일 디스크립터가 상속되지 않도록 설정되기 전에 새 프로그램이 생성되기 직전 상속 가능한 파일 디스크립터가 생성될 수 있습니다. 이 경우 파일 디스크립터가 자식 프로세스로 유출됩니다. 파일 디스크립터를 직접 상속되지 않는 상태로 생성하면 이 경쟁 조건을 방지할 수 있습니다.

FreeBSD, Linux, Mac OS X, Windows 및 기타 여러 운영 체제는 파일 디스크립터를 생성할 때 상속 플래그를 원자적으로 해제하여 상속되지 않는 파일 디스크립터를 생성하는 기능을 지원합니다.

상속되지 않는 소켓을 생성하기 위해 Windows 7 SP1 및 Windows Server 2008 R2 SP1에 WSASocket()용 새로운 WSA_FLAG_NO_HANDLE_INHERIT 플래그가 추가되었습니다. 이전 Windows 버전(예: Windows XP SP3)에서 이 플래그를 사용하면 WSASocket() 호출이 WSAEPROTOTYPE 오류와 함께 실패합니다.

UNIX에서는 파일과 소켓에 새로운 플래그가 추가되었습니다.

  • O_CLOEXEC: Linux (2.6.23), FreeBSD (8.3), Mac OS 10.8, OpenBSD 5.0, Solaris 11, QNX, BeOS, 다음 NetBSD 릴리스(6.1?)에서 사용할 수 있습니다. 이 플래그는 POSIX.1-2008의 일부입니다.
  • socket()socketpair()SOCK_CLOEXEC 플래그는 Linux 2.6.27, OpenBSD 5.2, NetBSD 6.0에서 사용할 수 있습니다.
  • fcntl(): F_DUPFD_CLOEXEC 플래그는 Linux 2.6.24, OpenBSD 5.0, FreeBSD 9.1, NetBSD 6.0, Solaris 11에서 사용할 수 있습니다. 이 플래그는 POSIX.1-2008의 일부입니다.
  • fcntl(): F_DUP2FD_CLOEXEC 플래그는 FreeBSD 9.1 및 Solaris 11에서 사용할 수 있습니다.
  • recvmsg(): MSG_CMSG_CLOEXEC은 Linux 2.6.23 및 NetBSD 6.0에서 사용할 수 있습니다.

2.6.23보다 오래된 Linux에서는 O_CLOEXEC 플래그가 단순히 무시됩니다. 따라서 파일 디스크립터가 상속되지 않는지 확인하려면 fcntl()을 호출해야 합니다. FD_CLOEXEC 플래그가 없으면 O_CLOEXEC은 지원되지 않습니다. 2.6.27보다 오래된 Linux에서는 소켓 유형에 SOCK_CLOEXEC 플래그가 설정된 경우 socket() 또는 socketpair() 호출이 errnoEINVAL로 설정하고 실패합니다.

새로운 함수:

  • dup3(): Linux 2.6.27(및 glibc 2.9)에서 사용할 수 있습니다.
  • pipe2(): Linux 2.6.27(및 glibc 2.9)에서 사용할 수 있습니다.
  • accept4(): Linux 2.6.28(및 glibc 2.10)에서 사용할 수 있습니다.

2.6.28보다 오래된 Linux에서는 accept4()errnoENOSYS로 설정하고 실패합니다.

요약:

운영 체제 원자적 파일 원자적 소켓
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)

범례:

  • “Atomic File”: open()을 사용하여 상속되지 않는 파일 디스크립터를 원자적으로 생성할 수 있는 운영 체제의 최초 버전입니다.
  • “Atomic Socket”: 상속되지 않는 소켓을 원자적으로 생성할 수 있는 운영 체제의 최초 버전입니다.
  • “X”: 아직 지원되지 않습니다.

다음도 참고하십시오:

Python 3.3의 상태

Python 3.3은 모든 플랫폼에서 상속 가능한 파일 디스크립터를 생성하지만, Windows에서는 상속되지 않는 파일 디스크립터를 생성하는 os.pipe()는 예외입니다.

상속되지 않는 파일 디스크립터를 원자적으로 생성하는 것과 관련된 새로운 상수 및 함수가 Python 3.3에 추가되었습니다: os.O_CLOEXEC, os.pipe2()socket.SOCK_CLOEXEC입니다.

UNIX에서는 subprocess 모듈이 기본적으로 자식 프로세스의 모든 파일 디스크립터를 닫지만, 표준 스트림(0, 1, 2) 및 pass_fds 매개변수의 파일 디스크립터는 예외입니다. close_fds 매개변수가 False로 설정되면 모든 상속 가능한 파일 디스크립터가 자식 프로세스에 상속됩니다.

Windows에서는 subprocess가 기본적으로 자식 프로세스의 모든 핸들과 파일 디스크립터를 닫습니다. 표준 스트림(stdin, stdout 또는 stderr) 중 하나 이상이 대체되면(예: 파이프로 리디렉션된 경우), 상속 가능한 모든 핸들과 파일 디스크립터 0, 1, 2가 자식 프로세스에 상속됩니다.

os.execv*()os.spawn*() 계열의 함수를 사용하면 상속 가능한 모든 핸들과 상속 가능한 모든 파일 디스크립터가 자식 프로세스에 상속됩니다.

UNIX에서는 multiprocessing모듈이 os.fork()를 사용하므로 모든 파일 디스크립터가 자식 프로세스에 상속됩니다.

Windows에서는 multiprocessing모듈을 사용하는 자식 프로세스에 상속 가능한 모든 핸들과 파일 디스크립터 0, 1, 2가 상속되며, 표준 스트림을 제외한 모든 파일 디스크립터는 닫힙니다.

요약:

모듈 UNIX의 FD Windows의 핸들 Windows의 FD
subprocess, 기본값 STD, pass_fds 없음 STD
subprocess, stdout 대체 STD, pass_fds 모두 STD
subprocess, close_fds=False 모두 모두 STD
multiprocessing 해당 없음 모두 STD
os.execv(), os.spawn() 모두 모두 모두

범례:

  • “all”: 모든 inheritable 파일 디스크립터 또는 핸들이 자식 프로세스에 상속됩니다.
  • “none”: 모든 핸들이 자식 프로세스에서 닫힙니다.
  • “STD”: 파일 디스크립터 0 (stdin), 1 (stdout), 2 (stderr)만 자식 프로세스에서 상속됩니다.
  • “pass_fds”: 서브프로세스의 pass_fds 매개변수에 지정된 파일 디스크립터가 상속됩니다.
  • “not applicable”: UNIX에서는 multiprocessing이 fork()를 사용하므로 이 경우는 이 PEP의 영향을 받지 않습니다.

열려 있는 모든 파일 디스크립터 닫기

UNIX에서는 subprocess 모듈이 자식 프로세스에서 거의 모든 파일 디스크립터를 닫습니다. 열려 있는 파일 디스크립터가 몇 개뿐인 경우에도 이 작업에는 MAXFD개의 시스템 호출이 필요하며, 여기서 MAXFD는 파일 디스크립터의 최댓값입니다. 이 최댓값은 다음을 사용하여 읽을 수 있습니다: os.sysconf("SC_OPEN_MAX").

MAXFD가 크면 이 작업이 느릴 수 있습니다. 예를 들어 MAXFD=655,000인 FreeBSD 빌드봇에서는 이 작업에 300ms가 걸렸습니다. issue #11284: 파일 디스크립터를 닫는 작업이 느림을 참조하십시오.

Linux에서 Python 3.3은 열려 있는 모든 파일 디스크립터의 목록을 /proc/<PID>/fd/에서 가져오므로 성능은 MAXFD가 아니라 열려 있는 파일 디스크립터의 수에 따라 달라집니다.

다음도 참조하십시오:

  • Python issue #1663329: SC_OPEN_MAX가 높을 때 subprocess close_fds의 성능이 낮음
  • Squid Bug #837033: Squid는 열린 FD에 CLOEXEC를 설정해야 합니다. “각 자식 프로세스에서 32k+개의 close() 호출은 Xen PV 게스트에서 오랜 시간이 걸립니다([12-56]초).”

제안

상속되지 않는 파일 디스크립터

다음 함수가 새로 생성되는 파일 디스크립터를 기본적으로 상속되지 않도록 수정됩니다:

  • asyncore.dispatcher.create_socket()
  • io.FileIO
  • io.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()는 여전히 기본적으로 상속 가능하게 생성합니다. 아래를 참조하십시오.

가능한 경우 파일 디스크립터를 상속 불가능하게 만들기 위해 원자적 플래그를 사용합니다. 원자적 플래그를 사용할 수 없을 때 폴백이 필요하므로 원자성은 보장되지 않습니다.

새 함수 및 메서드

모든 플랫폼에서 사용할 수 있는 새 함수:

  • os.get_inheritable(fd: int): 파일 디스크립터를 자식 프로세스에 상속할 수 있으면 True를, 그렇지 않으면 False를 반환합니다.
  • os.set_inheritable(fd: int, inheritable: bool): 지정한 파일 디스크립터의 상속 가능 플래그를 설정합니다.

Windows에서만 사용할 수 있는 새 함수:

  • os.get_handle_inheritable(handle: int): 핸들을 자식 프로세스에 상속할 수 있으면 True를, 그렇지 않으면 False를 반환합니다.
  • os.set_handle_inheritable(handle: int, inheritable: bool): 지정한 핸들의 상속 가능 플래그를 설정합니다.

새 메서드:

  • socket.socket.get_inheritable(): 소켓을 자식 프로세스에 상속할 수 있으면 True를, 그렇지 않으면 False를 반환합니다.
  • socket.socket.set_inheritable(inheritable: bool): 지정한 소켓의 상속 가능 플래그를 설정합니다.

기타 변경 사항

UNIX에서 subprocess는 pass_fds 매개변수의 파일 디스크립터를 상속 가능하게 만듭니다. 파일 디스크립터는 fork()execv() 전에 자식 프로세스에서 상속 가능하게 설정되므로, 부모 프로세스의 파일 디스크립터 상속 가능 플래그는 변경되지 않습니다.

os.dup2()에는 새로운 선택적 inheritable매개변수가 있습니다: os.dup2(fd, fd2, inheritable=True). fd2는 기본적으로 상속 가능하게 생성되지만, inheritableFalse이면 상속 불가능하게 생성됩니다.

os.dup2()의 가장 일반적인 사용 사례는 표준 스트림의 파일 디스크립터인 stdin (0), stdout (1) 및 stderr (2)를 대체하는 것이므로, os.dup2()os.dup()와 다르게 동작합니다. 표준 스트림은 자식 프로세스에 상속되는 것으로 예상합니다.

하위 호환성

이 PEP는 파일 디스크립터 상속에 의존하는 애플리케이션과의 호환성을 깨뜨립니다. 개발자는 파일 디스크립터 상속을 이식 가능한 방식으로 처리하는 고수준 Python 모듈인 subprocess를 재사용하도록 권장합니다.

pass_fds 매개변수와 함께 subprocess 모듈을 사용하거나 표준 스트림을 리디렉션하기 위해 os.dup2()만 사용하는 애플리케이션은 영향을 받지 않습니다.

이제 파일 디스크립터가 기본적으로 상속 불가능하게 설정되므로 Python은 더 이상 POSIX를 준수하지 않습니다. Python은 POSIX를 준수하도록 설계된 것이 아니라, 이식 가능한 애플리케이션을 개발하도록 설계되었습니다.

관련 작업

Go, Perl 및 Ruby 프로그래밍 언어는 새로 생성된 파일 디스크립터를 기본적으로 상속 불가능하게 만듭니다. Go 1.0(2009)부터 Perl 1.0 (1987) 및 Ruby 2.0(2013)도 마찬가지입니다.

Python으로 작성된 SCons 프로젝트는 Windows에서 파일을 상속 불가능하게 만들기 위해 내장 함수 file()open()을 재정의합니다. win32.py를 참조하십시오.

거부된 대안

새로운 open_noinherit() 함수를 추가하십시오

2007년 6월, Henning von Bargen은 자식 프로세스에서 상속된 파일 디스크립터 문제를 해결하기 위해 새로운 open_noinherit() 함수를 추가하자고 python-dev 메일링 리스트에서 제안했습니다. 당시 subprocess 모듈의 close_fds 매개변수 기본값은 False였습니다.

메일 스레드를 읽어 보십시오: [Python-Dev] 서브프로세스 및 보안 위험 문제를 방지하기 위한 새로운 함수 “open_noinherit” 제안.

PEP 433

PEP 433, “파일 디스크립터 상속을 더욱 쉽게 억제하기”는 여러 다른 대안을 제안한 이전 시도였지만, 합의에 도달하지 못했습니다.

Python 이슈