Hello, aa_inet_connect_perm() returns success immediately for AF_UNSPEC before checking the active AppArmor profile. AF_UNSPEC is the socket disconnect operation for TCP and UDP. A process confined by a profile containing deny network can therefore disconnect inherited sockets even though ordinary socket creation and connect calls are denied.
HEAD commit: fe2ec83746e501645709761605c2464a44fd2929 git tree: upstream Linux checkout, local branch master source version: Linux 7.3.0-rc4-70-gfe2ec83746e50 compiler: gcc 11.4.0, GNU ld 2.38 (build details in reproduction notes) console output: https://gist.githubusercontent.com/shaos26/73b057c77b9ea22d5e6813c259dbf43c/raw/fab5c58d6f184f5fab88a3a31a80c2b919efecf0/console-output.txt reproduction kernel config: https://gist.githubusercontent.com/shaos26/73b057c77b9ea22d5e6813c259dbf43c/raw/b9192c97c92fdd3b59089704bad6fbd0a33ccf06/kernel-config.txt reproducer: https://gist.githubusercontent.com/shaos26/73b057c77b9ea22d5e6813c259dbf43c/raw/92c7dd098a227276fe3daeea45996e2848e66439/poc.c Build the kernel from HEAD with the attached reproduction config, then make a one-file initramfs. The PoC mounts sysfs and securityfs itself; DEVTMPFS_MOUNT supplies /dev/console. mkdir -p build rootfs cp kernel-config.txt build/.config make O=build olddefconfig make O=build -j"$(nproc)" bzImage cc -O2 -static -Wall -Wextra -o poc poc.c cp poc rootfs/poc (cd rootfs && find poc | cpio -o -H newc --owner=0:0) | gzip -9 > initramfs.cpio.gz timeout 900 qemu-system-x86_64 -kernel build/arch/x86/boot/bzImage \ -initrd initramfs.cpio.gz -append "console=ttyS0 rdinit=/poc panic=-1 loglevel=7 lsm=apparmor security=apparmor apparmor=1" \ -nographic -m 1024 -smp 1 -no-reboot 2>&1 | tee console.log Under the deny-network profile, socket() and connect(AF_INET) returned EACCES, but connect(fd, AF_UNSPEC) returned success and tore down the inherited connection and listener. Two fresh boots matched. A one-line control that routed AF_UNSPEC through aa_sk_perm returned EACCES and kept both sockets alive. Impact and prerequisites: A confined process that inherits a TCP/UDP socket can bypass the profile's network mediation for disconnect and disrupt that socket. The finding does not permit socket creation, bind, or arbitrary peer connections; no privilege escalation is demonstrated. Run the normal connect permission check for the AF_UNSPEC disconnect case: diff --git a/security/apparmor/af_inet.c b/security/apparmor/af_inet.c --- a/security/apparmor/af_inet.c +++ b/security/apparmor/af_inet.c @@ -425,7 +425,7 @@ if (addrlen < offsetofend(struct sockaddr, sa_family)) return -EINVAL; if (addr->sa_family == AF_UNSPEC) - return 0; + return aa_sk_perm(OP_CONNECT, AA_MAY_CONNECT, sock->sk); /* do we need early bailout for !family ... */ return sk_has_perm2(sock->sk, OP_CONNECT, AA_MAY_CONNECT, profile, ad, Fixes: 89ac6aa752ec8 ("apparmor: push inet mediation into profile callbacks, and improve auditing") Signed-off-by: shaos <[email protected]> Validation: Two fresh vulnerable boots showed socket teardown. The one-line fixed-kernel control denied the call and preserved both sockets. Thanks, shaos
