Permission problems with default apparmor enforced modules for docker

Docker info:

Client:
 Version:    29.5.1
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  0.34.1
    Path:     /usr/lib/docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  5.1.3
    Path:     /usr/lib/docker/cli-plugins/docker-compose

Server:
 Containers: 2
  Running: 0
  Paused: 0
  Stopped: 2
 Images: 34
 Server Version: 29.5.1
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Using metacopy: true
  Native Overlay Diff: false
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: systemd
 Cgroup Version: 2
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
 CDI spec directories:
  /etc/cdi
  /var/run/cdi
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 64b425cf570b3b8dd1d4cc46da7c1fce65c6651a.m
 runc version: 
 init version: de40ad0
 Security Options:
  apparmor
  seccomp
   Profile: builtin
  cgroupns
 Kernel Version: 7.0.11-arch1-1
 Operating System: Arch Linux
 OSType: linux
 Architecture: x86_64
 CPUs: 12
 Total Memory: 14.39GiB
 Name: red-laptop-16124
 ID: XXXXXXXXXXXX-XXXX-XXX-XXX-XXXXXXX
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Username: virgula
 Experimental: false
 Insecure Registries:
  ::1/128
  127.0.0.0/8
 Live Restore Enabled: false
 Firewall Backend: iptables
  EnableUserlandProxy: true
  UserlandProxyPath: /usr/bin/docker-proxy

Hello,

I recently installed AppArmor on my arch distro instance

uname -r

7.0.11-arch1-1

cat /etc/os-release 
NAME="Arch Linux"
PRETTY_NAME="Arch Linux"
ID=arch
BUILD_ID=rolling
ANSI_COLOR="38;2;23;147;209"
HOME_URL="https://archlinux.org/"
DOCUMENTATION_URL="https://wiki.archlinux.org/"
SUPPORT_URL="https://bbs.archlinux.org/"
BUG_REPORT_URL="https://gitlab.archlinux.org/groups/archlinux/-/issues"
PRIVACY_POLICY_URL="https://terms.archlinux.org/docs/privacy-policy/"
LOGO=archlinux-logo
sudo pacman -S apparmor
sudo systemctl enable --now apparmor.service

with startup options in /proc/cmdline for the GRUB:

BOOT_IMAGE=/vmlinuz-linux root=UUID=XXXX rw cryptdevice=UUID=XXXX::cryptlvm rootfstype=ext4 apparmor=1 security=apparmor loglevel=3 quiet

without adding new profiles by doing aa-stauts I get default enforced ones like these:

9 profiles are in enforce mode.
   /usr/lib/apache2/mpm-prefork/apache2//phpsysinfo
   apache2//phpsysinfo
   chromium//opencl_pocl_clang
   chromium//opencl_pocl_ld
   docker-default
   firefox//opencl_pocl_clang
   firefox//opencl_pocl_ld
   systemd-coredump//opencl_pocl_clang
   systemd-coredump//opencl_pocl_ld

First of all as far as I understood the fact that the profile is not saved on the disk but loaded in memory and then deleted, is something done on purpose and is very frustrating not finding it in /etc/apparmor.d/ location.

I think the docker-default profile is the one giving me troubles with docker rootfull installation, in fact:

docker run --rm hello-world
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: unable to start init: fork/exec /proc/self/fd/6: permission denied

Run 'docker run --help' for more information

and even this does not work:

docker run --rm --security-opt apparmor=unconfined hello-world
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: unable to start init: fork/exec /proc/self/fd/6: permission denied

Run 'docker run --help' for more information

For this reason I have created a mock trying to disable the in-memory module:

echo 'profile docker-default {}' | tee /etc/apparmor.d/docker-default
sudo aa-disable /etc/apparmor.d/docker-default

With this trick the module enforced is gone from the list:

