fix(runc): apply AppArmor profile after finalizeNamespace in standard_init - #5557
Conversation
…_init Reorders the strict-mode runc v1.4.2 patch so the AppArmor profile change (and NoNewPrivileges) happen after finalizeNamespace runs setuid(2), mirroring setns_init_linux. Because the strict patches switch the profile immediately (aa_change_profile) instead of on exec, relabelling before setuid left the Go runtime's sibling threads under snap.microk8s.daemon-containerd while the calling thread moved to cri-containerd.apparmor.d. glibc's NPTL setxid broadcast (SIGRTMIN+1) then crossed two AppArmor profiles and was denied by AppArmor 4.x, breaking pod creation for workloads with allowPrivilegeEscalation: false (e.g. metallb). Doing setuid(2) while all threads share one profile keeps the broadcast intra-profile and resolves the denials without any snapd changes.
The upload_sarifs_matrix job runs codeql-action/upload-sarif, which requires security-events: write. With no permissions block declared the token fell back to the restricted default and uploads failed with "Resource not accessible by integration". Add a job-scoped permissions block granting the minimal scopes needed (contents/actions read, security-events write).
louiseschmidtgen
left a comment
There was a problem hiding this comment.
LGTM
Context around the approval:
The problem: With our strict-snap patches switching the AppArmor profile immediately (aa_change_profile) instead of on-exec, calling ApplyProfile before setuid splits the Go runtime's sibling threads across two profiles. The kernel only changes the profile on the current thread (domain.c#L1433 — it doesn't broadcast to siblings. So when glibc's NPTL does the setuid(2) setxid broadcast (SIGRTMIN+1) across all threads, that signal crosses two profiles and AppArmor 4.x denies it → pod creation fails (e.g. metallb with allowPrivilegeEscalation: false).
The fix: Do the setuid broadcast first, while all threads still share one profile, then apply the locked-down profile + NNP to the current thread. The post-switch split is harmless because we have nothing left to broadcast to the siblings.
Why we can't just match upstream: Upstream defers the switch to exec, so the ordering never bites them. In a strict snap we need the profile active earlier than that, so this reordering is the best we can do.
Summary
Master counterpart of the runc init-order fix being landed on
strict. Cherry-picks the same three commits ontomaster(which also builds runc v1.4.2).finalizeNamespacerunssetuid(2), mirroringsetns_init_linux. Because the strict patches switch the profile immediately (aa_change_profile) instead of on exec, relabelling beforesetuidleft the Go runtime's sibling threads under the old profile; glibc's NPTL setxid broadcast (SIGRTMIN+1) then crossed two AppArmor profiles and was denied by AppArmor 4.x, breaking pod creation for workloads withallowPrivilegeEscalation: false(e.g. metallb).permissionsblock toupload_sarifs_matrixsocodeql-action/upload-sarifcan upload (fixes "Resource not accessible by integration").Notes
strict-patches/v1.4.2/0003-...) is byte-identical to the version landing onstrict.1.35-strictcounterpart is not included here: that branch builds runc v1.3.3 (nov1.4.2patch dir), so the fix must be hand-ported tostrict-patches/v1.3.3/0003-...separately.