apparmor: add signal and ptrace rules for stacked profiles#919
Conversation
With AppArmor 5.0+ (Ubuntu 25.10+), child processes inside containers get stacked profiles (e.g. containers-default//&crun). The existing signal and ptrace peer rules only match the base profile name, causing DENIED audit events that break systemd-based containers. Add //&* wildcard rules for signal and ptrace to match any stacked profile peer. Signed-off-by: Ayato Tokubi <atokubi@redhat.com> Assisted-by: Claude Code <https://claude.com/claude-code>
|
LGTM |
| signal (receive) peer=unconfined, | ||
| signal (send,receive) peer={{.Name}}, | ||
| # With AppArmor 5.0+, child processes get a stacked profile. | ||
| signal (send,receive) peer={{.Name}}//&*, |
There was a problem hiding this comment.
can you link to official docs for this syntax/change?
Also is this fully backwards compatible? What happens if the rule is loaded on apparmor 4 or earlier will the parser accept that?
There was a problem hiding this comment.
https://gitlab.com/apparmor/apparmor/-/wikis/Release_Notes_5.0.0
I can't find the release note about this change, but apparently AI found the change that caused the issue (sorry about just putting the AI result, but I believe it'll help).
According to the AI , torvalds/linux@a9eb185 this change caused the issue. The AI summary is below.
Details
What changed
Previously, x_to_label() in security/apparmor/domain.c only checked whether the first entry in the exec transition table started with & (the stacking marker).
If the first entry wasn't a stack, stacking was skipped entirely — even if a later entry that actually matched did start with &.
The fix checks the actually matched entry for the & prefix:
// Before: checked first entry only
stack = rules->file->trans.table[xindex & AA_X_INDEX_MASK];
if (*stack != '&') { /* skip stacking */ } // After: checks the matched entry
new = x_table_lookup(profile, xindex, lookupname);
if (!new || **lookupname != '&')
break;
stack = new;Why this breaks container profiles
With the fix, exec'd processes inside containers now correctly receive a stacked label like cri-containerd.apparmor.d//&unconfined (or crio-default//&crun),
where previously the stacking was silently skipped and they just got cri-containerd.apparmor.d.
Existing signal/ptrace rules like signal (send,receive) peer={{.Name}} only match the bare profile name, not the stacked compound label — hence the DENIED
audit entries.
This has also the detailed explanation, but not mention about the upstream change.
containerd/containerd#12886
I confirmed the config is valid in apparmor 4 environment, but I just ran the reproducer, so not sure if it covers enough scenarios.
With AppArmor 5.0+, child processes get stacked profiles like profile//&crun. Add //&* wildcard rules for signal and ptrace to match stacked profile peers.
This is a reproducer.
https://gist.github.com/bitoku/6fe0dd11aed0e4dad31eb0171c49279f
This will fix cri-o/cri-o#10036 .
Assisted-by: Claude Code https://claude.com/claude-code