Skip to content

Thread creation fails under systemd's MemoryDenyWriteExecute=true #956

@bluetech

Description

@bluetech

systemd has a hardening flag for services MemoryDenyWriteExecute, described in the manpage as folllows:

Takes a boolean argument. If set, attempts to create memory mappings that are writable and executable at the same time, or to change existing memory mappings to become executable, or mapping shared memory segments as executable, are prohibited. Specifically, a system call filter is added (or preferably, an equivalent kernel check is enabled with prctl(2)) that rejects mmap(2) system calls with both PROT_EXEC and PROT_WRITE set, mprotect(2) or pkey_mprotect(2) system calls with PROT_EXEC set and shmat(2) system calls with SHM_EXEC set. Note that this option is incompatible with programs and libraries that generate program code dynamically at runtime, including JIT execution engines, executable stacks, and code "trampoline" feature of various C compilers. This option improves service security, as it makes harder for software exploits to change running code dynamically. [...]

When using this option with uv's python (3.14, Linux, x86-64, gnu), thread creation from Python fails:

$ systemd-run -p MemoryDenyWriteExecute=true -t ~/.local/share/uv/python/cpython-3.14.0-linux-x86_64-gnu/bin/python -c 'import threading; threading.Thread().start()'
Running as unit: run-p344916-i344917.service
Press ^] three times within 1s to disconnect TTY.
Traceback (most recent call last):
  File "<string>", line 1, in <module>
    import threading; threading.Thread().start()
                      ~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/home/ran/.local/share/uv/python/cpython-3.14.0-linux-x86_64-gnu/lib/python3.14/threading.py", line 1004, in start
    _start_joinable_thread(self._bootstrap, handle=self._os_thread_handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread

This doesn't happen with system Python (tested on Arch Linux with Python 3.14 and Debian trixie with Python 3.13):

$ systemd-run -p MemoryDenyWriteExecute=true -t python -c 'import threading; threading.Thread().start()'
Running as unit: run-p345006-i345007.service
Press ^] three times within 1s to disconnect TTY.

My initial thought was that this is due to JIT but sys._jit.is_enabled() returns false, and also has nothing to do with threads.

I will try to investigate why this happens when I have some time, but maybe someone has an idea.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions