gh-139184: Set O_CLOEXEC for master_fd when calling os.forkpty() (#139408)

Signed-off-by: Manjusaka <me@manjusaka.me>
Co-authored-by: Shamil <ashm.tech@proton.me>
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
This commit is contained in:
Nadeshiko Manju 2025-10-10 16:56:10 +08:00 committed by GitHub
parent f4104f5d74
commit 7cafd76a7f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 24 additions and 3 deletions

View File

@ -4592,6 +4592,8 @@ written in Python, such as a mail server's external command delivery program.
master end of the pseudo-terminal. For a more portable approach, use the
:mod:`pty` module. If an error occurs :exc:`OSError` is raised.
The returned file descriptor *fd* is :ref:`non-inheritable <fd_inheritance>`.
.. audit-event:: os.forkpty "" os.forkpty
.. warning::
@ -4608,6 +4610,9 @@ written in Python, such as a mail server's external command delivery program.
threads, this now raises a :exc:`DeprecationWarning`. See the
longer explanation on :func:`os.fork`.
.. versionchanged:: next
The returned file descriptor is now made non-inheritable.
.. availability:: Unix, not WASI, not Android, not iOS.

View File

@ -33,9 +33,14 @@ The :mod:`pty` module defines the following functions:
file descriptor connected to the child's controlling terminal (and also to the
child's standard input and output).
The returned file descriptor *fd* is :ref:`non-inheritable <fd_inheritance>`.
.. warning:: On macOS the use of this function is unsafe when mixed with using
higher-level system APIs, and that includes using :mod:`urllib.request`.
.. versionchanged:: next
The returned file descriptor is now made non-inheritable.
.. function:: openpty()

View File

@ -230,6 +230,7 @@ class PtyTest(unittest.TestCase):
os._exit(2)
os._exit(4)
else:
self.assertFalse(os.get_inheritable(master_fd))
debug("Waiting for child (%d) to finish." % pid)
# In verbose mode, we have to consume the debug output from the
# child or the child will block, causing this test to hang in the

View File

@ -0,0 +1 @@
:func:`os.forkpty` does now make the returned file descriptor non-inheritable.

View File

@ -5035,7 +5035,8 @@ PyDoc_STRVAR(os_forkpty__doc__,
"Returns a tuple of (pid, master_fd).\n"
"Like fork(), return pid of 0 to the child process,\n"
"and pid of child to the parent process.\n"
"To both, return fd of newly opened pseudo-terminal.");
"To both, return fd of newly opened pseudo-terminal.\n"
"The master_fd is non-inheritable.");
#define OS_FORKPTY_METHODDEF \
{"forkpty", (PyCFunction)os_forkpty, METH_NOARGS, os_forkpty__doc__},
@ -13446,4 +13447,4 @@ exit:
#ifndef OS__EMSCRIPTEN_LOG_METHODDEF
#define OS__EMSCRIPTEN_LOG_METHODDEF
#endif /* !defined(OS__EMSCRIPTEN_LOG_METHODDEF) */
/*[clinic end generated code: output=b5b370c499174f85 input=a9049054013a1b77]*/
/*[clinic end generated code: output=47ace1528820858b input=a9049054013a1b77]*/

View File

@ -9018,11 +9018,12 @@ Returns a tuple of (pid, master_fd).
Like fork(), return pid of 0 to the child process,
and pid of child to the parent process.
To both, return fd of newly opened pseudo-terminal.
The master_fd is non-inheritable.
[clinic start generated code]*/
static PyObject *
os_forkpty_impl(PyObject *module)
/*[clinic end generated code: output=60d0a5c7512e4087 input=f1f7f4bae3966010]*/
/*[clinic end generated code: output=60d0a5c7512e4087 input=24765e0f33275b3b]*/
{
int master_fd = -1;
pid_t pid;
@ -9048,6 +9049,12 @@ os_forkpty_impl(PyObject *module)
} else {
/* parent: release the import lock. */
PyOS_AfterFork_Parent();
/* set O_CLOEXEC on master_fd */
if (_Py_set_inheritable(master_fd, 0, NULL) < 0) {
PyErr_FormatUnraisable("Exception ignored when setting master_fd "
"non-inheritable in forkpty()");
}
// After PyOS_AfterFork_Parent() starts the world to avoid deadlock.
if (warn_about_fork_with_threads("forkpty") < 0)
return NULL;
@ -9055,6 +9062,7 @@ os_forkpty_impl(PyObject *module)
if (pid == -1) {
return posix_error();
}
return Py_BuildValue("(Ni)", PyLong_FromPid(pid), master_fd);
}
#endif /* HAVE_FORKPTY */