diff --git a/containers/agent/seccomp-profile.json b/containers/agent/seccomp-profile.json index 6f73f1a9..7c95b1a0 100644 --- a/containers/agent/seccomp-profile.json +++ b/containers/agent/seccomp-profile.json @@ -189,11 +189,9 @@ "munlock", "munlockall", "munmap", - "name_to_handle_at", "nanosleep", "newfstatat", "open", - "open_by_handle_at", "openat", "openat2", "pause", @@ -395,7 +393,9 @@ "get_kernel_syms", "query_module", "create_module", - "nfsservctl" + "nfsservctl", + "name_to_handle_at", + "open_by_handle_at" ], "action": "SCMP_ACT_ERRNO", "errnoRet": 1, diff --git a/src/seccomp-profile.test.ts b/src/seccomp-profile.test.ts index 7f71f9d7..c817e1ce 100644 --- a/src/seccomp-profile.test.ts +++ b/src/seccomp-profile.test.ts @@ -79,6 +79,7 @@ describe('seccomp-profile', () => { 'pivot_root', 'umount', 'umount2', 'swapon', 'swapoff', 'syslog', 'add_key', 'request_key', 'keyctl', + 'name_to_handle_at', 'open_by_handle_at', ]; for (const syscall of dangerousSyscalls) { @@ -121,6 +122,25 @@ describe('seccomp-profile', () => { } }); + test('should block Shocker container-escape syscalls (CVE-2014-9357)', () => { + const allowedSyscalls = new Set( + profile.syscalls + .filter(r => r.action === 'SCMP_ACT_ALLOW') + .flatMap(r => r.names) + ); + + const blockedSyscalls = profile.syscalls + .filter(r => r.action === 'SCMP_ACT_ERRNO') + .flatMap(r => r.names); + + // Explicitly listed in ERRNO rules for defense-in-depth regression protection + // (deny-by-default means absence alone would block them, but explicit denial is more robust) + 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); + }); + test('should have valid JSON structure', () => { expect(profile.defaultAction).toBeDefined(); expect(profile.architectures).toBeDefined();