Skip to content

Suppress setuid and setgid on shebang scripts#199

Merged
jserv merged 1 commit into
sysprog21:mainfrom
open-sources-port:setuid-setgid
Jul 15, 2026
Merged

Suppress setuid and setgid on shebang scripts#199
jserv merged 1 commit into
sysprog21:mainfrom
open-sources-port:setuid-setgid

Conversation

@doanbaotrung

@doanbaotrung doanbaotrung commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

The Linux kernel (fs/exec.c bprm_fill_uid) deliberately ignores setuid/setgid bits on interpreted scripts to prevent privilege escalation via interpreter manipulation. elfuse had no such guard: exec_is_script was never tracked, so the setuid/setgid check was effectively always true for all executables.

Fix by:

  • Snapshotting the directly-executed file's stat() before the shebang resolution loop overwrites path_host with the final interpreter path.
  • Setting exec_is_script = true on the first confirmed shebang (rc > 0 from elf_read_shebang), so deeply nested chains also trip the flag.
  • After elf_load, applying S_ISUID/S_ISGID only when the directly-executed file was a regular non-script ELF.
  • Honouring the kernel's S_ISGID-requires-S_IXGRP rule to distinguish mandatory-locking GIDs from setgid execution.

Fix #138
Fix #139


Summary by cubic

Suppress setuid/setgid on shebang scripts to match Linux and prevent privilege escalation. Switch exec to fd-based loading/mapping with execute-permission checks to avoid TOCTOU.

  • Bug Fixes
    • Snapshot the original file’s stat and mark exec_is_script on the first shebang (covers nested chains).
    • Update creds only for non-script regular files; apply sgid only when group-exec is set.
    • Use elf_read_shebang_fd, elf_load_fd, and elf_map_segments_fd to keep stable fds, validate exec perms for both target and interpreter, and commit new creds right before PNR.

Fixes #138.

Written for commit e862632. Summary will update on new commits.

Review in cubic

@jserv
jserv requested a review from Max042004 July 13, 2026 07:53
cubic-dev-ai[bot]

This comment was marked as resolved.

@jserv jserv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refined based on the review from @cubic-dev-ai . If you disagree with any of its feedback, discuss it with the reviewer to reach a consensus and consolidate the shared knowledge base.

@doanbaotrung
doanbaotrung force-pushed the setuid-setgid branch 2 times, most recently from 6f1545e to 48a67e2 Compare July 15, 2026 15:25
The Linux kernel (fs/exec.c bprm_fill_uid) deliberately ignores
setuid/setgid bits on interpreted scripts to prevent privilege
escalation via interpreter manipulation.  elfuse had no such
guard: exec_is_script was never tracked, so the setuid/setgid
check was effectively always true for all executables.

Fix by:
- Snapshotting the directly-executed file's stat() before the
  shebang resolution loop overwrites path_host with the final
  interpreter path.
- Setting exec_is_script = true on the first confirmed shebang
  (rc > 0 from elf_read_shebang), so deeply nested chains also
  trip the flag.
- After elf_load, applying S_ISUID/S_ISGID only when the
  directly-executed file was a regular non-script ELF.
- Honouring the kernel's S_ISGID-requires-S_IXGRP rule to
  distinguish mandatory-locking GIDs from setgid execution.

Fix sysprog21#138
@doanbaotrung

Copy link
Copy Markdown
Collaborator Author

Fixed all the comments

@jserv
jserv merged commit 602c619 into sysprog21:main Jul 15, 2026
9 checks passed
@jserv

jserv commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Thank @doanbaotrung for contributing!

henrybear327 pushed a commit to henrybear327/elfuse that referenced this pull request Jul 17, 2026
The Linux kernel (fs/exec.c bprm_fill_uid) deliberately ignores
setuid/setgid bits on interpreted scripts to prevent privilege
escalation via interpreter manipulation.  elfuse had no such
guard: exec_is_script was never tracked, so the setuid/setgid
check was effectively always true for all executables.

Fix by:
- Snapshotting the directly-executed file's stat() before the
  shebang resolution loop overwrites path_host with the final
  interpreter path.
- Setting exec_is_script = true on the first confirmed shebang
  (rc > 0 from elf_read_shebang), so deeply nested chains also
  trip the flag.
- After elf_load, applying S_ISUID/S_ISGID only when the
  directly-executed file was a regular non-script ELF.
- Honouring the kernel's S_ISGID-requires-S_IXGRP rule to
  distinguish mandatory-locking GIDs from setgid execution.

Close sysprog21#138
Close sysprog21#139

Co-authored-by: Trung <trung_bao.d@kbtgvn.tech>
henrybear327 pushed a commit to henrybear327/elfuse that referenced this pull request Jul 17, 2026
The Linux kernel (fs/exec.c bprm_fill_uid) deliberately ignores
setuid/setgid bits on interpreted scripts to prevent privilege
escalation via interpreter manipulation.  elfuse had no such
guard: exec_is_script was never tracked, so the setuid/setgid
check was effectively always true for all executables.

Fix by:
- Snapshotting the directly-executed file's stat() before the
  shebang resolution loop overwrites path_host with the final
  interpreter path.
- Setting exec_is_script = true on the first confirmed shebang
  (rc > 0 from elf_read_shebang), so deeply nested chains also
  trip the flag.
- After elf_load, applying S_ISUID/S_ISGID only when the
  directly-executed file was a regular non-script ELF.
- Honouring the kernel's S_ISGID-requires-S_IXGRP rule to
  distinguish mandatory-locking GIDs from setgid execution.

Close sysprog21#138
Close sysprog21#139

Co-authored-by: Trung <trung_bao.d@kbtgvn.tech>
@doanbaotrung
doanbaotrung deleted the setuid-setgid branch July 18, 2026 17:17
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.

Fragile Path Verification for trusted_setid_script (Affecting sudo and pkexec) Interpreted Scripts Deliberately Execute as Setuid/Setgid

2 participants