Skip to content

codegen: reject x32 syscalls in x86_64 filters (fixes #19) - #49

Closed
Saransh-Jainbu wants to merge 1 commit into
google:masterfrom
Saransh-Jainbu:x32-syscall-bit
Closed

Saransh-Jainbu wants to merge 1 commit into
google:masterfrom
Saransh-Jainbu:x32-syscall-bit

Conversation

@Saransh-Jainbu

@Saransh-Jainbu Saransh-Jainbu commented Oct 28, 2026 •

Copy link
Copy Markdown

x32 syscalls report AUDIT_ARCH_X86_64, just like native x86_64 ones, and are told apart only by
__X32_SYSCALL_BIT (0x40000000) in nr. seccomp(2) says a filter must reject that bit
explicitly. kafel didn't check it, so on a kernel with x32 enabled, a denylist policy
(DEFAULT ALLOW with DENY/ERRNO rules) could be bypassed by calling the same syscall
through the x32 ABI.

Before, with POLICY p { DENY { ptrace } } USE p DEFAULT ALLOW:

  0: A := architecture
  1: if A != 0xc000003e goto 5
  2: A := syscall number
  3: if A < 0x65 goto 6
  4: if A >= 0x66 goto 6
  5: KILL
  6: ALLOW

Here x32 ptrace (0x40000209) is ALLOWed.

After:

  0: A := architecture
  1: if A != 0xc000003e goto 7
  2: A := syscall number
  3: if A < 0x40000000 goto 5
  4: if A != 0xffffffff goto 7
  5: if A < 0x65 goto 8
  6: if A >= 0x66 goto 8
  7: KILL
  8: ALLOW
  • x32 numbers are now killed, the same way kafel already handles an architecture the policy doesn't target.
  • nr == -1 still goes through the normal rules, so its result is unchanged. Tracers use -1 to
    skip a syscall, and filters are re-run after tracing. libseccomp makes the same exception.
  • Uniform policies (no syscall rules) and non-x86_64 arches are unchanged.
  • Added the x32_abi_rejected test. It fails without the change (the x32 syscall gets
    SECCOMP_RET_ALLOW) and passes with it. It runs on any x86_64 kernel, because seccomp sees nr
    before the kernel rejects x32 when the x32 ABI is disabled. All 36 tests pass.

This affects nsjail's shipped DEFAULT ALLOW configs (apache, firefox, chromium, telegram, znc, ...).
I'll send a submodule bump to nsjail once this lands.

x32 syscalls report AUDIT_ARCH_X86_64 like native x86_64 ones and are
only distinguished by __X32_SYSCALL_BIT in nr. seccomp(2) requires
filters to reject that bit explicitly; kafel did not, so on kernels with
x32 enabled a DEFAULT ALLOW deny-list could be bypassed by issuing the
same syscall through the x32 ABI.

Kill x32 syscall numbers the same way an untargeted architecture is
handled, while letting nr == -1 through to the regular rules (tracers use
it to skip a syscall and filters are re-run after tracing), matching
libseccomp.

Fixes google#19

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@google-cla

google-cla Bot commented Oct 28, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

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.

1 participant