Detect a seccomp-blocked set_thread_area so wibo runs under AWS Lambda#130
Conversation
|
I suggested a different approach here: #113 (comment) |
setThreadArea64 issues set_thread_area through int 0x80. Some seccomp sandboxes block that compat path and kill the process with SIGSYS before tebThreadSetup can fall back to modify_ldt; AWS Lambda is one. Lambda's filter uses a non-catchable KILL action rather than SECCOMP_RET_TRAP, so a SIGSYS handler can't recover from it either. Probe set_thread_area once in a forked child instead: if the child is killed by the filter (or the syscall fails), use modify_ldt. Forking isolates the trap, so this works for both KILL and TRAP filters. On a normal system it's a single extra fork at startup (cached) with the same result as before.
9d70533 to
51d206b
Compare
|
Thanks, I like the fork approach. Could you measure how much impact it has on startup (if any?) |
|
If fork overhead turns out to be measurable, then I wonder how vfork compares |
|
On the perf question — I benchmarked it on a normal x86_64 box (no seccomp, so the probe's Three variants:
800 / 400 runs per variant; 1σ ≈ 0.4 ms and 0.5–1.1 ms respectively. So the probe adds ~60 µs, once, at startup — about 1.3% of a do-nothing Box: Intel Core Ultra 7 265, Ubuntu 24.04, kernel 6.8. |
|
Thanks for verifying! |
Picks up the thread from #113 — running wibo on AWS Lambda, the GC/2.0
mwcceppcdies with SIGSYS during thread setup. It'ssetThreadArea64: it makes itsset_thread_areacall viaint 0x80, and Lambda's seccomp filter blocks the compat syscall path. The signal lands before the existingmodify_ldtfallback can run, since that only triggers whenset_thread_areareturns an error.I started from the SIGSYS-handler idea in the #113 review (catch the trap, rewrite the return to
-ENOSYS, let the normal fallback take over). It's neat, but it doesn't actually work on Lambda: the filter there uses a KILL action, notSECCOMP_RET_TRAP, so the SIGSYS is uncatchable and a handler never runs. I confirmed it with a small probe — install anSA_SIGINFOSIGSYS handler, fireint 0x80/set_thread_area, and the process is killed outright (the handler'ssi_code/si_archchecks never get a chance).So rather than catch the signal, this detects whether
set_thread_areais usable by trying it once in a forked child. If the child gets killed by the filter (or the syscall fails), the parent treats it as unavailable and usesmodify_ldt. Forking isolates the trap: a KILL action only takes down the child's process group, so the parent survives either way, and it works for both KILL and TRAP filters.Tested on Lambda (x86_64):
mwcceppc -versionand real compiles work and produce correct PPC objects, no env vars or config. The setup log shows the fall-through:On a normal machine it's one extra
forkat startup (cached, so at most once) and otherwise unchanged. If you'd rather not fork on the common path, I can gate it behind a/proc/self/statusSeccompcheck so it only probes when a filter is actually installed — happy to add that.Scope note: this only covers the x86_64 compat path (the
int 0x80insetThreadArea64); the 32-bit build's nativeset_thread_areais untouched.