Skip to content

core: build and run on musl targets - #224

Merged
congwang-mk merged 3 commits into
mainfrom
musl-build
Sep 12, 2026
Merged

core: build and run on musl targets#224
congwang-mk merged 3 commits into
mainfrom
musl-build

Conversation

@congwang-mk

Copy link
Copy Markdown
Contributor

cargo build --target x86_64-unknown-linux-musl failed with 19 type errors, so anyone wanting a static binary for a small Alpine image had to fall back to a glibc base. The errors come from the libc crate typing the bindings differently per target, not from anything a build flag can change. Fixing the build then exposed two runtime bugs that only show on musl.

core: build on musl targets. The libc crate types the ptrace request as c_uint on glibc and c_int on musl, ioctl requests as c_ulong versus c_int, and msg_controllen as size_t versus u32. The explicit glibc-shaped casts are dropped so the constants carry their per-target type, ioctl requests cast to libc::Ioctl, and the one helper that names the ptrace request type sits behind a cfg alias. A test spelled STATX_BASIC_STATS locally because the libc crate only exports it for glibc.

landlock: open rule paths with open(2), not OpenOptions. musl defines O_SEARCH as O_PATH and folds it into O_ACCMODE, and std's OpenOptions masks custom flags with !O_ACCMODE. On musl the Landlock rule open silently lost O_PATH and became a real O_RDONLY open, so a read rule on a FIFO blocked child setup forever. Calling open(2) directly keeps O_PATH on every libc.

seccomp: stop the exec rewrite scan at the first NUL. The scan for argv/envp strings that could run into the execve path buffer read the whole span up to the buffer before looking for a NUL. glibc's brk heap keeps that span mapped, but musl's allocator places allocations in separate mmap chunks with unmapped pages between them, so the read hit a hole and the child's execve failed with EFAULT under chroot (19 of 20 runs). Checking each page for a NUL before reading the next also matches what the kernel would copy.

Verified on x86_64: the musl CLI is a static-pie binary that passes sandlock check and enforces Landlock; the full workspace suite on musl and on gnu produce identical results, with the only failures being the environment-dependent tests addressed in #223 plus one hardlink test that fails the same way on main here.

Not covered: the FFI cdylib is not produced for musl unless built with -C target-feature=-crt-static, and no musl target is added to the release matrix yet.

🤖 Generated with Claude Code

The libc crate types ptrace requests as c_uint on glibc but c_int on
musl, ioctl requests as c_ulong versus c_int, and msg_controllen as
size_t versus u32. The explicit glibc-shaped casts made a musl build
fail with 19 type errors, so users wanting a static binary for Alpine
had to fall back to a glibc base image. Let the constants carry their
per-target type, cast ioctl requests to libc::Ioctl, and fold the one
helper that named the request type into a PTRACE_CONT-only resume so
no code has to spell the type at all. The statx test constant is
spelled locally because the libc crate only exports it for glibc.

Signed-off-by: Cong Wang <cwang@multikernel.io>
musl defines O_SEARCH as O_PATH and folds it into O_ACCMODE, and
std's OpenOptions masks custom flags with !O_ACCMODE. On musl the
Landlock rule open therefore lost O_PATH and became a real O_RDONLY
open, so a read rule on a FIFO blocked child setup forever. Calling
open(2) directly keeps O_PATH on every libc.

Signed-off-by: Cong Wang <cwang@multikernel.io>
The scan for argv/envp strings that could run into the execve path
buffer read the whole span from each candidate up to the buffer, then
looked for a NUL. glibc's brk heap keeps that span mapped, but musl's
allocator places allocations in separate mmap chunks with unmapped
pages between them, so the read hit a hole and the child's execve
failed with EFAULT under chroot. Check each page for a NUL before
reading the next, which also matches what the kernel would copy.

Signed-off-by: Cong Wang <cwang@multikernel.io>
@congwang-mk
congwang-mk merged commit f5cfc91 into main Sep 12, 2026
17 checks passed
@congwang-mk
congwang-mk deleted the musl-build branch September 12, 2026 23:50
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