-
Notifications
You must be signed in to change notification settings - Fork 14
test: add chroot escape vector test coverage #1162
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -169,6 +169,69 @@ describe('Chroot Edge Cases', () => { | |||||
| }); | ||||||
| }); | ||||||
|
|
||||||
| // ---------- Batch: Container escape vector tests ---------- | ||||||
| describe('Container Escape Prevention (batched)', () => { | ||||||
| let batch: BatchResults; | ||||||
|
|
||||||
| beforeAll(async () => { | ||||||
| batch = await runBatch(runner, [ | ||||||
| // pivot_root - blocked in seccomp profile | ||||||
| { name: 'pivot_root', command: 'mkdir -p /tmp/newroot /tmp/putold && pivot_root /tmp/newroot /tmp/putold 2>&1 || unshare --mount pivot_root /tmp/newroot /tmp/putold 2>&1' }, | ||||||
| // mount after capability drop - mount syscall allowed in seccomp but CAP_SYS_ADMIN should be dropped | ||||||
| { name: 'mount_tmpfs', command: 'mount -t tmpfs tmpfs /tmp/test-mount-$$ 2>&1' }, | ||||||
|
||||||
| { name: 'mount_tmpfs', command: 'mount -t tmpfs tmpfs /tmp/test-mount-$$ 2>&1' }, | |
| { name: 'mount_tmpfs', command: 'mkdir -p /tmp/test-mount-$$ && mount -t tmpfs tmpfs /tmp/test-mount-$$ 2>&1' }, |
Copilot
AI
Mar 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
umount /tmp is often not a mount point, so it may fail with messages like 'not mounted' or 'invalid argument' rather than a permission/seccomp-related error. This can make the test flaky or fail for the wrong reason. Consider targeting a path that is reliably a mount point inside the container (or adjust the expected output regex to include common non-permission failures if that's acceptable for this check).
| { name: 'umount', command: 'umount /tmp 2>&1' }, | |
| { name: 'umount', command: 'umount /proc 2>&1' }, |
Copilot
AI
Mar 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer avoiding cat | grep here; it adds an unnecessary process and can be simplified to a single grep reading the file directly (and optionally anchor the match to reduce accidental matches). This also makes the command’s exit code semantics clearer.
| { name: 'no_new_privs', command: 'cat /proc/self/status | grep NoNewPrivs 2>&1' }, | |
| { name: 'no_new_privs', command: 'grep "^NoNewPrivs:" /proc/self/status 2>&1' }, |
Copilot
AI
Mar 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting logLevel: 'debug' in integration tests can significantly increase CI noise and make failures harder to scan. Consider using the default log level (or only enabling debug logging when a test fails / via an env flag) so routine runs stay quiet.
Copilot
AI
Mar 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This command doesn’t reliably exercise pivot_root as an escape vector: (1) pivot_root requires specific preconditions (new root typically needs to be a mount point), so it can fail with EINVAL (invalid argument) even when protections are not the cause; and (2) the || unshare --mount pivot_root ... fallback further mixes failure modes. As written, the test can pass due to invalid setup rather than seccomp/capability enforcement. To make this a true protection test, set up the required preconditions (so it would succeed in an unsafe configuration), then assert on a failure mode that maps to the intended protection (or adjust comments/assertions to avoid claiming seccomp specifically).
Copilot
AI
Mar 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
umount /tmp is often not a mount point, so it may fail with messages like 'not mounted' or 'invalid argument' rather than a permission/seccomp-related error. This can make the test flaky or fail for the wrong reason. Consider targeting a path that is reliably a mount point inside the container (or adjust the expected output regex to include common non-permission failures if that's acceptable for this check).
| expect(r.stdout).toMatch(/operation not permitted|permission denied|not permitted/i); | |
| expect(r.stdout).toMatch(/operation not permitted|permission denied|not permitted|not mounted|invalid argument/i); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This command doesn’t reliably exercise
pivot_rootas an escape vector: (1)pivot_rootrequires specific preconditions (new root typically needs to be a mount point), so it can fail withEINVAL(invalid argument) even when protections are not the cause; and (2) the|| unshare --mount pivot_root ...fallback further mixes failure modes. As written, the test can pass due to invalid setup rather than seccomp/capability enforcement. To make this a true protection test, set up the required preconditions (so it would succeed in an unsafe configuration), then assert on a failure mode that maps to the intended protection (or adjust comments/assertions to avoid claiming seccomp specifically).