Skip to content

fix(sandbox): deny path truncate on Landlock ABI below 3 - #143

Draft
cursor[bot] wants to merge 1 commit into
mainfrom
cursor/critical-bug-investigation-b62d
Draft

cursor[bot] wants to merge 1 commit into
mainfrom
cursor/critical-bug-investigation-b62d

Conversation

@cursor

@cursor cursor Bot commented Nov 9, 2026

Copy link
Copy Markdown

Bug and impact

On Landlock ABI 1 and 2, a sandboxed shell can wipe a user-owned file outside the workspace. open for write is still denied (EACCES), but truncate(2) succeeds and the file size becomes 0.

ShellClaw's primary device is a Jetson Orin Nano on JetPack 6.2, which ships kernel 5.15 (Landlock ABI 1). A command with no / in its text, such as python3 building the path with chr(47), passes the allowlist and reaches that syscall. The same shape was already shown to chmod host files. This one deletes the bytes.

Root cause

LANDLOCK_ACCESS_FS_TRUNCATE exists only from ABI 3 (Linux 6.2). landlock_handled_fs correctly omits that bit on older kernels, because setting it makes create_ruleset fail. A right that is not in handled_access_fs stays allowed. open(O_TRUNC) is still gated by WRITE_FILE. The path form of truncate(2) is not.

Fix

After restrict_self, if the ABI is below 3, install a seccomp filter that returns EPERM for truncate(2) (and truncate64 where that syscall exists). ftruncate(2) stays allowed: it needs a writable descriptor, and WRITE_FILE already rejects opening a host file. Shell redirection uses open(O_TRUNC), so workspace writes keep working.

On ABI 3 and newer the existing Landlock bit still applies, and the filter is not installed. os.truncate(path) and the truncate utility inside the workspace return EPERM on JetPack. Creating or rewriting a file with open does not.

Validation

A ruleset built with ABI 1 rights on this host (kernel Landlock ABI 6) reproduced the wipe: open(O_WRONLY|O_TRUNC) returned EACCES and truncate left the file at 0 bytes.

make test_sandbox then failed on the new case (WEXITSTATUS=5, size 22 to 0). After the filter, the same case passes: truncate returns EPERM, the host file keeps its size, a workspace open(O_TRUNC) succeeds, and ftruncate on that descriptor succeeds. The rest of test_sandbox passed.

Open in Web View Automation 

JetPack 6.2 (kernel 5.15) is Landlock ABI 1, which cannot gate
truncate(2). A sandboxed command could wipe a user-owned file outside
the workspace even though open for write returned EACCES. Deny that
path syscall with seccomp. ftruncate and open(O_TRUNC) stay available
so workspace writes still work.

Co-authored-by: esadrianno <esadrianno@gmail.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant