Skip to content

Improve file descriptor disinheritance performance #172

@jakepetroules

Description

@jakepetroules

Wrote this up a while back and pasting it here so we can consider applying some of the APIs described here to maximize file descriptor disinheritance performance across various platforms.

--

In POSIX, spawning a new process inherits the parent's file descriptors by default. This is widely considered a security issue, and many libraries (including swift-subprocess) attempt to effectively flip this default.

Unfortunately, preventing subprocesses from inheriting all open file descriptors requires using non-portable API and comes with a significant performance penalty depending on the platform and libc versions. In most cases, swift-subprocess will attempt to use posix_spawn in cases where the platform offers a related posix_spawn API for efficiently closing all open file descriptors. If the platform offers no such API, it will fall back to fork+exec and use a related API for efficiently closing all open file descriptors, and finally fall back to manually computing the largest open file descriptor and manually issuing a potentially very large number of close() syscalls.

The following table indicates the performance and techniques used based on the spawn strategy used. The posix_spawn column indicates the specific O(1) posix_spawn API used to close all file descriptors. The pre-fork column indicates the file descriptor closing strategy used when posix_spawn can't be used. N/A in both columns indicates that O(n) manual closing will be used.

Platform Version posix_spawn pre-fork
macOS 10.7+ posix_spawnattr_setflags + POSIX_SPAWN_CLOEXEC_DEFAULT -
Linux kernel 5.9+ with Glibc 2.34+ posix_spawn_file_actions_addclosefrom_np close_range
^ kernel 5.9+ with older Glibc - close_range
^ kernel 5.9+ with Musl - close_range
^ kernel < 5.9 - -
Android kernel 5.11+ posix_spawnattr_setflags + POSIX_SPAWN_CLOEXEC_DEFAULT close_range
^ kernel < 5.11 posix_spawnattr_setflags + POSIX_SPAWN_CLOEXEC_DEFAULT * -
FreeBSD 13.1+ posix_spawn_file_actions_addclosefrom_np close_range / closefrom
OpenBSD 3.5+ - closefrom

* POSIX_SPAWN_CLOEXEC_DEFAULT requires Android 13 (API level 33) and provides no good programmatic way to know if it's supported other than checking the version at runtime
* Android with a kernel older than Linux 5.11 falls back to an O(n) solution when using posix_spawn because close_range with CLOSE_RANGE_CLOEXEC is not available.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions