{"id":51873459,"url":"https://github.com/1ay1/linuxity","last_synced_at":"2026-07-25T03:00:51.900Z","repository":{"id":372006635,"uuid":"1304272194","full_name":"1ay1/linuxity","owner":"1ay1","description":"A portable, type-theoretic C++23 implementation of the Linux userspace ABI — run native distro binaries at native speed via a ptrace+seccomp kernel-substitute, no VM, no emulation.","archived":false,"fork":false,"pushed_at":"2026-07-18T08:45:21.000Z","size":584,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-07-18T09:17:37.413Z","etag":null,"topics":["abi","container","cpp23","linux","ptrace","rootfs","sandbox","seccomp","syscall","userspace"],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/1ay1.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-07-17T18:12:26.000Z","updated_at":"2026-07-18T08:45:28.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/1ay1/linuxity","commit_stats":null,"previous_names":["1ay1/linuxity"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/1ay1/linuxity","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1ay1%2Flinuxity","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1ay1%2Flinuxity/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1ay1%2Flinuxity/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1ay1%2Flinuxity/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/1ay1","download_url":"https://codeload.github.com/1ay1/linuxity/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1ay1%2Flinuxity/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35863583,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-25T02:00:06.922Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["abi","container","cpp23","linux","ptrace","rootfs","sandbox","seccomp","syscall","userspace"],"created_at":"2026-07-25T03:00:51.243Z","updated_at":"2026-07-25T03:00:51.892Z","avatar_url":"https://github.com/1ay1.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# linuxity\n\nA **portable, type-theoretic implementation of the Linux userspace ABI**.\n\nNot a VM. Not instruction emulation. `linuxity` is a userspace\nre-implementation of the Linux kernel/user contract: guest ELF binaries run\n**directly on the host CPU at native speed** while the runtime *is the\nkernel* — it services their syscalls.\n\nThe distro you install is decoupled from the instruction set:\n\n| | what it is | runs at |\n|---|---|---|\n| **the environment** | an Arch / Alpine / Debian rootfs — files, `/proc`, the package manager, the ABI contract | — |\n| **the guest code** | ELF binaries in that rootfs | **native CPU speed** |\n| **the ISA** | whatever the host is (x86-64 here) | native — no emulation |\n\nSo on an x86-64 host you install the **x86-64 build** of the distro and every\ninstruction runs bare on the CPU — no VM, no `/dev/kvm`, no interpreter. A\n*foreign*-arch rootfs is the only case that needs a binary-translation\nbackend (FEX / Rosetta-style), and that plugs in behind the same ABI at the\nISA boundary — it is not the core.\n\n```\n            Linux program (AArch64 ELF)\n                      │\n             Linux syscall ABI            ← abi/syscall.hpp\n                      │\n        ┌──────────────────────────┐\n        │        Kernel            │      ← the *product* of subsystems\n        │  VFS · Process · Memory  │      ← kernel/subsystem.hpp (concepts)\n        │  IPC · Net · /proc · …   │\n        └──────────────────────────┘\n             │        │        │\n          PosixHost  Darwin   Windows      ← host/host.hpp (a tiny concept)\n             │        │        │\n          Linux    macOS/iOS  Windows\n```\n\nThe guest **only ever talks to the runtime**, never the host OS.\n\n## The design, in types\n\n| Idea | Encoded as |\n|------|-----------|\n| A syscall is a total function `Args → Errno + Value` | `Result\u003cT\u003e = std::expected\u003cT, Errno\u003e` |\n| errno can't be confused with a value/fd/pid | `enum class Errno`, strong `Id\u003cTag\u003e` newtypes |\n| `read` / `write` / `open` / `mount` are one subsystem | `concept Vfs` |\n| the kernel is the *product* of subsystems | `concept IsKernel = Vfs \u0026\u0026 Process \u0026\u0026 Memory` |\n| the host is a swappable primitive layer | `concept Host` (static polymorphism, zero vtables) |\n| a guest pointer must never be dereferenced un-validated | `UAddr` / `UserPtr\u003cT\u003e` — un-dereferenceable by construction |\n| do-notation / `?` for error propagation | `LX_TRY(expr)` |\n\nBecause subsystems and the host are **concepts**, the syscall dispatcher and\nthe whole runtime are written *once, generically*, and instantiated against:\nthe production kernel, a host-free `MockKernel` in tests, or a future\nJIT-backed kernel — with no virtual dispatch in the hot path.\n\n## Layout\n\n- `include/linuxity/abi/`    — `result.hpp`, `types.hpp`, `syscall.hpp`\n- `include/linuxity/kernel/` — `subsystem.hpp` (concepts), `authority.hpp` (the host-authority boundary), `file_namespace.hpp` (mount table + cwd + fd table + realm classifier), `kernel.hpp`\n- `include/linuxity/vfs/`    — `inode.hpp` (FileSystem concept), `tmpfs.hpp` (in-memory backend), `hostfs.hpp` (on-disk rootfs backend), `procfs.hpp` (synthesized /proc), `vfs.hpp` (mount table + path resolution)\n- `include/linuxity/host/`   — `host.hpp` (the concept), `posix_host.hpp` (Linux/Darwin backend)\n- `src/main.cpp`             — wires host → kernel → ABI, issues guest syscalls\n- `tests/`                   — host-free type-algebra, authority, and VFS tests\n\n## Build\n\n```sh\ncmake -S . -B build -G Ninja\ncmake --build build\nctest --test-dir build\n\n# run a NATIVE Linux binary under the runtime (native speed, no VM):\n./build/linuxity /path/to/binary [args...]\n\n# ...including real distro binaries with the dynamic linker:\n./build/linuxity /usr/bin/uname -a\n#   -\u003e Linux linuxity 6.6.0-linuxity #1 linuxity portable Linux ABI x86_64\n./build/linuxity /usr/bin/id\n#   -\u003e uid=0(root) gid=0(root) ...      (identity VIRTUALIZED by linuxity)\n\n# mount an extracted distro rootfs as the guest '/' (UNPRIVILEGED — no\n# chroot, no root): every guest path is translated to the real host path\n# under the rootfs before the syscall runs; /proc is synthesized.\n./build/linuxity --root ./alpine-rootfs /bin/sh\n\n# proof the guest lives in the rootfs, not the host:\n./build/linuxity --root ./my-rootfs /bin/cat /etc/os-release\n#   -\u003e the ROOTFS os-release, even though the host's is different\n./build/linuxity /bin/cat /proc/version\n#   -\u003e Linux version 6.6.0-linuxity (linuxity@linuxity) ...  (SYNTHESIZED)\n```\n\nRequires a C++23 compiler (`std::expected`, concepts). Tested with GCC 16.\nNative execution uses a `ptrace` trap backend on Linux/x86-64: the guest runs\nits own instructions on the CPU; each syscall is either **virtualized** by\nlinuxity's subsystems or **forwarded** to the host kernel acting on the guest.\n\n## Documentation\n\n- **[doc/MANUAL.md](doc/MANUAL.md)** — the user manual: install, get a rootfs,\n  every CLI flag and environment variable, a task cookbook, resource limits,\n  bind mounts, DNS, fake-root, package managers, troubleshooting, and an FAQ.\n  **Start here to *use* linuxity.**\n- **[doc/ARCHITECTURE.md](doc/ARCHITECTURE.md)** — the internals: the trap\n  backend, syscall fates, the seccomp fast path, the filesystem namespace and\n  copy-on-write overlay, shadow-metadata fake-root, the pid namespace, signals,\n  synthesized `/proc`/`/sys`/`/dev`, the loader/exec rewriting, resource\n  governance, and how to extend it. **Read this to *understand* linuxity.**\n- **[doc/reference-study.md](doc/reference-study.md)** — how the techniques map\n  from proot / termux-exec / proot-distro / ish onto linuxity, and why.\n\n## Status\n\n**Real native Linux binaries — including dynamically-linked distro programs —\nrun under the runtime today, and the guest's ENTIRE filesystem view is now\nlinuxity's own virtual namespace.** `/bin/echo`, `/usr/bin/id`,\n`/usr/bin/uname`, `date`, `cat` all execute natively on the CPU while\nlinuxity services their syscalls. Proofs of the model:\n\n- `uname -a` reports **`Linux linuxity 6.6.0-linuxity`** (not the host\n  kernel) — we intercept `uname`, synthesize linuxity's identity, and\n  `copy_out` into the guest buffer.\n- `id` / `whoami` report **`uid=0(root)`** — virtualized `getuid`/`getgid`\n  return the virtual world's root.\n- `cat /proc/version` reports **`Linux version 6.6.0-linuxity`**,\n  `/proc/self/status` reports **`Pid: 1`, `Uid: 0`**, `/proc/mounts` reports\n  **linuxity's** mount table — `/proc` is fully **synthesized**, not the host's.\n- `--root \u003crootfs\u003e /bin/cat /etc/os-release` reads the **rootfs** file, not\n  the host's — and needs **no privilege and no chroot**.\n- `--root \u003crootfs\u003e /bin/sh -c '/bin/cat /etc/os-release | /bin/head -1'` runs a\n  **shell that forks and execs coreutils**, and every child stays inside the\n  rootfs — the whole process tree lives in linuxity's world, no host escape.\n- the guest can **write** (`/tmp`, `/run`, `/var`, …) and the writes land in a\n  copy-on-write **overlay upper** layer — the on-disk rootfs stays **pristine**,\n  never mutated by the guest.\n- **`htop` and `top` run as real process monitors** — they read linuxity's\n  synthesized `/proc/stat`, `/proc/meminfo`, `/proc/uptime`, `/proc/loadavg`\n  and `/sys` (CPU topology, cpufreq, hwmon temperatures), enumerate `/proc`\n  and each `/proc/\u003cpid\u003e/task/\u003ctid\u003e` (virtualized `getdents64`), and render the\n  **live process tree**: run a shell that backgrounds `sleep`/`yes` and `htop`\n  shows every one with its real command line — `sh`, `sleep 10`, `yes`, `htop`\n  — because the trap feeds every fork/exec/exit into linuxity's process table.\n  `free`, `uptime`, `ls /proc`, `ls /proc/1` all work the same way.\n- **Signals reach the right task.** A guest `kill`/`tgkill`/`tkill` names a pid\n  in *linuxity's* namespace, so the raw number is never forwarded (it would\n  signal an unrelated host task). The runtime translates the target to the\n  traced task's real host tid and delivers the signal there — a shell can\n  background `sleep 30 \u0026` then `kill`/`kill -9` it, `kill -0` probes liveness,\n  and an unknown pid returns `ESRCH`. Signal **dispositions and masks**\n  (`rt_sigaction`/`rt_sigprocmask`) are forwarded to the real task, so a guest\n  `SIGTERM` handler actually **runs** instead of the process being killed.\n- **Every task has a coherent identity.** `getpid`/`gettid`/`getppid`/\n  `getpgid`/`getsid`/`setsid` answer from the trap's live task map, so a forked\n  child sees its *own* pid with its parent's pid — not a fixed “pid 1”. init is\n  pid 1 with ppid 0.\n- **`/proc/self/exe` (and `\u003cpid\u003e/exe`, `cwd`, `root`) are synthesized** against\n  linuxity's namespace, so a dynamic loader or runtime that finds its own\n  binary reads the guest path (`/bin/foo`), never the host path.\n- **Shell pipelines work.** `echo a b | wc -w`, `... | tr ... | wc -l`, loops,\n  `awk`, backgrounded jobs — the whole forked pipeline stays in linuxity's\n  namespace and its members signal, wait on, and enumerate each other correctly.\n- **A real distro runs.** Point `--root` at an extracted **Alpine** (musl)\n  rootfs and `/bin/sh`, `/bin/ls`, `/bin/cat`, `busybox` and friends all run:\n  dynamically-linked PIE binaries load through their **translated PT_INTERP**\n  (the musl/glibc dynamic linker), absolute rootfs **symlinks** (`/bin/sh -\u003e\n  /bin/busybox`) re-root inside the rootfs, and nested `execve`s of dynamic\n  programs are rewritten the same way — so a shell spawns real coreutils.\n  `uname -a` reports linuxity, `cat /etc/alpine-release` reads the real distro\n  file, `id` is root, a pipeline of 82 busybox applets counts correctly.\n- **The guest sees a root-owned world.** A rootfs unpacked by an unprivileged\n  user is owned on disk by *that* user, and a host-backed `stat` is redirected,\n  so the host kernel fills the guest buffer with the host owner. linuxity\n  scrubs the owner fields to `0` in the same stopped syscall-exit window (a\n  post-redirect hook, before the task can read the buffer and race the write),\n  so `ls -la` shows **`root root`** for every entry and a monitor's USER column\n  reads `root` — the world is coherently owned by init, not the box's user.\n- **A package manager installs into the world, and the installed program\n  runs.** Alpine's real `apk` — reading its installed DB through the namespace,\n  extracting a `.apk`, writing files, `chmod`/`chown`ing them, running triggers,\n  updating the database — installs a package end to end (`OK: N packages`), and\n  the freshly-written binary then executes and walks the rootfs. This works\n  because the **whole mutating-path syscall family** (`mkdir`, `rmdir`,\n  `unlink`, `rename`, `link`, `symlink`, `chmod`, `chown`, `truncate`,\n  `utimensat`, `mknod`, and their `*at` forms) translates each guest path to\n  the copy-on-write **overlay upper** layer — never the host's own `/usr`,\n  `/etc` — with two-path ops (`rename`/`link`) rewriting *both* operands and\n  `chown`-to-root accepted as a vacuous no-op (the world is already root-owned,\n  the host process is unprivileged). The pristine lower rootfs is never touched.\n- **`/dev` is a populated devtmpfs.** A bare rootfs ships an empty `/dev`, so\n  every program that reaches for `/dev/null`, `/dev/zero`, `/dev/urandom` or the\n  stdio nodes used to die on `can't open '/dev/null'`. linuxity synthesizes a\n  `/dev` that **redirects the character devices to the host's real nodes** —\n  the guest opens the true `/dev/null` (endless sink), `/dev/zero`, `/dev/urandom`\n  (real CSPRNG) with native `read`/`write`/`mmap` semantics — and wires\n  `/dev/std{in,out,err}` → `/proc/self/fd/{0,1,2}` so a shell's `\u003e /dev/stdout`\n  reaches the real fd. Zero emulation: the devices are real, we just mount them.\n- **`#!` scripts run without double-rooting.** A rootfs scriptlet like\n  `#!/bin/sh -e` used to have the host kernel relaunch its interpreter with the\n  *host-translated* script path, which linuxity then re-translated\n  (`\u003crootfs\u003e/\u003crootfs\u003e/...`). Now the exec dispatcher resolves the shebang\n  itself and execs the interpreter — chaining its `ld.so` when the interpreter\n  is dynamic — with the script as a **guest** path, so `openat` redirects it\n  cleanly. Cross-mount **symlinks** resolve too: `/etc/mtab -\u003e /proc/self/mounts`\n  crosses from the rootfs into the virtual `/proc`, and following it lands in\n  the virtual realm instead of fabricating a nonexistent host path.\n- **Arch's `pacman` installs a package from the network, end to end.** On a\n  real Arch/glibc bootstrap rootfs, glibc `bash` and `pacman` run, and\n  `pacman -Sy \u003cpkg\u003e --noconfirm` **downloads the repo databases, resolves\n  dependencies, downloads the package, and installs it**: the binary lands in\n  the overlay, the package DB entry is written, and the post-transaction\n  **systemd hook** (a `#!/bin/sh` scriptlet) runs. Networking is fully native —\n  DNS, TLS, and HTTP are forwarded to the host kernel, identical to bare metal.\n  Two subtleties fell along the way: (1) pacman's **multi-threaded libcurl**\n  download workers create a short-lived wakeup `eventfd` and open the data file\n  nearly at once; in a bare `0,1,2`-only guest both raced for fd `3`, so a\n  sibling thread's 8-byte wakeup landed in `core.db` and corrupted it — fixed\n  by reserving the low descriptors in the child (mirroring a shell-launched\n  process that inherits open fds). (2) `pacman -U \u003cpkg\u003e.pkg.tar.zst` installs a\n  local package the same way. pacman 7's download **sandbox** (`DownloadUser`,\n  Landlock, seccomp) is accepted vacuously — setuid/Landlock are no-ops because\n  linuxity's namespace already confines the guest — but the sandbox's forked\n  download child relays completion to the parent over a pipe whose commit step\n  is the remaining frontier; with the standard in-process download path it all\n  works.\n\n### How the filesystem is virtualized\n\nEvery path-taking syscall (`openat`, `newfstatat`, `statx`, `access`,\n`readlinkat`, `chdir`, `getcwd`, …) is resolved through a **`FileNamespace`**\n— a mount table + guest cwd + guest-fd table — and classified into one realm:\n\n- **host-backed** (a rootfs mount): the guest path is translated to the real\n  host path under the rootfs, and the syscall is **redirected** (its path\n  register is rewritten in the child, then forwarded). Because the child ends\n  up with a real host fd, native `ld.so` `mmap`s the actual library file —\n  this is what carries a dynamically-linked distro binary to `main()`. A\n  write-intent open (`O_WRONLY`/`O_RDWR`/`O_CREAT`/`O_TRUNC`) resolves to a\n  copy-on-write **overlay upper** dir (copying the file up from the read-only\n  lower first), so the pristine rootfs is never mutated. The full **mutation\n  family** (`mkdir`/`rmdir`/`unlink`/`rename`/`link`/`symlink`/`chmod`/`chown`/\n  `truncate`/`utimensat`/`mknod` and their `*at` forms) redirects the same way:\n  each guest path resolves to the overlay upper layer, directories that exist\n  only in the read-only lower are mirrored up on first child-write, two-path\n  ops rewrite both operands, and a `symlink`'s literal target is preserved as a\n  guest path (resolved later through the namespace, not the host).\n- **virtual** (`/proc`, `/sys`, and future tmpfs, overlays): the bytes are\n  synthesized and either written straight into guest memory (`read`/`stat`/\n  `statx`) or materialized into a real fd the child can read *and* `mmap`\n  (**inject**). A virtual **directory** is backed by a real empty temp dir (so\n  `O_DIRECTORY` opens succeed) and its `getdents64` is fully virtualized — the\n  entries are synthesized from linuxity's state.\n\n`/proc` is comprehensive: `/proc/{stat,meminfo,cpuinfo,uptime,loadavg,version,\ncmdline,filesystems,mounts,sys/...}` plus the per-process tree\n`/proc/\u003cpid\u003e/{stat,statm,status,cmdline,comm,io,maps,task/\u003ctid\u003e/...}`, all\ngenerated from linuxity's **process table** (pid 1 = init, uid 0, its own\nnumbers). Host-backed `stat`/`statx` are redirected but their **owner fields\nare scrubbed to `0`** afterwards, so a rootfs unpacked by an unprivileged user\nstill presents as root-owned. `/sys` is synthesized too — CPU topology (`devices/system/cpu`,\n`cpufreq/policyN/scaling_cur_freq`), `hwmon` temperatures, one virtual block\ndevice, cgroup v2 stubs — so a hardware monitor discovers linuxity's virtual\nmachine, not the box it runs on. That is why a process/hardware monitor shows\nlinuxity's world.\n\nSo the guest never sees the host tree: `--root` makes `/` the rootfs and\n`/proc` reports linuxity's world — all with zero privilege, no VM, no chroot.\n\n**The trap traces the whole process tree.** A real shell forks and execs\nchildren and blocks in `wait4()`/`read()` on them, so the `ptrace` backend is\nmulti-process and event-driven: it traces every descendant\n(`PTRACE_O_TRACEFORK|VFORK|CLONE|EXEC`), waits on any task, and never blocks on\none while another can run — so a parent's blocking `wait4` doesn't deadlock its\nchild. Each task's syscall entry/exit is told apart robustly by the kernel's\n`rax == -ENOSYS` entry priming. A forked `cat` in a pipeline therefore lives in\nexactly the same virtual namespace as its parent shell; it never escapes to\nthe host filesystem.\n\nMemory (`mmap`/`brk`/`mprotect`) stays forwarded so native libc reaches\n`main()`; identity, credentials, lifecycle, `uname`, **signal delivery**,\n**per-task pid/session identity**, **`/proc` symlinks**, and now the **whole\nfile path — reads AND mutations** — are virtualized. In place and proven by\n18 test suites:\n\n- the type algebra, subsystem concept lattice, and authority boundary;\n- a real **VFS** (mount table, path resolution) with **tmpfs** and a\n  **HostFs** backend, plus the **`FileNamespace`** the syscall path routes\n  through and a synthesized **procfs**;\n- an **ELF64 loader** (PT_LOAD, .bss zero-fill, PT_INTERP) into a typed guest\n  **address space**, plus SysV AMD64 **stack/auxv** init;\n- an arch-neutral **syscall dispatcher** (per-arch tables → canonical `Sysno`)\n  with a **virtualize / forward / redirect / inject / signal** classifier,\n  driven by a concept-based **trap** loop and a real **multi-process** `ptrace`\n  backend that traces the entire forked/exec'd process tree.\n\n**The live process tree feeds `/proc`.** The `ptrace` backend observes every\nfork/vfork/exec/exit in the guest tree and emits neutral lifecycle events; the\nexecution loop folds them into the kernel's process table (mapping host tids to\nlinuxity's own tiny pid space, root = pid 1, real argv captured at `exec`). So\n`/proc` — and every monitor reading it — reflects linuxity's real, live\nprocesses, not the host's.\n\n### Bounding the guest: two numbers, kept equal\n\nlinuxity is an ABI translator, not a hypervisor, so it never *partitions*\nhardware — the guest runs native and draws memory/CPU straight from the host's\nglobal pool via **forwarded** `mmap`/`brk`. But because the guest is a real\nhost process tree, it is **cgroup-able like any other process**, so \"how much\nit gets\" becomes a policy the host kernel enforces:\n\n```\nlinuxity --root /alpine --memory 512M --cpus 2 --pids 256 /sbin/apk add ...\n```\n\nThere are **two** numbers a program cares about, and linuxity keeps them equal:\n\n- **Belief** — what the guest *reads* (`sysinfo`, `/proc/meminfo`,\n  `/proc/cpuinfo`, `sched_getaffinity`), so it sizes its caches and thread\n  pools sensibly. This comes from the `MachineSpec`.\n- **Enforced reality** — what the host kernel actually *lets* it consume.\n\nA single `ResourceSpec` drives BOTH: it (a) writes the host-side bound and (b)\n**derives** the `MachineSpec` the guest sees (`--memory 512M` → `MemTotal:\n524288 kB`; `--cpus 2` → `nproc` = 2). So a program that sizes a cache to \"half\nof RAM\" fits inside `memory.max` instead of being OOM-killed — belief == the\nnumber you asked to be bounded to, by construction.\n\nEnforcement is **best-effort with graceful fallback** (the Docker-rootless /\nTermux discipline):\n\n1. **cgroup v2** — a `payload` cgroup under linuxity's own delegated subtree\n   gets `memory.max` / `cpu.max` / `pids.max` / `cpuset.cpus`. When the\n   session's controllers aren't yet delegated (the common unprivileged case),\n   linuxity **re-execs itself through `systemd-run --user --scope`** to obtain\n   a delegated scope, then moves itself into a `supervisor` leaf so it can\n   enable the controllers (cgroup v2's \"no internal processes\" rule). This is\n   the precise, kernel-enforced bound.\n2. **`setrlimit`** — where no cgroup can be created, `RLIMIT_AS` bounds address\n   space as a coarse memory ceiling. (`--pids` is deliberately NOT mapped to\n   `RLIMIT_NPROC`, which counts the whole login session, not just the guest\n   tree.)\n\nProven: a guest touching 800 MB under `--memory 256M` is stopped by the host\nkernel at ~240 MB (uncapped, the same binary reaches 800 MB); `--pids 32`\nstops a fork bomb at 32 tasks; `apk add` installs a package unbounded AND under\na 400 MB cap. The default (no flags) is fully unbounded native speed — the\nguest is just another host process.\n\nThe road ahead: overlay directory-read UNION (getdents merge of lower+upper),\nlive advancing `/proc` CPU counters, and richer `futex`/`epoll` coverage for\nheavily-threaded programs. The architecture is fixed and machine-checked.\n\n## A coherent uid-0 world (fake root, done right)\n\nThe host process is **unprivileged**, but the guest believes it is root — and\nthat belief has to survive a `stat`. Two holes the host filesystem can't back:\nownership (`chown 1000:1000 f` can't really change owner) and privileged mode\nbits (`chmod 4755 f` — the host may drop the setuid bit). linuxity closes them\nwith a **shadow metadata store** (`kernel/meta_store.hpp`): chmod/chown/fchmod/\nfchown RECORD the guest-intended `(mode, uid, gid)`, and every stat/lstat/statx/\nnewfstatat OVERLAYS them back onto the host inode result. So:\n\n```\nlinuxity --root /arch /usr/bin/bash -c \\\n  'touch /tmp/z; chmod 4755 /tmp/z; chown 1000:1000 /tmp/z; stat -c \"%a %u:%g\" /tmp/z'\n# -\u003e 4755 1000:1000\n```\n\nround-trips exactly — setuid bit and non-root owner intact — even though the\nreal inode never changed owner and the host would have dropped the setuid bit.\nWhere proot scatters a `.proot-meta-file.\u003cname\u003e` **sidecar** beside every\ntouched file (polluting the guest tree), linuxity keeps ONE consolidated\n`.linuxity-meta` journal in the overlay upper layer: never guest-visible,\npersists and replays across runs, with tombstones so unlink/rename stay exact.\n\n## Binding host directories in\n\n`--bind host[:guest]` exposes a real host directory inside the guest tree at\n`guest` (default: the same path) — proot's `-b`, bubblewrap's `--bind`, but\nriding linuxity's path-translation namespace (no privilege, no real `mount(2)`):\n\n```\nlinuxity --root /arch --bind ~/project:/work /usr/bin/bash\n# /work in the guest IS ~/project on the host; writes land on the real files.\n```\n\nBinds register after the rootfs, so a deeper or explicit bind wins by\nlongest-prefix and can even shadow a rootfs directory. It's a thin wrapper over\nthe same `FileNamespace::mount_host` the `--root` overlay already uses.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F1ay1%2Flinuxity","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F1ay1%2Flinuxity","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F1ay1%2Flinuxity/lists"}