Skip to content

macOS: Python ProcessPoolExecutor fails under seatbelt — sysctl for SC_SEM_NSEMS_MAX not allowed #211

Description

@goerz

The macOS seatbelt profile grants (allow ipc-posix-sem), so POSIX
semaphores are clearly intended to work. But Python's
concurrent.futures.ProcessPoolExecutor (and multiprocessing generally)
crashes on startup under fence:

File ".../concurrent/futures/process.py", line 594, in _check_system_limits
  nsems_max = os.sysconf("SC_SEM_NSEMS_MAX")
PermissionError: [Errno 1] Operation not permitted

sysconf(SC_SEM_NSEMS_MAX) performs a sysctl lookup that is not on the
profile's sysctl-read allowlist (which covers hw.* names and a few
others). Python checks this limit before creating any semaphore, so the
allowed ipc-posix-sem capability is unreachable in practice for the most
common Python parallelism API.

Reproduce

fence -- python3 -c "from concurrent.futures import ProcessPoolExecutor as P; P(2).__enter__()"

Real-world hit: marker-pdf (PDF OCR) uses a process pool for text
extraction and dies immediately under fence; the workaround is per-tool
(--disable_multiprocessing) and not always available.

Suggested fix

According to Claude:

Add the POSIX semaphore sysctls to the allowlist, e.g.:

(allow sysctl-read (sysctl-name-prefix "kern.posix.sem."))

(Or the specific name the lookup uses on current macOS — the denial is
visible via log stream --predicate 'sender == "Sandbox"' while running the
one-liner above.)

Unlike GPU access this has no security-posture trade-off worth debating:
it's a read-only limit query required to use a capability the profile
already grants.

Environment: macOS 24.6.0 (Apple Silicon), Python 3.14 (uv-managed), fence
sandbox-exec backend.

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