Skip to content

Commit a186551

Browse files
authored
Add regression tests for MemoryDenyWriteExecute=true (#1071)
As reported in #956, executable stacks cause thread creation to fail under MemoryDenyWriteExecute=true. In kernel 6.3+ (which the GitHub Actions runners should have) this is implemented using prctl(PR_SET_MDWE). In older versions systemd uses a more complicated seccomp filter.
1 parent 7af98d6 commit a186551

File tree

1 file changed

+36
-0
lines changed

1 file changed

+36
-0
lines changed

pythonbuild/disttests/__init__.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,42 @@ def assertPythonWorks(path: Path, argv0: Optional[str] = None):
320320
with self.subTest(msg="weird argv[0]"):
321321
assertPythonWorks(sys.executable, argv0="/dev/null")
322322

323+
@unittest.skipUnless(sys.platform == "linux", "Linux-specific prctl")
324+
@unittest.skipIf(
325+
"static" in os.environ["BUILD_OPTIONS"],
326+
"cannot import libc on static builds",
327+
)
328+
def test_nx_thread_creation(self):
329+
"Test that thread creation works under e.g. systemd's MemoryDenyWriteExecute."
330+
# Note that NX cannot be unset so this pollutes the current process,
331+
# but if something else breaks under NX we probably want to know!
332+
import ctypes
333+
import threading
334+
335+
libc = ctypes.CDLL(None, use_errno=True)
336+
# <linux/prctl.h>
337+
PR_SET_MDWE = 65
338+
PR_GET_MDWE = 66
339+
PR_MDWE_REFUSE_EXEC_GAIN = 1 << 0
340+
PR_MDWE_NO_INHERIT = 1 << 1
341+
mdwe = libc.prctl(PR_GET_MDWE, 0, 0, 0, 0)
342+
if mdwe < 0:
343+
self.skipTest("prctl(PR_SET_MDWE) unsupported")
344+
elif not (mdwe & PR_MDWE_REFUSE_EXEC_GAIN):
345+
if (
346+
libc.prctl(
347+
PR_SET_MDWE, PR_MDWE_REFUSE_EXEC_GAIN | PR_MDWE_NO_INHERIT, 0, 0, 0
348+
)
349+
!= 0
350+
):
351+
self.fail("prctl(PR_SET_MDWE): " + os.strerror(ctypes.get_errno()))
352+
353+
a = []
354+
t = threading.Thread(target=a.append, args=("Thread was here",))
355+
t.start()
356+
t.join()
357+
self.assertEqual(a, ["Thread was here"])
358+
323359

324360
if __name__ == "__main__":
325361
unittest.main()

0 commit comments

Comments
 (0)