Open-source project
proot-me/proot avatar
proot-me/proot

proot: user-space chroot and binfmt_misc on Linux without root

chroot, mount --bind, and binfmt_misc without privilege/setup for Linux

2,631 stars490 forksCGPL-2.0

At a glance

What is it?
PRoot intercepts the system calls of the programs it launches through ptrace, so you can chroot into a rootfs, bind mount paths and register binfmt handlers as an ordinary user. The repository also ships CARE, an Android package installer built on the same machinery.
Who is it for?
PRoot earns its place when you need a foreign userland, a bind mount or a binfmt handler and have no root, which is the situation on a shared build box or a phone. It is the wrong tool when you need kernel isolation, because everything is enforced by interception rather than by the kernel.
Can I use it commercially?
Yes, with conditions. GPL-2.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 21 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • proot-me/proot2,631 ★ · +11
Star history
Repository2026-10-072026-10-22
proot-me/proot2.6k2.6k

11 Stars in the last 15 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Interception instead of privileges

The repository description is the whole thesis in one line: chroot, mount --bind, and binfmt_misc without privilege or setup for Linux. GitHub reports the language as C and the topics line up with the mechanism rather than the goal: c, chroot, chroot-environment, linux, ptrace, rootfs, syscalls and userland-exec.

That topic list is the honest description of what PRoot is. It does not ask the kernel for a new mount namespace. It sits between your program and the kernel using ptrace, and the translation happens in userspace. Everything the program believes about its filesystem, about which binaries are recognised by extension, and about what a given path resolves to can be rewritten on the way through.

The consequence is worth being blunt about, because it is the whole trade. Isolation is advisory rather than enforced. The tracer decides what the tracee sees, which means PRoot protects you from a rootfs being confused, not from a determined attacker who knows how the interception works. The repository also carries a `doc/` directory with separate manuals for PRoot and for CARE, which is where the actual behavioural contract lives.

Three make invocations build the loader before anything else

The README's build section is three commands, and the order matters because the first one produces the artefacts the later steps link against. PRoot ships as a set of program-specific loaders rather than one binary:

bash
make -C src loader.elf loader-m32.elf build.h
make -C src proot care
make -C test

The first target builds `loader.elf`, a 32-bit variant `loader-m32.elf`, and a generated `build.h` of configuration. The second builds the `proot` executable and `care`, the Android package installer. The third runs the test suite. The README annotates the first two lines as building the config and loader first, and compiling PRoot and CARE second.

The dependency list is short and specific: libarchive, libtalloc, and uthash, the last of which the README says is only required for building CARE. That is a much lighter dependency set than a container runtime or a full virtualisation stack, which is the practical reason people pick this approach on a locked-down machine.

The same interception powers Android package installation

CARE is the more interesting half of the repository, and it explains a lot about where PRoot is actually used. CARE is a package installer in the shape of an Android app, and it is built on the same syscall interception as PRoot. When you run an Android package on a desktop Linux machine without an emulator, CARE maps the app's expected paths into a directory tree with ptrace and bind mounts.

That combination is why the terms `binfmt_misc` and `userland-exec` appear together. Registering a binfmt_misc handler normally means writing to a system path and having the kernel recognise a file type. PRoot can intercept that registration and apply it only to the process tree it supervises, so a foreign executable format becomes usable inside the traced session without touching host configuration.

The repository tree supports the reading: `src/` for the implementation, `lib/` for support code, `contrib/` for extras, `test/` for the suite, `util/` for helpers, and separate documents under `doc/`. The README also links an asciinema recording of the build, which is a reasonable way to see the sequence without installing anything.

Version history has a long quiet stretch

The release list reads oddly at first glance. GitHub reports v5.4.1 published 2026-09-08, v5.4.0 published 2023-05-13 and v5.3.1 published 2022-04-24. So the most recent tag is a patch on a minor line whose predecessor is three years old. The last push was 2026-09-21, ten days after the v5.4.1 tag, so work is landing on the branch even though the minor version has not moved.

A project with a three year gap between minor releases is telling you something about its maintenance rhythm. The README's own build status block still asks for input through a 2023 usage survey, and the CI badge points at a GitLab pipeline at gitlab.com/proot/proot while the source of record here is a GitHub repository under the proot-me organisation. Two hosts for one project is common enough among research-adjacent C code, and it does mean the badge and the release tag you can see may be produced by different automation.

