blob: 90c0590a53648cf84aada9b0520288931cfdb9ff [file]
# An AppArmor profile that lets amem create user namespaces.
#
# WHY THIS IS NEEDED
#
# Ubuntu 23.10 and later set kernel.apparmor_restrict_unprivileged_userns=1. That
# does not block user namespaces outright: it moves a binary with no profile of its
# own into a stub profile, `unprivileged_userns`, which has no CAP_SYS_ADMIN. So the
# namespace is created and then everything inside it that needs privilege fails. In
# the kernel audit log:
#
# apparmor="AUDIT" operation="userns_create" info="Userns create - transitioning
# profile" profile="unconfined" target="unprivileged_userns"
# execpath="/home/you/.cargo/bin/amem"
# apparmor="DENIED" operation="capable" profile="unprivileged_userns"
# capability=21 capname="sys_admin"
#
# Without a profile, `amem launch` fails at the first mapping:
#
# amem: sandbox: confinement: /proc/self/setgroups: Permission denied
# error: confinement: spawn /opt/memory/memory: Invalid argument (os error 22)
#
# WHAT THIS GRANTS
#
# `flags=(unconfined)` means this profile mediates nothing: amem is as unconstrained
# as it was before. The profile exists only so that amem HAS one, which keeps the
# userns transition from happening, and `userns,` is the single permission it adds.
#
# This is narrower than the alternative. Setting
# kernel.apparmor_restrict_unprivileged_userns=0 grants user namespaces to every
# unprofiled binary on the machine; this grants them to one path.
#
# INSTALL
#
# sudo install -m 644 packaging/apparmor/amem /etc/apparmor.d/amem
# sudo apparmor_parser -r /etc/apparmor.d/amem
#
# Then `amem doctor` should report `backend / user namespaces` as passing.
#
# @{HOME} comes from tunables/home, included by tunables/global, and expands to each
# home directory on the host, so this is not tied to one user. Two profiles because
# the installed binary and the one `make launch` runs are different files.
abi <abi/4.0>,
include <tunables/global>
# `cargo install --path crates/memory`, or `make install`
profile amem @{HOME}/.cargo/bin/amem flags=(unconfined) {
userns,
include if exists <local/amem>
}
# `cargo build --release`, which is what the Makefile's targets run
profile amem-build @{HOME}/**/target/{release,debug}/amem flags=(unconfined) {
userns,
include if exists <local/amem>
}