fix: block Shocker container-escape syscalls in seccomp profile (CVE-2014-9357)#2276
fix: block Shocker container-escape syscalls in seccomp profile (CVE-2014-9357)#2276
Conversation
…2014-9357) Remove name_to_handle_at and open_by_handle_at from the SCMP_ACT_ALLOW list and add them to the SCMP_ACT_ERRNO deny list. These syscalls enable the Shocker container-escape attack chain. Docker's default seccomp profile blocks both; our custom profile previously relied solely on the capability bounding set (missing CAP_DAC_READ_SEARCH) as the single defense layer. This provides defense-in-depth: seccomp blocks the syscalls at the kernel level, regardless of capability configuration. Closes #2265 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
✅ Coverage Check PassedOverall Coverage
📁 Per-file Coverage Changes (1 files)
Coverage comparison generated by |
There was a problem hiding this comment.
Pull request overview
This PR hardens the agent container’s custom seccomp profile against the Shocker container-escape chain (CVE-2014-9357) by ensuring name_to_handle_at and open_by_handle_at are blocked consistent with Docker’s default posture.
Changes:
- Moved
name_to_handle_atandopen_by_handle_atfrom the seccomp allowlist to theSCMP_ACT_ERRNOdeny rules (EPERM). - Extended the existing “dangerous syscalls” test coverage to include these syscalls.
- Added a dedicated regression test asserting both syscalls are explicitly denied and not allowed.
Show a summary per file
| File | Description |
|---|---|
| containers/agent/seccomp-profile.json | Removes the two syscalls from SCMP_ACT_ALLOW and adds them to the explicit SCMP_ACT_ERRNO deny list. |
| src/seccomp-profile.test.ts | Adds assertions/tests to ensure the profile blocks the Shocker-related syscalls. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 1
| // Both syscalls must be explicitly denied, not just absent from allow list | ||
| expect(blockedSyscalls).toContain('name_to_handle_at'); | ||
| expect(blockedSyscalls).toContain('open_by_handle_at'); | ||
| expect(allowedSyscalls.has('name_to_handle_at')).toBe(false); | ||
| expect(allowedSyscalls.has('open_by_handle_at')).toBe(false); |
There was a problem hiding this comment.
The comment "must be explicitly denied, not just absent from allow list" is misleading here: the profile is already deny-by-default (defaultAction: SCMP_ACT_ERRNO), so simply omitting these syscalls from the allow rules would still block them. Consider rewording to reflect the actual intent (e.g., ensuring they remain explicitly listed in the ERRNO rules for defense-in-depth / regression protection) to avoid implying the allowlist omission would be insufficient.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
@copilot address the review feedback |
Done in 43a6711. Updated the comment to clarify that the explicit ERRNO listing serves defense-in-depth and regression protection purposes — since the profile is already deny-by-default ( |
Smoke Test: Copilot BYOK — PASS ✅
Running in BYOK offline mode ( PR by @lpcox · reviewer:
|
🔥 Smoke Test Results — PASS
PR: fix: block Shocker container-escape syscalls in seccomp profile (CVE-2014-9357) Overall: PASS ✅
|
Chroot Version Comparison Results
Result: FAILED — Python and Node.js versions differ between host and chroot environments.
|
|
Smoke Test Results ✅ PASS
|
|
Recent merged PRs:
GitHub MCP review: ❌ Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "registry.npmjs.org"See Network Configuration for more information.
|
🏗️ Build Test Suite Results
Overall: 8/8 ecosystems passed — ✅ PASS
|
Summary
Removes
name_to_handle_at(NR 303) andopen_by_handle_at(NR 304) from the seccomp ALLOW list and adds them to the ERRNO deny list, matching Docker's default seccomp hardening posture.Problem
The Shocker container-escape attack (CVE-2014-9357) uses
name_to_handle_atto obtain a raw inode handle andopen_by_handle_atto open it in a privileged context, escaping the container namespace. Docker's default seccomp profile blocks both syscalls for exactly this reason.Our custom seccomp profile previously allowed both syscalls, relying solely on the capability bounding set (missing
CAP_DAC_READ_SEARCH) as a single defense layer. While effective today, any future configuration drift — capability grant, privilege escalation, or kernel bypass — would leave the escape path fully open.Changes
containers/agent/seccomp-profile.json: Movedname_to_handle_atandopen_by_handle_atfrom SCMP_ACT_ALLOW to SCMP_ACT_ERRNOsrc/seccomp-profile.test.ts: Added dedicated test for Shocker syscalls + added both to the existing dangerous-syscalls assertionsDefense-in-depth
With this change, the Shocker attack chain is blocked at two independent layers:
CAP_DAC_READ_SEARCHabsent from bounding setCloses #2265