How an unvetted socket creation flags validation bug in security/apparmor/net.c allowed sandboxed snap processes to create arbitrary raw network sockets.
Imagine a prison guard who checks everyone entering the gate. He has a list that says 'Visitors can only bring paper, not knives or keys'. But a sneaky visitor passes a key hidden inside a box with a special label 'Special Fragile'. The guard only checks standard boxes, ignores the special label, and lets the prisoner receive a master key.
A confined application runs under a restrictive AppArmor profile forbidding raw network sockets.
The process calls socket(AF_INET, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_RAW).
AppArmor's check compared raw integer values instead of masking out ancillary flags, skipping the denial.
The restricted app sends spoofed raw packets and sniffs local traffic across the host.
Представлено на понятном высокоуровневом исходном коде (без ассемблера и бинарных дампов).
// VULNERABLE: security/apparmor/net.c before patch
int aa_profile_af_perm(struct aa_profile *profile, int family, int type, int protocol) {
// ROOT CAUSE:
// 'type' contains socket creation flags (e.g., SOCK_CLOEXEC, SOCK_NONBLOCK)!
// Direct lookup fails because the policy table only defines base types (SOCK_RAW = 3)!
// If type = (SOCK_RAW | SOCK_CLOEXEC) = 0x80003, rule lookup miss defaults to ALLOW!
return aa_lookup_net(profile, family, type, protocol);
}
// SECURE: security/apparmor/net.c patch
int aa_profile_af_perm(struct aa_profile *profile, int family, int type, int protocol) {
// 1. Mask out socket creation flags to extract purely the fundamental socket type
int base_type = type & SOCK_TYPE_MASK;
// 2. Perform policy mediation lookup using sanitized base type
return aa_lookup_net(profile, family, base_type, protocol);
}