From eb5a0c04b422c3fb65cf6401627a4bbbd8d12a30 Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Tue, 23 Apr 2024 12:21:22 +0900 Subject: [PATCH] apparmor: add `signal (receive) peer=/usr/local/bin/rootlesskit,` Fix containerd/nerdctl issue 2730 > [Rootless] `nerdctl rm` fails when AppArmor is loaded: > `error="unknown error after kill: runc did not terminate successfully: exit status 1: > unable to signal init: permission denied\n: unknown"` Caused by: > kernel: audit: type=1400 audit(1713840662.766:122): apparmor="DENIED" operation="signal" class="signal" > profile="nerdctl-default" pid=366783 comm="runc" requested_mask="receive" denied_mask="receive" signal=kill > peer="/usr/local/bin/rootlesskit" The issue is known to happen on Ubuntu 23.10 and 24.04 LTS. Doesn't seem to happen on Ubuntu 22.04 LTS. Signed-off-by: Akihiro Suda --- contrib/apparmor/template.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/contrib/apparmor/template.go b/contrib/apparmor/template.go index 5869cffaa..76fd34811 100644 --- a/contrib/apparmor/template.go +++ b/contrib/apparmor/template.go @@ -29,6 +29,8 @@ import ( "path" "strings" "text/template" + + "github.com/containerd/log" ) // NOTE: This code is copied from . @@ -57,6 +59,10 @@ profile {{.Name}} flags=(attach_disconnected,mediate_deleted) { signal (receive) peer={{.DaemonProfile}}, # Container processes may send signals amongst themselves. signal (send,receive) peer={{.Name}}, +{{if .RootlessKit}} + # https://github.com/containerd/nerdctl/issues/2730 + signal (receive) peer={{.RootlessKit}}, +{{end}} deny @{PROC}/* w, # deny write for all files directly in /proc (not in a subdir) # deny write to files not in /proc//** or /proc/sys/** @@ -90,6 +96,7 @@ type data struct { Imports []string InnerImports []string DaemonProfile string + RootlessKit string } func cleanProfileName(profile string) string { @@ -125,6 +132,16 @@ func loadData(name string) (*data, error) { } p.DaemonProfile = cleanProfileName(string(currentProfile)) + // If we were running in Rootless mode, we could read `/proc/$(cat ${ROOTLESSKIT_STATE_DIR}/child_pid)/exe`, + // but `nerdctl apparmor load` has to be executed as the root. + // So, do not check ${ROOTLESSKIT_STATE_DIR} (nor EUID) here. + p.RootlessKit, err = exec.LookPath("rootlesskit") + if err != nil { + log.L.WithError(err).Debug("apparmor: failed to determine the RootlessKit binary path") + p.RootlessKit = "" + } + log.L.Debugf("apparmor: RootlessKit=%q", p.RootlessKit) + return &p, nil }