Skip to content

Commit 989a5a6

Browse files
ned-deilymiss-islington
authored andcommitted
pythongh-97897: Prevent os.mkfifo and os.mknod segfaults with macOS 13 SDK (pythonGH-97944)
The macOS 13 SDK includes support for the `mkfifoat` and `mknodat` system calls. Using the `dir_fd` option with either `os.mkfifo` or `os.mknod` could result in a segfault if cpython is built with the macOS 13 SDK but run on an earlier version of macOS. Prevent this by adding runtime support for detection of these system calls ("weaklinking") as is done for other newer syscalls on macOS. (cherry picked from commit 6d0a019) Co-authored-by: Ned Deily <[email protected]>
1 parent e2591e4 commit 989a5a6

File tree

3 files changed

+80
-8
lines changed

3 files changed

+80
-8
lines changed

Lib/test/test_posix.py

+22
Original file line numberDiff line numberDiff line change
@@ -2066,6 +2066,28 @@ def test_mkdir(self):
20662066
with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
20672067
os.mkdir("dir", dir_fd=0)
20682068

2069+
def test_mkfifo(self):
2070+
self._verify_available("HAVE_MKFIFOAT")
2071+
if self.mac_ver >= (13, 0):
2072+
self.assertIn("HAVE_MKFIFOAT", posix._have_functions)
2073+
2074+
else:
2075+
self.assertNotIn("HAVE_MKFIFOAT", posix._have_functions)
2076+
2077+
with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
2078+
os.mkfifo("path", dir_fd=0)
2079+
2080+
def test_mknod(self):
2081+
self._verify_available("HAVE_MKNODAT")
2082+
if self.mac_ver >= (13, 0):
2083+
self.assertIn("HAVE_MKNODAT", posix._have_functions)
2084+
2085+
else:
2086+
self.assertNotIn("HAVE_MKNODAT", posix._have_functions)
2087+
2088+
with self.assertRaisesRegex(NotImplementedError, "dir_fd unavailable"):
2089+
os.mknod("path", dir_fd=0)
2090+
20692091
def test_rename_replace(self):
20702092
self._verify_available("HAVE_RENAMEAT")
20712093
if self.mac_ver >= (10, 10):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
The macOS 13 SDK includes support for the ``mkfifoat`` and ``mknodat`` system calls.
2+
Using the ``dir_fd`` option with either :func:`os.mkfifo` or :func:`os.mknod` could result in a
3+
segfault if cpython is built with the macOS 13 SDK but run on an earlier
4+
version of macOS. Prevent this by adding runtime support for detection of
5+
these system calls ("weaklinking") as is done for other newer syscalls on
6+
macOS.

Modules/posixmodule.c

+52-8
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@
8585
# define HAVE_FUTIMENS_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)
8686
# define HAVE_UTIMENSAT_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)
8787
# define HAVE_PWRITEV_RUNTIME __builtin_available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, *)
88+
# define HAVE_MKFIFOAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)
89+
# define HAVE_MKNODAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)
8890

8991
# define HAVE_POSIX_SPAWN_SETSID_RUNTIME __builtin_available(macOS 10.15, *)
9092

@@ -169,6 +171,8 @@
169171
# define HAVE_FUTIMENS_RUNTIME 1
170172
# define HAVE_UTIMENSAT_RUNTIME 1
171173
# define HAVE_PWRITEV_RUNTIME 1
174+
# define HAVE_MKFIFOAT_RUNTIME 1
175+
# define HAVE_MKNODAT_RUNTIME 1
172176
#endif
173177

174178

@@ -10554,18 +10558,35 @@ os_mkfifo_impl(PyObject *module, path_t *path, int mode, int dir_fd)
1055410558
{
1055510559
int result;
1055610560
int async_err = 0;
10561+
#ifdef HAVE_MKFIFOAT
10562+
int mkfifoat_unavailable = 0;
10563+
#endif
1055710564

1055810565
do {
1055910566
Py_BEGIN_ALLOW_THREADS
1056010567
#ifdef HAVE_MKFIFOAT
10561-
if (dir_fd != DEFAULT_DIR_FD)
10562-
result = mkfifoat(dir_fd, path->narrow, mode);
10563-
else
10568+
if (dir_fd != DEFAULT_DIR_FD) {
10569+
if (HAVE_MKFIFOAT_RUNTIME) {
10570+
result = mkfifoat(dir_fd, path->narrow, mode);
10571+
10572+
} else {
10573+
mkfifoat_unavailable = 1;
10574+
result = 0;
10575+
}
10576+
} else
1056410577
#endif
1056510578
result = mkfifo(path->narrow, mode);
1056610579
Py_END_ALLOW_THREADS
1056710580
} while (result != 0 && errno == EINTR &&
1056810581
!(async_err = PyErr_CheckSignals()));
10582+
10583+
#ifdef HAVE_MKFIFOAT
10584+
if (mkfifoat_unavailable) {
10585+
argument_unavailable_error(NULL, "dir_fd");
10586+
return NULL;
10587+
}
10588+
#endif
10589+
1056910590
if (result != 0)
1057010591
return (!async_err) ? posix_error() : NULL;
1057110592

@@ -10606,18 +10627,33 @@ os_mknod_impl(PyObject *module, path_t *path, int mode, dev_t device,
1060610627
{
1060710628
int result;
1060810629
int async_err = 0;
10630+
#ifdef HAVE_MKNODAT
10631+
int mknodat_unavailable = 0;
10632+
#endif
1060910633

1061010634
do {
1061110635
Py_BEGIN_ALLOW_THREADS
1061210636
#ifdef HAVE_MKNODAT
10613-
if (dir_fd != DEFAULT_DIR_FD)
10614-
result = mknodat(dir_fd, path->narrow, mode, device);
10615-
else
10637+
if (dir_fd != DEFAULT_DIR_FD) {
10638+
if (HAVE_MKNODAT_RUNTIME) {
10639+
result = mknodat(dir_fd, path->narrow, mode, device);
10640+
10641+
} else {
10642+
mknodat_unavailable = 1;
10643+
result = 0;
10644+
}
10645+
} else
1061610646
#endif
1061710647
result = mknod(path->narrow, mode, device);
1061810648
Py_END_ALLOW_THREADS
1061910649
} while (result != 0 && errno == EINTR &&
1062010650
!(async_err = PyErr_CheckSignals()));
10651+
#ifdef HAVE_MKNODAT
10652+
if (mknodat_unavailable) {
10653+
argument_unavailable_error(NULL, "dir_fd");
10654+
return NULL;
10655+
}
10656+
#endif
1062110657
if (result != 0)
1062210658
return (!async_err) ? posix_error() : NULL;
1062310659

@@ -15466,6 +15502,14 @@ PROBE(probe_fdopendir, HAVE_FDOPENDIR_RUNTIME)
1546615502
PROBE(probe_mkdirat, HAVE_MKDIRAT_RUNTIME)
1546715503
#endif
1546815504

15505+
#ifdef HAVE_MKFIFOAT
15506+
PROBE(probe_mkfifoat, HAVE_MKFIFOAT_RUNTIME)
15507+
#endif
15508+
15509+
#ifdef HAVE_MKNODAT
15510+
PROBE(probe_mknodat, HAVE_MKNODAT_RUNTIME)
15511+
#endif
15512+
1546915513
#ifdef HAVE_RENAMEAT
1547015514
PROBE(probe_renameat, HAVE_RENAMEAT_RUNTIME)
1547115515
#endif
@@ -15599,11 +15643,11 @@ static const struct have_function {
1559915643
#endif
1560015644

1560115645
#ifdef HAVE_MKFIFOAT
15602-
{ "HAVE_MKFIFOAT", NULL },
15646+
{ "HAVE_MKFIFOAT", probe_mkfifoat },
1560315647
#endif
1560415648

1560515649
#ifdef HAVE_MKNODAT
15606-
{ "HAVE_MKNODAT", NULL },
15650+
{ "HAVE_MKNODAT", probe_mknodat },
1560715651
#endif
1560815652

1560915653
#ifdef HAVE_OPENAT

0 commit comments

Comments
 (0)