For an adopter, the practical reading is that PRoot is a mature, slow-moving project rather than an abandoned one. `CHANGELOG.rst` sits at the root next to `HACKING.rst` and `COPYING`, and `sonar-project.properties` in the tree suggests static analysis is part of the pipeline.

A licence identifier that does not quite line up

There is a small inconsistency worth flagging because it affects anyone automating a compliance check. GitHub reports the repository licence as GPL-2.0. The README's licence section states `SPDX-License-Identifier: GPL-2.0-or-later`, and points at the `COPYING` file in the repository root. Both statements describe GPL-2.0, and the README's form is the stricter and more precise one, since or-later means you may redistribute under GPL-2.0 or any later version while plain GPL-2.0 pins the version.

You do not have to pick between them for ordinary use. What matters is that the grant is GPL-2.0 rather than something permissive, which shapes what you can do with a binary you build. Linking PRoot into a closed-source product is a different proposition from linking a permissively licensed library into it, and the manual under `doc/proot/manual.rst` is where the usage terms are written out in full.

Support channels are the three you would expect for a project of this age: a mailing list at proot_me on Google Groups, a forum on the same group, and a Gitter chat. The README's Dependencies section is the other place to look if you are packaging PRoot, since CARE pulls in uthash on top of the shared requirements.

Choosing between PRoot, a user namespace and a container

The comparison worth making is with Linux user namespaces, since both approaches aim at the same goal: running something in a filesystem that is not the host's, without being root. The mechanisms are different in a way that shows up immediately in what you can do.

A user namespace gives you real kernel enforcement. Mounts inside it are real mounts, `chroot` is a real `chroot`, and a process that escapes its tree has escaped into a namespace the kernel still tracks. The catch is that unprivileged user namespaces have to be enabled and are frequently disabled by hardened kernels, distributions or container hosts, and where they are available you still need the mount points set up for you.

PRoot needs no kernel support and no configuration, which makes it the option that works on an Android phone, in a CI image where you cannot change sysctls, or on a shared machine where namespaces are switched off. What it gives up is enforcement: you are trusting the tracer, and the performance cost comes from trapping every system call rather than from a copy-on-write filesystem.

So the decision is about trust and environment rather than features. If you need the guest to be genuinely unable to reach the host, use namespaces or a container. If you need a working foreign userland on a machine where you cannot ask for anything, PRoot is still the more reliable of the two.

Editorial conclusion

PRoot earns its place when you need a foreign userland, a bind mount or a binfmt handler and have no root, which is the situation on a shared build box or a phone. It is the wrong tool when you need kernel isolation, because everything is enforced by interception rather than by the kernel. GitHub reports the last push on 2026-09-21 with v5.4.1 published 2026-09-08, so start from the release tarball and the manual in `doc/proot/manual.rst`, not from a fork.

Frequently asked questions

Is PRoot safe to use?

PRoot enforces what a program sees by intercepting its system calls with ptrace, so the isolation depends on the tracer rather than on the kernel. That is enough to keep a foreign rootfs from confusing the programs inside it, and it is not a security boundary against a program designed to escape one. The repository topics list ptrace, syscalls and userland-exec, and the manual under `doc/proot/manual.rst` documents the behaviour in detail.

What does PRoot need to build?

Three make invocations in order: `make -C src loader.elf loader-m32.elf build.h` to build the configuration and the program-specific loaders, then `make -C src proot care` to compile both binaries, then `make -C test` for the suite. External dependencies are libarchive and libtalloc, with uthash needed only for CARE.

What is CARE for, and how does it relate to PRoot?

CARE is an Android package installer that lives in the same repository and shares PRoot's interception mechanism. It maps the paths an Android package expects into a directory tree using ptrace and bind mounts, which lets such a package run on a desktop Linux machine without an emulator.

Official sources

  1. License: GPL-2.0
  2. Project website
  3. proot-me/proot on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/proot-me-proot.svg)](https://hysenlabs.com/projects/proot-me-proot)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/proot-me-proot.svg)](https://hysenlabs.com/projects/proot-me-proot)

Was this useful?