You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Every guest-execution bug we've hit (#112 git corruption, #115 link false-success, bun install failure, the failed glibc-native T0) traces to one architectural root: proot uses ptrace, a lossy syscall-translation layer forced on us by unrooted Android (untrusted_app blocks namespaces/root). We've fixed the widespread cases with targeted patches, but ptrace has a ceiling some tools sit above. This issue frames the long-term "any Linux tool works" architecture decision so it's made deliberately, not one band-aid at a time.
bun — its installer opens node_modules as a directory fd then forks ~14 workers doing openat(dirfd, …)/linkatrelative to that fd. proot can't correctly track dirfd→path across parallel ptraced processes → workers get ENOENT on an existing dir → Failed to install N packages, empty node_modules, misleading exit 0. Not the Run the engine natively (no proot in the hot path): structural fix for the untrusted_app transport corruption #115 bug (copyfile backend fails identically); not config-fixable. Parallel + fd-relative ops are exactly where ptrace sandboxes break down. (Even native Termux struggles to run bun.)
glibc-native (T0, #115 comment) — running our glibc rootfs binaries directly under Android's bionic linker is impossible (ET_EXEC rejected; glibc rtld aborts; PIE glibc still segfaults). So "just drop proot for the current rootfs" is off the table.
General ceiling: io_uring, complex fd-relative flows, some namespaces — anything ptrace can't faithfully mediate.
Reference: what Termux does
Termux's native environment is not proot — its ~2000 packages are compiled against bionic and run as real app processes (no ptrace) → real syscalls, hardlinks, fd semantics all work. When Termux needs glibc (real Ubuntu) it uses proot-distro — the same proot, the same bugs we have. So Termux "wins" only by avoiding proot for its own tools, at the cost of a fully bionic userland. Their Play-Store build execs those bionic PIE binaries via /system/bin/linker64 (our T0 confirmed that path works for bionic PIE, not for glibc).
The decision: how do we reach "any Linux tool works"?
Option
What
Fixes bun / exotic tools?
Cost / risk
A. Stay on proot, patch per-tool
keep glibc rootfs; fix tools as they break (l2s, git/pnpm config, …)
No — ceiling stays
Low per fix, but unbounded tail; can't cover parallel/fd-relative/io_uring tools
B. Native bionic userland (Termux model)
rebuild engine (node/git/…) as bionic PIE, run native via linker64, no proot in hot path; proot only for optional glibc
Most tools yes; bun still uncertain (flaky even on native Termux)
High — adopt/маintain a bionic userland, drop glibc rootfs; claude/codex ride native node (npm pkgs, OK once node runs)
C. microVM (Android AVF / pKVM)
real Linux kernel in a VM; everything runs natively incl. glibc
High + device-gated (needs AVF/pKVM: Android 13+, specific SoCs; MediaTek/Exynos support varies), perf/battery/size cost; fall back to proot where AVF absent
Long term: pick B or C deliberately if "arbitrary Linux tooling must work" is a real product requirement. C (AVF microVM) is the only path that fixes everything including glibc + exotic tools, but it's device-gated and needs a proot fallback. B (native bionic) removes ptrace for the engine but keeps a long tail (and doesn't clearly win bun).
Asks
Decide whether "any arbitrary Linux tool works on-device" is a hard requirement or best-effort.
If hard requirement → spike AVF availability across the target device matrix (Seeker/MediaTek, Snapdragon, Exynos) — that gates option C.
Otherwise → adopt "proot + targeted fixes, bun/exotic unsupported" as the documented stance.
Related: #112, #114, #115 (+ PR #116). Evidence (probe harness, on-device traces) in debug/issue-115/ and the #115 comments.
Summary
Every guest-execution bug we've hit (#112 git corruption, #115 link false-success, bun install failure, the failed glibc-native T0) traces to one architectural root: proot uses ptrace, a lossy syscall-translation layer forced on us by unrooted Android (
untrusted_appblocks namespaces/root). We've fixed the widespread cases with targeted patches, but ptrace has a ceiling some tools sit above. This issue frames the long-term "any Linux tool works" architecture decision so it's made deliberately, not one band-aid at a time.What's already fixed (proot patches, shipped/in-flight)
--link2symlink. Inuntrusted_appthe kernel denies hardlinks; l2s faked success (result=0) via dangling symlinks, defeating callers' fallbacks → silent git object loss + broken pnpm. Removing it makeslinkatfail honestly → git falls back to rename, pnpm to copy. Fixes the whole link()-with-fallback class (git, pnpm, npm was never affected). Verified on-device (SM-A356E): git 50/50 objects, pnpm 589/589 files, node server HTTP 200.What proot CANNOT fix (the ceiling)
node_modulesas a directory fd then forks ~14 workers doingopenat(dirfd, …)/linkatrelative to that fd. proot can't correctly track dirfd→path across parallel ptraced processes → workers getENOENTon an existing dir →Failed to install N packages, emptynode_modules, misleading exit 0. Not the Run the engine natively (no proot in the hot path): structural fix for the untrusted_app transport corruption #115 bug (copyfile backend fails identically); not config-fixable. Parallel + fd-relative ops are exactly where ptrace sandboxes break down. (Even native Termux struggles to run bun.)Reference: what Termux does
Termux's native environment is not proot — its ~2000 packages are compiled against bionic and run as real app processes (no ptrace) → real syscalls, hardlinks, fd semantics all work. When Termux needs glibc (real Ubuntu) it uses proot-distro — the same proot, the same bugs we have. So Termux "wins" only by avoiding proot for its own tools, at the cost of a fully bionic userland. Their Play-Store build execs those bionic PIE binaries via
/system/bin/linker64(our T0 confirmed that path works for bionic PIE, not for glibc).The decision: how do we reach "any Linux tool works"?
linker64, no proot in hot path; proot only for optional glibcRecommendation
Asks
Related: #112, #114, #115 (+ PR #116). Evidence (probe harness, on-device traces) in
debug/issue-115/and the #115 comments.