8 profiles are in enforce mode.
   /usr/lib/apache2/mpm-prefork/apache2//phpsysinfo
   apache2//phpsysinfo
   chromium//opencl_pocl_clang
   chromium//opencl_pocl_ld
   firefox//opencl_pocl_clang
   firefox//opencl_pocl_ld
   systemd-coredump//opencl_pocl_clang
   systemd-coredump//opencl_pocl_ld

but docker still won’t work:

docker run --rm hello-world
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: unable to start init: fork/exec /proc/self/fd/6: permission denied

Run 'docker run --help' for more information, the only way to make it work is to tardown all loaded profiles:

Instead, unloading all profiles:

sudo aa-teardown
Unloading AppArmor profiles
docker run --rm hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

I need to use apparmor for other security reason but I can’t if docker gives me this kind of problem. What is the problem? Does any other enforced profile restricts the behavior for fork/exec /proc/self/fd/6? How can I eventually disable it since I also tried to complain them all with sudo aa-complain /etc/apparmor.d/*

There is no official package from Docker Inc. for Arch Linux: https://docs.docker.com/engine/install/#installation-procedures-for-supported-platforms

We can’t say whether something is different, and if so what in the docker package for Arch Linux. You might want to ask the maintainer of the docker package from the Arch Linux community for directions.

You can also wait until another user that uses the Arch Linux docker packages who know the problem and solution, posts an answer. I assume there are more Arch Linux users who use docker, than docker users who run it on Arch Linux.

I installed docker via official package manager pacman and I did not know that docker was not officially maintained on Arch. Thanks for the info, but anyway I think this is an issue more linked to AppArmor profiles and usages themself than an usage problem due to Arch, because without AppAmor it works fine as described in the main post.

That’s not what I wrote :slight_smile: I wrote that there is no official package from Docker Inc for Arch Linux. The Arch Linux community maintains their own package.

I just installed apparmor on a test system with Ubuntu 24.04 and Docker 29.5.3.
Works like a charm:

[root@docker ~ ]# docker run --rm -it --security-opt apparmor=docker-default hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

[root@docker ~ ]# docker info
Client: Docker Engine - Community
 Version:    29.5.3
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.34.1
    Path:     /usr/libexec/docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v5.1.4
    Path:     /usr/libexec/docker/cli-plugins/docker-compose

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 1
 Server Version: 29.5.3
 Storage Driver: overlayfs
  driver-type: io.containerd.snapshotter.v1
 Logging Driver: json-file
 Cgroup Driver: systemd
 Cgroup Version: 2
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
 CDI spec directories:
  /etc/cdi
  /var/run/cdi
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 193637f7ee8ae5f5aa5248f49e7baa3e6164966e
 runc version: v1.3.5-0-g488fc13e
 init version: de40ad0
 Security Options:
  apparmor
  seccomp
   Profile: builtin
  cgroupns
 Kernel Version: 6.8.0-94-generic
 Operating System: Ubuntu 24.04.4 LTS
 OSType: linux
 Architecture: x86_64
 CPUs: 4
 Total Memory: 3.823GiB
 Name: docker
 ID: xxxx-xxxx-xxxx-xxxx-xxxx
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Experimental: false
 Insecure Registries:
  ::1/128
  127.0.0.0/8
 Live Restore Enabled: false
 Firewall Backend: iptables
  EnableUserlandProxy: true
  UserlandProxyPath: /usr/bin/docker-proxy

Thanks, let’s see if anyone with Arch too had the same problem.

Also, I see your version is 29.5.3 but from changelog

They do not seem to contain braking changes about this topic

Or maybe the containerd static bianaries update introduced with 29.5.2->29.5.3 could have update previously broken apparmor behaviour?

EDIT:

From:

github[.]com/containerd/containerd/releases/tag/v2.2.4

There is pr: “Set AppArmor abi conditionally to support versions < 3.0” github[.]com/containerd/containerd/pull/13275 this could be related

But my version is: apparmor 4.1.7-1

My package versions:

  • apparmor: 4.0.1really4.0.1-0ubuntu0.24.04.7
  • conainerd: 2.2.4-1~ubuntu.24.04~noble

What’s surprising in your docker info output is that the runc version number is missing. the binary should be installed as part of the containerd package.

Update:
Even when I downgrade docker-ce to 5:29.5.1-1~ubuntu.24.04~noble , which is 29.5.1, it still works.

I’m trying to investigate the problem of missing containerd version. I’m having this problem on both normal linux arch kernel and the hardened one: 7.0.11-hardened2-1-hardened.

EDIT:

it seems that docker is unable to get version because of missing commit version in runc --version

runc version 1.4.2
spec: 1.3.0
go: go1.26.1-X:nodwarf5
libseccomp: 2.6.0

This bug should not be related to the main topic

Ok after investigating with the help of LLMs I was able to solve the problem.

Here it is explanation + fixes:

The aa-status only listed 9 profiles in enforce mode, and runc wasn’t one of them.
The apparmor.d profiles are built for modern AppArmor 4.x. Instead of running in standard “enforce” or “complain” modes, they are loaded with a special flag: flags=(unconfined).
These profiles tell the kernel: “Let this program do whatever it wants, EXCEPT if it triggers specific namespace transitions (like user namespaces).” Because they aren’t technically in “enforce” mode, aa-status doesn’t show them as enforcing. But because they contain structural transition rules, they still intercept runc when it tries to clone namespaces and clone itself via /proc/self/fd/6.

Since this is Docker rootfull, Docker handles its own container confinement via docker-default (which is properly enforced, as seen from aa-status). apparmor.d profiles interfering with the container engines are not needed.

The solution is to disable runc, crun, buildah, podman, and the global unprivileged_userns profile:

  1. Create the disable symlinks
sudo aa-enforce /etc/apparmor.d/*
sudo ln -sf /etc/apparmor.d/runc /etc/apparmor.d/disable/
sudo ln -sf /etc/apparmor.d/crun /etc/apparmor.d/disable/
sudo ln -sf /etc/apparmor.d/buildah /etc/apparmor.d/disable/
sudo ln -sf /etc/apparmor.d/podman /etc/apparmor.d/disable/
sudo ln -sf /etc/apparmor.d/unprivileged_userns /etc/apparmor.d/disable/
  1. Force-unload them from kernel memory right now and restart services:
sudo apparmor_parser -R /etc/apparmor.d/runc
sudo apparmor_parser -R /etc/apparmor.d/crun
sudo apparmor_parser -R /etc/apparmor.d/buildah
sudo apparmor_parser -R /etc/apparmor.d/podman
sudo apparmor_parser -R /etc/apparmor.d/unprivileged_userns
sudo systemctl restart containerd docker

Now:

docker run --rm hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

Anyway running a command like sudo aa-enforce /etc/apparmor.d/* will re-enabled that explicit disabled profiles and will delete all .delete profiles in /etc/apparmor.d/disable/

Hope this will help others too.

You might want to let the maintainer of the Arch Linux docker package know about this.

On my test machine, I have 28 profiles in enforce mode, amongst them are docker-default and unprivileged_userns. runc is not in the list → it is listed as profile in unconfined mode, like it was on your system.

I am not sure why problems with the chain dockercontainerdrunc, would be related to crun, buildah and podman. All three are from an alternative container runtime ecosystem.

I think that crun, buildah and podman are totally not related, but the LLM suggested to whitelist them as well for the future, eventually and in case of other container ecosystems usages. I opened a thread about this on the Arch forum (Permission problems with default apparmor enforced modules for docker / Networking, Server, and Protection / Arch Linux Forums), but no one answered me, so I guess maintainers are gonna ignore this anyway. At the end of the day, I think the most probable profile that was giving me troubles was exactly unprivileged_userns since runc was already not in the list and docker-default is at the moment enforced and is giving me no problems.

I personally don’t like to apply things to my systems that are not required.
And I agree with the assessment that unprivligied_userns is most likely responsible for the issue on Arch Linux.

You can find the maintainers in the package description: