commit 9b9d44c384f8a7cf652e0b5d73f015a206b8190e Author: Jason Thistlethwaite Date: Fri May 1 06:48:52 2026 -0400 Initial commit diff --git a/README.md b/README.md new file mode 100755 index 0000000..2b44618 --- /dev/null +++ b/README.md @@ -0,0 +1,52 @@ +## AppArmor bwrap fix + +Ubuntu 24.04 and later can restrict unprivileged user namespaces through +AppArmor. When that restriction applies to Bubblewrap, tools that use `bwrap` +for sandboxed execution may fail before the intended command starts. + +One common symptom is: + +```text +bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted +``` + +This project installs a small AppArmor profile for `/usr/bin/bwrap` that keeps +the profile otherwise unconfined while explicitly allowing user namespace +creation. + +## Install + +Review the profile first: + +```bash +sed -n '1,120p' profiles/usr.bin.bwrap +``` + +Install and reload it with: + +```bash +sudo ./install.sh +``` + +The installer copies `profiles/usr.bin.bwrap` to +`/etc/apparmor.d/usr.bin.bwrap` and reloads it with `apparmor_parser -r`. + +## Verify + +Run: + +```bash +./verify.sh +``` + +The verifier prints the relevant namespace sysctls, checks that the bwrap +profile is installed, and runs a minimal Bubblewrap smoke test. + +## Security notes + +This does not change system sysctl settings. It adds a targeted AppArmor profile +for `/usr/bin/bwrap` with the `userns` permission needed by Bubblewrap on +affected Ubuntu systems. + +The profile is intentionally limited to bwrap. Browser-specific profiles and +per-user home directory paths are out of scope for this project. diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..41b124b --- /dev/null +++ b/install.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ ${EUID} -ne 0 ]]; then + echo "Run as root: sudo ./install.sh" >&2 + exit 1 +fi + +if ! command -v apparmor_parser >/dev/null 2>&1; then + echo "apparmor_parser is required but was not found" >&2 + exit 1 +fi + +repo_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +profile_dir="${repo_dir}/profiles" +target_dir="/etc/apparmor.d" + +profiles=( + "usr.bin.bwrap" +) + +for profile in "${profiles[@]}"; do + source="${profile_dir}/${profile}" + target="${target_dir}/${profile}" + + if [[ ! -f "${source}" ]]; then + echo "Missing profile template: ${source}" >&2 + exit 1 + fi + + install -m 0644 -o root -g root "${source}" "${target}" + apparmor_parser -r "${target}" + echo "Loaded ${target}" +done + +echo "Targeted AppArmor user namespace profile installed." +echo "No sysctl settings were changed." diff --git a/profiles/usr.bin.bwrap b/profiles/usr.bin.bwrap new file mode 100755 index 0000000..96514b0 --- /dev/null +++ b/profiles/usr.bin.bwrap @@ -0,0 +1,11 @@ +abi , +include + +# Give bubblewrap a named AppArmor profile that is otherwise unconfined, but +# explicitly allows user namespace creation on Ubuntu 24.04+. +profile bwrap /usr/bin/bwrap flags=(unconfined) { + userns, + + # Site-specific additions and overrides. See /etc/apparmor.d/local/README. + include if exists +} diff --git a/verify.sh b/verify.sh new file mode 100755 index 0000000..371ec0a --- /dev/null +++ b/verify.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "== AppArmor namespace sysctls ==" +sysctl kernel.apparmor_restrict_unprivileged_userns kernel.unprivileged_userns_clone + +echo +echo "== Profile files ==" +profile="/etc/apparmor.d/usr.bin.bwrap" +if [[ -f "${profile}" ]]; then + echo "present: ${profile}" +else + echo "missing: ${profile}" +fi + +echo +echo "== bubblewrap smoke test ==" +/usr/bin/bwrap \ + --ro-bind /usr /usr \ + --ro-bind /bin /bin \ + --ro-bind /lib /lib \ + --ro-bind /lib64 /lib64 \ + /bin/true +echo "bwrap smoke test passed"