Closed Bug 1376653 Opened 4 years ago Closed 4 years ago

firefox seccomp-bpf sandbox is broken on musl libc


(Core :: Security: Process Sandboxing, defect)

54 Branch
Not set



Tracking Status
firefox56 --- fixed


(Reporter:, Assigned: jld)


(Whiteboard: sb+)


(3 files)

User Agent: Mozilla/5.0 (X11; Linux x86_64; rv:54.0) Gecko/20100101 Firefox/54.0
Build ID: 20170626211010

Steps to reproduce:

start firefox 54.0 on alpine linux

Actual results:

instead of correct page load it shows "Gah. Your tab just crashed."

background process with seccomp-bpf filter crashed because pthread_create of musl uses different clone flags than glibc so the syscall failed and this lead to a null pointer dereference.

thread creation fails at ProcessHangMonitor ctor
null deref is at CreateHangMonitorChild
because mThread is 0.

the sandbox policy only allows the glibc clone flags and it fails to whitelist certain syscalls used by musl that are reasonable to allow, details are in the alpine bug report:

Expected results:

allow thread creation, not crash.
Component: Untriaged → DOM
Product: Firefox → Core
Bill might be able to offer some thoughts ...
Flags: needinfo?(wmccloskey)
Flags: needinfo?(wmccloskey) → needinfo?(jld)
Assignee: nobody → jld
Component: DOM → Security: Process Sandboxing
Flags: needinfo?(jld)
To summarize what I'm seeing in the downstream bug report, and what to do about it:

1. musl libc is passing CLONE_DETACHED, of which the man page says: “This flag is still defined, but has no effect.” (as of 2.6.2, which predates seccomp-bpf); the kernel doesn't seem to have done anything with the flag other than #define it since the beginning of the Git history.  We can just mask it off in the flag comparison.

2. musl uses tkill to target threads in the current process; the workaround we did for Bionic in bug 1093893 can have its conditional expanded.

3. getdents vs. getdents64; normally amd64 doesn't have separate "64" versions of file-related syscalls, but apparently this is an exception.  Trivial to fix.

4. ALSA is trying to fork/exec to… run a shell to expand a glob?  There seems to be a workaround to make ALSA not do that, but if there weren't:

  a. ALSA support is Tier 3 (in the sense of, and plugins other than hw and dmix may already be broken by content sandboxing.  Up to a point we'd take patches that allow more things under #ifdef MOZ_ALSA, but:

  b. fork/exec wouldn't work even if we allowed the syscalls, because the child process would inherit the seccomp-bpf policy, and *not* the SIGSYS handler.  So the first time the dynamic linker calls open() or stat(), the process is immediately killed.  (Also, once we get content processes chrooted, /bin/sh won't exist because / will be an empty deleted directory.)
Whiteboard: sb+
Comment on attachment 8887219 [details]
Bug 1376653 - Loosen restrictions on clone flags for musl.
Attachment #8887219 - Flags: review?(gpascutto) → review+
Comment on attachment 8887220 [details]
Bug 1376653 - Unconditionalize the tkill() polyfill.
Attachment #8887220 - Flags: review?(gpascutto) → review+
Comment on attachment 8887221 [details]
Bug 1376653 - Fix handling of architecture differences for getdents.
Attachment #8887221 - Flags: review?(gpascutto) → review+
Pushed by
Loosen restrictions on clone flags for musl. r=gcp
Unconditionalize the tkill() polyfill. r=gcp
Fix handling of architecture differences for getdents. r=gcp
Closed: 4 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla56
You need to log in before you can comment on or make changes to this bug.