Skip to content

Drop inherited supplementary groups when supplementaryGroups is [] - #384

Merged
iCharlesHu merged 2 commits into
mainfrom
jake-petroules/fix381
Oct 8, 2026
Merged

iCharlesHu merged 2 commits into
mainfrom
jake-petroules/fix381

Conversation

@jakepetroules

Copy link
Copy Markdown
Contributor

Fixes #381.

Setting PlatformOptions.supplementaryGroups to [] kept the parent's supplementary groups instead of dropping them. Both the fallback-path routing check (requiresFallbackSpawnPath) and the C shims tested count > 0, so [] behaved exactly like nil and setgroups() was never called.

Changes

  • Any non-nil value, including [], is now a request to call setgroups(); only nil inherits.

    • requiresFallbackSpawnPath routes any non-nil supplementaryGroups to the fallback path.
    • Swift passes a count of -1 for nil. _subprocess_spawn_prefork and _subprocess_fork_exec call setgroups(n, sgroups) whenever the count is non-negative, so [] becomes setgroups(0, NULL). The convention is documented in process_shims.h.
  • The DocC comment on supplementaryGroups (Darwin and Unix) now spells out each case:

    • nil: inherit (the default)
    • []: drop all
    • non-empty: replace exactly

    It also states that any non-nil value requires the privilege to call setgroups(), and that groups are applied before groupID/userID.

Behavior change

A process without root that sets supplementaryGroups = [] used to spawn successfully, because the setting was a silent no-op. It now fails with .spawnFailed / EPERM, as it would for any non-empty list.

Tests

  • SpawnPathTests.testPrivilegeChangesRequireTheFallbackPath: flipped the [] expectation and added a nil case.
  • testSubprocessPlatformOptionsEmptySupplementaryGroupsCallsSetgroups (runs without root): [] fails with EPERM, which proves setgroups is called. It fails without the fix.
  • testSubprocessPlatformOptionsNilSupplementaryGroupsInherits: nil spawns normally.
  • testSubprocessPlatformOptionsEmptySupplementaryGroupsDropsInherited (root only): with groupID = G and [], id -G reports only G.

Tested locally on macOS without root; the root-only tests were skipped there.

Setting PlatformOptions.supplementaryGroups to an empty array kept the
parent's supplementary groups instead of dropping them: both the
fallback-path routing check and the C shims tested `count > 0`, so `[]`
was indistinguishable from `nil` and setgroups() was never called.

Treat any non-nil value, including `[]`, as a request to call
setgroups(), keeping `nil` as "inherit". A non-nil empty array now routes
to the fallback (fork/exec or Darwin pre-fork) path, Swift passes a count
of -1 for `nil`, and the shims call setgroups(n, sgroups) whenever the
count is non-negative, so `[]` results in setgroups(0, NULL).

Document the nil (inherit) vs empty array (drop all) vs non-empty array
(replace) behavior on `supplementaryGroups`, including that any non-nil
value requires the privilege to call setgroups().

Fixes #381
Android has no /usr/bin/true, so testSubprocessPlatformOptionsNilSupplementaryGroupsInherits
failed there with executableNotFound. Run /bin/sh -c 'exit 0' instead, which is
available on every Unix platform the tests run on.
@iCharlesHu
iCharlesHu merged commit 536684c into main Oct 8, 2026
46 checks passed
@jakepetroules
jakepetroules deleted the jake-petroules/fix381 branch October 12, 2026 16:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

supplementaryGroups: [] retains the parent's supplementary groups instead of dropping them

2 participants