From: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> Date: Mon, 20 Jul 2026 09:40:40 +0000 (+0200) Subject: [3.15] gh-154225: Fix os.openpty() acquiring a controlling terminal on Solaris (GH... X-Git-Url: http://git.ipfire.org/index.cgi?a=commitdiff_plain;h=2aee2faff41046c351580f092e596a163489e000;p=thirdparty%2FPython%2Fcpython.git [3.15] gh-154225: Fix os.openpty() acquiring a controlling terminal on Solaris (GH-154229) (GH-154238) (cherry picked from commit a0caab9db6c2655d8429279892848d817343f99d) Co-authored-by: Serhiy Storchaka Co-authored-by: Claude Fable 5 --- diff --git a/Misc/NEWS.d/next/Library/2026-07-20-14-10-00.gh-issue-154225.openpty.rst b/Misc/NEWS.d/next/Library/2026-07-20-14-10-00.gh-issue-154225.openpty.rst new file mode 100644 index 000000000000..f15022b66320 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-20-14-10-00.gh-issue-154225.openpty.rst @@ -0,0 +1,2 @@ +Fix :func:`os.openpty` on Solaris and illumos: it no longer leaves the +pseudo-terminal as the controlling terminal of the calling process. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 2a25be16e61d..b4009b8cb686 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -9429,11 +9429,30 @@ os_openpty_impl(PyObject *module) goto posix_error; #if defined(HAVE_STROPTS_H) && !defined(HAVE_DEV_PTC) + // Pushing "ptem" makes the slave a terminal, which a session leader + // without a controlling terminal then acquires as one despite O_NOCTTY. + // Note whether we already had one, so a new one can be disowned below. + int had_ctty = 0; +#ifdef TIOCNOTTY + int tty_fd = open("/dev/tty", O_RDONLY | O_NOCTTY); + if (tty_fd >= 0) { + had_ctty = 1; + close(tty_fd); + } +#endif ioctl(slave_fd, I_PUSH, "ptem"); /* push ptem */ ioctl(slave_fd, I_PUSH, "ldterm"); /* push ldterm */ #ifndef __hpux ioctl(slave_fd, I_PUSH, "ttcompat"); /* push ttcompat */ #endif /* __hpux */ +#ifdef TIOCNOTTY + if (!had_ctty && getsid(0) == getpid()) { + // Disown it; TIOCNOTTY sends SIGHUP to the session leader. + PyOS_sighandler_t sig_saved = PyOS_setsig(SIGHUP, SIG_IGN); + ioctl(slave_fd, TIOCNOTTY); + PyOS_setsig(SIGHUP, sig_saved); + } +#endif #endif /* defined(HAVE_STROPTS_H) && !defined(HAVE_DEV_PTC) */ #endif /* HAVE_OPENPTY */