An ARM64-focused PRoot fork for Android/Termux containers. neoproot targets developers who run Debian/Ubuntu userspaces on phones and tablets, especially Node.js, pnpm, TypeScript, nvim, bwrap, and other syscall-heavy workflows.
GitHub Release assets are ARM64 Linux (glibc) CI builds. Termux needs a local bionic build; do not install those assets as $PREFIX/bin/neoproot.
curl -fsSL https://github.com/Raymer8639/neoproot/releases/latest/download/install.sh | shThe script detects the platform and does the right thing: on Termux it installs the build dependencies, builds the bionic binary from the tagged source, backs up the previous binary and installs the new one into $PREFIX/bin; on ARM64 Linux it downloads the release binary, verifies it against SHA256SUMS, and installs it into your PATH. It never touches a running container's rootfs. Read scripts/install.sh before piping it to a shell if you prefer; sh scripts/install.sh --help lists --version, --prefix and --portable.
Always build on the Termux host. Linux CI / Release files will not run correctly as the Termux Android binary.
pkg install clang make llvm binutils pkg-config libtalloc
git clone https://github.com/Raymer8639/neoproot.git
cd neoproot
sh install.sh
# Or build with Meson (GNUmakefile remains the reference implementation):
# Install meson+ninja with your package manager first.
CC=clang CXX=clang++ meson setup builddir
meson compile -C builddir
meson install -C builddirThe installer places neoproot in $PREFIX/bin.
On ARM64 Linux (not Termux), download neoproot or the lower-instruction-set neoproot-portable from Releases, verify its SHA256, and install it in your PATH.
- Automatic Termux host setup: wake-lock, file-descriptor limits, and
LD_*cleanup are handled by theneoprootlauncher. - link2symlink hard-link emulation works with pnpm and TypeScript/tsgo workflows that probe real paths through
/proc/<pid>/fd/<fd>. - High-frequency path operations avoid the fork's removed translation-thread-pool overhead, keeping nvim and package-manager workflows responsive.
- Optional
--seccomp-notify(Linux 5.0+) emulatesnewfstatatvia seccomp USER_NOTIF so directory metadata scans skip a ptrace stop. Kernel 4+ without the flag is unchanged. - Optional
--stat-shim=<guest-lib>preloads a guest-ABILD_PRELOADlibrary that resolvesstat/lstat/statxin-process (bind translation and fake_id0), keeping link2symlink results exact through a flag-gated USER_NOTIF fallback. Off by default. See stat-shim/README.md. - Built-in high-priority scheduling (
setpriority(-20)) improves CPU availability without root access. - Fixes include Chinese VNC exit hangs, logout/background-switch issues, and the misleading
signal 11exit warning. - The codebase uses a lean C23/C++23 implementation tuned for ARMv8.2, trading generic architecture coverage for ARM64 performance.
- 64-bit ARM Linux (
aarch64/ ARMv8.2+), with Android/Termux as the primary target. - Termux or an equivalent Android Linux environment, or an ARM64 Linux host.
- The optimized build is intentionally not supported on x86_64. Use an ARM64 machine for the published binaries.
neoproot -0 -r /data/data/com.termux/files/home/rootfs \
-b /dev -b /proc -b /sys -b /sdcard \
/usr/bin/env -i HOME=/root TERM=${TERM} PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
/bin/bash --loginThe command-line interface follows official PRoot conventions. You do not need to manually unset LD_PRELOAD, LD_LIBRARY_PATH, or LD_BIND_NOW; the launcher handles those variables before entering the guest.
The first-stage UML backend is selected explicitly with --backend=um. It
starts a separate UML guest kernel, so it must be launched from an untraced
Termux host process rather than from inside an existing PRoot or sandbox.
The backend accepts either a host directory or an ext4 image passed with -r
or --rootfs. A directory is used as the UML hostfs root. An ext4 image is
mounted as the UML guest root with a per-run temporary COW file; --readonly
uses the image directly without a COW file. The UML kernel and
stub_exe can be supplied with command-line options to neoproot-um, or
through these environment variables:
export NEOPROOT_UM_KERNEL=/path/to/linux-bionic
export NEOPROOT_UM_STUB=/path/to/stub_exe
neoproot --backend=um -r /path/to/rootfs -- /bin/shHostfs exposes the selected host directory directly to the guest; it is not a
security isolation boundary. Bind sources already inside that root can be
mapped with -b host:guest[:ro]; sources outside it, controlled targets such
as /proc, /sys, and /dev, and unsafe targets are rejected. Ext4 mode
requires /um-init from the matching UM harness. The supervisor passes the
session-v1 protocol parameters after mounting the guest's proc filesystem;
the init script mounts the temporary hostfs session at /run/neoproot and
returns the command status through that mount. Ext4 mode does not currently
support -b. Guest network setup is not supported. The backend must therefore
be treated as experimental and explicitly requested.
When --backend is omitted, the existing Neoproot behavior remains the
default. --backend=fast also selects that existing path; --backend=auto
does not enable UML automatically in this first stage.
Measured on a Termux aarch64 device, Arch Linux ARM container, identical output in every mode. Stat-heavy work is what a container spends its time on, and that is what neoproot removes:
du -As /usr (whole-tree metadata walk, output 4007438 in all modes)
| Mode | Time | vs plain ptrace |
|---|---|---|
| Plain ptrace path | 33.3 s | — |
--seccomp-notify only |
31.2 s | 1.07x |
--stat-shim + --seccomp-notify |
14.4 s | 2.32x |
Later releases cut the remaining ptrace stops further (fcntl is now traced only for the two fd-duplication commands), taking the same run from 15.7 s to 13.1 s, and 11-12 s on the device after deployment.
Single stat call (µs/op, plain / notify / shim)
| Call | plain | notify | shim |
|---|---|---|---|
| absolute path | 288.7 | 96.6 | 8.1 |
| dirfd-relative | 308.5 | 114.4 | 4.4 |
AT_FDCWD-relative |
203.8 | 90.9 | 92.9 |
raw syscall(SYS_statx) |
324.5 | 106.5 | 10.4 |
AT_FDCWD-relative names keep the tracer in the loop on purpose: the guest's cwd is virtual, so the shim re-issues them through the --seccomp-notify channel instead of guessing. That costs about the same as the plain path (103 vs 111 µs) while staying correct.
Compilation is unaffected (80-file cc -O0 build: 18.2 / 18.5 / 18.3 s across the three modes); the wins are in process startup, parsing and header I/O.
The older sysbench workload, for reference:
| Load | vs official PRoot |
|---|---|
| Low (primes <= 10000) | On par (within noise) |
| Medium-high (50000) | Ahead by 2.9% |
| Extreme (100000) | Ahead by 7.2% |
When reporting a result, include the device/SoC, Android and Termux versions, exact command, baseline version, and repeated measurements. Use the performance report form so results can be compared.
- Default target:
-march=armv8.2-a+fp16+dotprod+lse+rcpc+simd+crc+crypto(override withMARCH=). - Portable releases use
-march=armv8-a -mtune=generic; this relaxes CPU instructions but does not promise libc or kernel compatibility. - Link options include ThinLTO, section garbage collection, identical-code folding, RELRO/NOW, and stripping.
- The build depends on
libtalloc(Termux package:talloc).upxis optional.
neoproot was renamed from proot-scicat / uproot and continues to track useful fixes from termux/proot. The original implementation is proot-me/proot; the direct fork ancestor is scicat-team/proot-scicat. See CHANGELOG.md for version history and attribution.
Maintainers may use AI tools to assist with research, drafting, coding, or review. AI output is treated as untrusted input: maintainers remain responsible for reviewing and testing changes before merge. See CONTRIBUTING.md for expectations when submitting AI-assisted work.
- Report a bug
- Request a feature
- Ask a usage question
- Read help.md, SUPPORT.md, CONTRIBUTING.md, and SECURITY.md
Versions follow the termux/proot style. Releases before 2026-08-15 used the historical -scicat suffix; v5.7.3 and later releases use the neoproot name without that suffix.
GPLv2. The canonical text is in LICENSE; COPYING carries the original PRoot/CARE copyright notice from upstream.