# proot for the sandbox: sources, build and licenses

`sandbox/src/main/jniLibs/arm64-v8a/libproot.so` and `libproot-loader.so` are built by `build-proot.sh` in this
folder. They ship as native libraries so Android extracts them, executable, into the app's `nativeLibraryDir`. Their
SHA-256s are in `SHA256SUMS`. `NativeBinariesTest` checks the sums, and that both files are arm64 with every `PT_LOAD`
aligned to 16 KB.

## Sources

| What | URL | SHA-256 |
| --- | --- | --- |
| Termux proot 5.1.107.102 | https://github.com/termux/proot/archive/refs/tags/v5.1.107.102.tar.gz | `36fb68838d86e491bc577064e23d365ea936e03ded4e90f62dc540907c04f385` |
| talloc 2.5.0 | https://www.samba.org/ftp/talloc/talloc-2.5.0.tar.gz | `912afa237510ae542a7733998eb18a12bcda35ab6729c8e2ddb43e8d0ebab007` |

The script downloads both into a fresh temp folder and stops if either SHA-256 does not match. It makes one change to
the proot source: it adds `#include <string.h>` to `src/extension/ashmem_memfd/ashmem_memfd.c`, which calls `strcmp` and
`memset` without it. The NDK's clang treats an implicit declaration as an error.

`cross-answers.txt` is copied verbatim from Termux's
[`packages/libtalloc/build.sh`](https://github.com/termux/termux-packages/blob/master/packages/libtalloc/build.sh).

## Toolchain

- Android NDK `27.1.12297006`, `aarch64-linux-android26-clang`, with `llvm-ar`, `llvm-strip`, `llvm-objcopy` and
  `llvm-objdump` from the same NDK. The build calls a bare `readelf`, so the script links it to the NDK's `llvm-readelf`.
- Host: macOS (`darwin-x86_64` prebuilts) or Linux (`linux-x86_64`). Also needs python3 (talloc's waf), make and curl.

## Build

```sh
ANDROID_HOME=/path/to/sdk mobile-app/android/sandbox/native/build-proot.sh
```

What it runs:

1. **talloc**, static, as Termux builds it:
   - `CC=… ./configure --disable-rpath --disable-python --cross-compile --cross-answers=cross-answers.txt`
   - `make`
   - In `bin/default`: `llvm-ar rcs libtalloc.a talloc.c.6.o lib/replace/replace.c.2.o lib/replace/closefrom.c.2.o`.
     These are the objects waf links into `libtalloc.so`. Termux's archive holds only `talloc*.o`, but its proot links
     the shared library. Linked statically, talloc 2.5.0 also needs its built-in libreplace (`rep_memset_explicit`).
2. **proot**, with every flag passed as an exported environment variable, so the makefile's own `+=` appends stay:
   ```sh
   export CC AR STRIP OBJCOPY OBJDUMP
   export PROOT_UNBUNDLE_LOADER=/nonexistent
   export CPPFLAGS="-I$TALLOC -DARG_MAX=131072 -DVERSION=\\\"5.1.107.102\\\""
   export LDFLAGS="-L$TALLOC -Wl,-z,max-page-size=16384 -Wl,-z,common-page-size=16384"
   export LOADER_LDFLAGS="-Wl,-z,max-page-size=16384"
   export GIT_DIR=/nonexistent   # build.h's `git describe` must not find a surrounding repository
   make -C src proot HAS_LOADER_32BIT=
   ```
   - `PROOT_UNBUNDLE_LOADER=/nonexistent`: the loader is not embedded in proot. The app always sets `PROOT_LOADER` to
     `nativeLibraryDir/libproot-loader.so`.
   - `HAS_LOADER_32BIT=`: no 32-bit loader. The guest is arm64 only.
   - Not built with `PROOT_WITH_LIBANDROID_SHMEM`. proot's own sysvipc extension covers SysV IPC.
3. Copy `src/proot` to `libproot.so` and `src/loader/loader` to `libproot-loader.so`, run `llvm-strip` on both, and
   write `SHA256SUMS`.

The build is reproducible: runs in different temp folders give byte-identical files. This was shown on macOS with the
NDK 27.1 `darwin-x86_64` prebuilts; a Linux host (`linux-x86_64` prebuilts) has not been checked against `SHA256SUMS`.

### The loader's layout

The loader is static, with its code and entry point at `0x5400000000`. The makefile asks lld for `--rosegment`, so lld
also emits a 0x120-byte read-only segment holding only the ELF and program headers at its default image base,
`0x200000`. Termux's own `proot_5.1.107.102_aarch64.deb` loader has the same two segments. Nothing reads that page at
run time.

## Licenses

- proot is GPL-2.0-or-later (`licenses/GPL-2.0.txt`).
- talloc and the libreplace files linked with it (`replace.c`, `closefrom.c`) are LGPL-3.0-or-later
  (`licenses/LGPL-3.0.txt`). The LGPL-3.0 is a set of extra permissions on the GPL-3.0, so `licenses/GPL-3.0.txt`
  ships too.
- talloc is linked statically into `libproot.so`, so the combined binary is distributed under the GPL-3.0.
  `libproot-loader.so` is proot code only (GPL-2.0-or-later).

The corresponding source is the two pinned tarballs above plus this folder (`build-proot.sh`, `cross-answers.txt`).
See "Decisions for the user" in `docs/superpowers/plans/2026-11-09-mobile-m4-sandbox.md`.
