docker-default denies signals between a container's own processes when Ubuntu stacks the profile (`docker-default//&unconfined`)

Open
#54,099 4 comments 6 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
22/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
docker, go, linux

Research direction

The relevant rules are the signal and ptrace lines in apparmor/template.go in moby/profiles, which only allow peer={{.PeerName}}. Start by reading how that template is rendered and how the profile name is passed in, then reproduce the stacked label with cat /proc/<pid>/attr/current and dmesg | grep DENIED. Done means processes in a container under the stacked docker-default//&unconfined label can signal their own threads, and the template tests still pass.

Written by the indexing model from the issue text.

Description

Description

On Ubuntu 26.04 with kernel 7.0.0-1016-aws, processes in a container under docker-default cannot signal each other. The postgres image never starts. Its entrypoint runs gosu, gosu spins at full CPU, and the container writes no log output.

Ubuntu's apparmor package sets kernel.apparmor_restrict_unprivileged_unconfined=1 in /usr/lib/sysctl.d/10-apparmor.conf. runc runs unconfined and has no CAP_MAC_ADMIN when it changes profile. With that sysctl, the kernel turns runc's profile change into a stack:

apparmor="AUDIT" operation="change_onexec" info="change_profile unprivileged unconfined converted to stacking" profile="unconfined" name="/usr/local/bin/docker-entrypoint.sh" comm="runc:[2:INIT]" target="docker-default//&unconfined"

The container processes then have the label docker-default//&unconfined (enforce). The template in moby/profiles apparmor/template.go allows signals only to the literal profile name:

signal (send,receive) peer={{.PeerName}},
ptrace (trace,tracedby,read,readby) peer={{.PeerName}},

So AppArmor denies signals from a container process to its own threads:

apparmor="DENIED" operation="signal" class="signal" profile="docker-default" comm="gosu" requested_mask="send" denied_mask="send" signal=urg peer="docker-default//&unconfined"
apparmor="DENIED" operation="signal" class="signal" profile="docker-default" comm="gosu" requested_mask="send" denied_mask="send" signal=rtmin+1 peer="docker-default//&unconfined"

The stack depends on the kernel build. On 7.0.0-1014-aws, with the same AppArmor 5.0.2, Docker, containerd, runc, and sysctl value, the container gets the plain docker-default label and postgres starts normally. containerd has the same bug in its default profile: containerd/containerd#14485, with a proposed fix in containerd/containerd#14487.

Reproduce
  1. Use Ubuntu 26.04 with kernel 7.0.0-1016-aws, and leave kernel.apparmor_restrict_unprivileged_unconfined at its default of 1.
  2. docker run -d --name pg -e POSTGRES_PASSWORD=password postgres:16.13
  3. docker logs pg prints nothing. docker exec pg pg_isready -U postgres never succeeds.
  4. cat /proc/$(pgrep -x gosu)/attr/current prints docker-default//&unconfined (enforce).
  5. dmesg | grep DENIED shows the signal denials above.

Workaround: set kernel.apparmor_restrict_unprivileged_unconfined=0 and start a new container. The container then gets docker-default, and postgres accepts connections in about 2 seconds. This weakens a host hardening setting, so it is not a good default fix.

Expected behavior

Processes in one container can signal each other under docker-default, with or without the stacked label. One possible fix is the same one that containerd#14487 proposes: also allow the stacked form of the peer, for example peer={{.PeerName}}//&unconfined, and nothing wider.

docker version
Docker Engine 29.4.2 (docker-ce 5:29.4.2-2~ubuntu.26.04~resolute)
containerd 2.4.2 (containerd.io 2.4.2-3~ubuntu.26.04~resolute)
runc 1.5.2
docker info
cgroup v2, storage driver overlayfs with the containerd snapshotter
Host: Ubuntu 26.04.1 LTS, kernel 7.0.0-1016-aws, arm64 (Graviton)
AppArmor 5.0.2-0ubuntu1~26.04.1
Additional Info

The host is a GitHub Actions runner image, based on actions/runner-images Ubuntu 26.04. Other reports of the same failure: AutomatosAI/automatos-ai#1401 (k3s) and Osmantic/ODS#7619 (docker exec).

Dominant language
Go
Stars
72.2k
Forks
19.3k
Avg merge
1d 18h
Merged PRs (30d)
157

Getting set up

Open in Codespaces

Starts the project's dev container in your browser, under your own GitHub account.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from moby/moby

All issues in moby/moby

Similar issues

More Go issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.