> Is it really present on Jammy ? with the test plan above, it seems
only present on Noble.
My apologies, this looks like a typo on my part. This issue is only
present in Noble.
> You seems to use a wrong SHA in your patch
12391ee0c046cd2c5c2ccdf58be21a1eb017587e instead of
4bb134e4bb950a8c9a1f70a27eb2acd2a35df412. Can you change it?
Thanks for spotting this. The patch was referencing my local merge
commit due to conflict resolution. Fixed and updated now.
** Description changed:
[Impact]
Socket creation with the following AppArmor unconfined profile fails due
to an AppArmor permission error:
PermissionError: [Errno 13] Permission denied
abi <abi/4.0>,
profile aa-repro flags=(unconfined) {
userns,
}
This socket_create issue does not occur with the Noble GA kernel; it
only occurs when running Noble userland on the Noble HWE kernel or
later.
This report is similar to the pivot_root issue in bug 2067900, which
shares the root cause in the AppArmor parser. This AppArmor parser bug
is addressed in the upstream commit:
https://gitlab.com/apparmor/apparmor/-/commit/4bb134e4bb950a8c9a1f70a27eb2acd2a35df412
The AppArmor parser incorrectly added mediation classes to unconfined
profiles, including those that would affect pivot_root (and
socket_create). The upstream fix 4bb134e landed in Resolute (and
Stonking), but not in Noble's 4.0.1really4.0.1-0ubuntu0.24.04.7 version.
In bug 2067900, the kernel commit
dc757a645cfa82f6ac252365df20a36a9ff82760 was reverted in the Noble GA
kernel, because it had other issues with older versions of the AppArmor
parser. This does not address the AppArmor parser bug, but fixed the
pivot_root bug temporarily.
The upstream fix in the AppArmor parser did initially land in Noble
updates, but was later reverted due to an (unrelated?) regression
according to bug 2067900. Since reverting dc757a6 already fixed the
pivot_root issue on the Noble GA kernel, bug 2067900 has been left
inactive. This report is thus intended to backport 4bb134e to address
this socket_create issue, in addition to the pivot_root issue.
[Test Plan]
I have tested the kernel behaviour under the following scenarios:
1. Jammy GA kernel (5.15.0-1104-kvm) + Jammy userland (22.04.5 LTS)
2. Jammy HWE kernel (6.8.0-136-generic) + Jammy userland (22.04.5 LTS)
3. Noble GA kernel (6.8.0-136-generic) + Noble userland (24.04.4 LTS)
4. Noble HWE kernel (7.0.0-28-generic) + Noble userland (24.04.4 LTS)
5. Noble HWE kernel (7.0.0-28-generic) + Noble userland (24.04.4 LTS; with
4bb134e)
6. Resolute GA kernel (7.0.0-28-generic) + Resolute userland (26.04 LTS)
7. Stonking kernel (7.0.0-14-generic) + Stonking userland (Ubuntu Stonking
Stingray)
For 5, the upstream fix 4bb134e was manually applied on ubuntu/noble-
updates.
First, set up the host and container:
~$ lxc launch ubuntu:24.04 aa-repro1 --vm -d root,size=20GB
# Or for Stonking kernel:
# ~$ lxc launch ubuntu-daily:stonking aa-repro3 --vm -d root,size=20GB
~$ lxc shell aa-repro1
root@aa-repro1:~# snap install lxd
root@aa-repro1:~# lxd init --minimal
root@aa-repro1:~# lxc launch ubuntu:24.04 c1
# Or for Stonking kernel:
# root@aa-repro1:~# lxc launch ubuntu-daily:stonking c1
root@aa-repro1:~# lxc shell c1
root@c1:~# uname -r
6.8.0-136-generic
root@c1:~# lsb_release -a | grep Description
Description: Ubuntu 24.04.4 LTS
Then create an unconfined AppArmor profile and test socket creation:
root@c1:~# apt update && apt install -y apparmor apparmor-utils
root@c1:~# cat >/etc/apparmor.d/aa-repro <<'EOF'
abi <abi/4.0>,
profile aa-repro flags=(unconfined) {
userns,
}
EOF
# Or for Jammy userland:
# root@c1:~# cat >/etc/apparmor.d/aa-repro <<'EOF'
# abi <abi/3.0>,
# profile aa-repro flags=(unconfined) {
# }
# EOF
root@c1:~# apparmor_parser -r /etc/apparmor.d/aa-repro
root@c1:~# aa-exec -p aa-repro -- \
python3 -c 'import socket; socket.socket(socket.AF_INET, socket.SOCK_STREAM);
socket.socket(socket.AF_INET6, socket.SOCK_STREAM); print("ok")'
ok
Repeating this for 1-7, I have obtained the following results:
# 1. Jammy GA kernel + Jammy userland
root@c1:~# aa-exec -p aa-repro -- ...
ok
# 2. Jammy HWE kernel + Jammy userland
root@c1:~# aa-exec -p aa-repro -- ...
ok
# 3. Noble GA kernel + Noble userland
root@c1:~# aa-exec -p aa-repro -- ...
ok
# 4. Noble HWE kernel + Noble userland
root@c1:~# aa-exec -p aa-repro -- ...
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/usr/lib/python3.12/socket.py", line 233, in __init__
_socket.socket.__init__(self, family, type, proto, fileno)
PermissionError: [Errno 13] Permission denied
root@c1:~# exit
root@aa-repro1:~# journalctl -k | grep 'apparmor="DENIED"' | grep
'class="net"'
Jul 29 07:43:28 aa-repro1 kernel: audit: type=1400 audit(1785311008.964:621):
apparmor="DENIED" operation="create" class="net" info="failed af match"
error=-13 namespace="root//lxd-c1_<var-snap-lxd-common-lxd>" profile="aa-repro"
pid=3516 comm="python3" family="inet" sock_type="stream" protocol=0
requested="create" denied="create"
# 5. Noble HWE kernel + Noble userland (with 4bb134e)
root@c1:~# aa-exec -p aa-repro -- ...
ok
# 6. Resolute kernel + Resolute userland
root@c1:~# aa-exec -p aa-repro -- ...
ok
# 7. Stonking kernel + Stonking userland
root@c1:~# aa-exec -p aa-repro -- ...
ok
- The AppArmor parser bug is present in Jammy and Noble userland, but not
- in Resolute userland. As shown above, the AppArmor parser in Jammy and
- Noble userland only fails on the Noble HWE kernel (or later).
+ The AppArmor parser bug is present in Noble userland, but not in
+ Resolute userland. As shown above, the AppArmor parser in Noble userland
+ only fails on the Noble HWE kernel (or later).
On another note, pivot_root succeeds for 4, which is why I believe
justifies keeping this report separate from bug 2067900:
# 4. Noble HWE kernel + Noble userland
aa-exec -p aa-repro -- unshare --mount --propagation private -- bash -c '
mkdir -p /mnt/newroot
mount -t tmpfs tmpfs /mnt/newroot
mkdir -p /mnt/newroot/put_old
cd /mnt/newroot
pivot_root . put_old && echo ok'
ok
[Where problems could occur]
I believe backporting the upstream fix 4bb134e has minimal impact
because it only affects unconfined profiles. It also only removes
mediation classes from the unconfined profiles, correctly excluding
userns.
[Other Info]
While the root cause is the corrupted binary blob in which the AppArmor
parser added spurious mediation classes to unconfined profiles, I have
identified the subtle kernel behaviour that would explain:
1. Why reverting dc757a6 on the Noble GA kernel temporarily fixed the issue
2. Why Noble userland on the Noble HWE kernel fails, but not on the Noble GA
kernel
These can be explained by how these primitives work for unconfined
profiles:
1. profile_unconfined(profile) returns 1 in an LXD container process
2. unconfined(label) returns 0 in an LXD container process, if the host
profile is confined i.e. the profiles are stacked in a label
3. RULE_MEDIATES(rules, AA_CLASS_XXX) (and its variants) returns 1 if the
binary blob is corrupted
4. label_mediates(label, AA_CLASS_XXX) returns 0 even if the binary blob is
corrupted
RULE_MEDIATES() reads from the start states of the DFA directly, which
are compiled from the AppArmor parser. On the other hand,
label_mediates() reads from the 'mediates' bits directly, which are left
unset (except AA_CLASS_NS) in aa_compute_profile_mediates() if
profile_unconfined() is 1.
I have verified the above results by adding a few printk() calls to the
kernel, triggering them in an LXD container nested in an LXD VM.
The corresponding LSM hooks use the above primitives in slightly
different ways, which I believe leads to the divergent behaviour of
pivot_root and socket_create in an LXD container running on different
kernel versions:
1. apparmor_sb_pivotroot() on the Jammy GA kernel:
- Same as item 3 below.
2. apparmor_sb_pivotroot() on the Noble GA kernel (before reverting dc757a6):
- The first check label_mediates(label, AA_CLASS_MOUNT) returns 1, and
proceeds to the second check.
- The second check !RULE_MEDIATES(rules, AA_CLASS_MOUNT) returns 0 in
build_pivotroot(), and errors in the DFA matching.
3. apparmor_sb_pivotroot() on the Noble GA kernel (after reverting dc757a6):
- The first check !unconfined(label) returns 1, and proceeds to the second
check.
- The second check profile_unconfined(profile) || !RULE_MEDIATES(rules,
AA_CLASS_MOUNT) returns 1 in build_pivotroot(), and bypasses the DFA matching.
4. apparmor_sb_pivotroot() on the Resolute GA kernel:
- Same as item 3 above.
5. apparmor_socket_create() on the Jammy GA kernel:
- The first check !(kern || unconfined(label)) returns 1, and proceeds to
the second check.
- The second check profile_unconfined(profile) returns 1, and bypasses the
DFA matching.
6. apparmor_socket_create() on the Noble GA kernel:
- The first check label_mediates(label, AA_CLASS_NET) returns 0, and
bypasses the DFA matching.
7. apparmor_socket_create() on the Resolute GA kernel:
- The first check !unconfined(label) returns 1.
- The second check RULE_MEDIATES_NET(rule) returns 1 in
profile_create_perm(), and errors in the DFA matching.
--
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2162134
Title:
Unconfined profile blocks socket_create
To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/2162134/+subscriptions
--
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs