Eine Sicherheitslücke in dem AppArmor-Modul des Linux Kernels hat zur Folge, dass ein Angreifer
Denial-of-Service-Attacken durchführen kann.
Mit AppArmor können einzelnen Linux-Programmen bestimmte Rechte zugeteilt oder entzogen werden. Es handelt sich dabei um eine Kernel-Erweiterung,
die Mandatory Access Control (MAC) bereitstellt. AppArmor macht dazu Gebrauch von der Linux Security Module-Schnittstelle (LSM), die auch SELinux
verwendet. Der durch AppArmor bereitgestellte Schutz von Prozessen ist sinnvoll, um das System vor noch unbekannten Sicherheitslücken
wie Zero-Day-Exploits zu schützen. Für verschiedene Anwendungen stehen diverse Sicherheitsprofile zur Verfügung, die regeln, welche Rechte
AppArmor der jeweiligen Anwendung geben soll. AppArmor-Profile können in grundsätzlich zwei Modi betrieben werden: Enforcement oder Complain. Der erste
Modus legt fest, dass die spezifizierte Policy eingehalten werden muss, während “complain” angibt, dass Verletzungen der Policy gemeldet werden sollen.
Unter Ubuntu sind die Profile in “/etc/apparmor.d/” abgelegt. So findet sich beispielsweise für Tcpdump das Profil in “usr.sbin.tcpdump”:
# vim:syntax=apparmor
# Last Modified: Wed Feb 3 07:58:30 2009
# Author: Jamie Strandboge
#include <tunables/global>
/usr/sbin/tcpdump { #include <abstractions/base> #include <abstractions/nameservice> #include <abstractions/user-tmp> capability net_raw, capability setuid, capability setgid, capability dac_override, network raw, network packet, # for -D capability sys_module, @{PROC}/bus/usb/ r, @{PROC}/bus/usb/** r, # for tracing USB bus, which libpcap supports /dev/usbmon* r, /dev/bus/usb/ r, /dev/bus/usb/** r, # for -F and -w audit deny @{HOME}/.* mrwkl, audit deny @{HOME}/.*/ rw, audit deny @{HOME}/.*/** mrwkl, audit deny @{HOME}/bin/ rw, audit deny @{HOME}/bin/** mrwkl, owner @{HOME}/ r, owner @{HOME}/** rw, /usr/sbin/tcpdump r,
}
Das Anlegen eines solchen Profiles wird durch “aa-genprof” vereinfacht, welches die verschiedenen Aktionen eines Programms mitloggen kann, so dass der
Administrator weiß, welche minimalen Rechte dieses Programm benötigt.
AppArmor bietet auch ein Kernel-Interface zu dem eigentlichen AppArmor-Modul. Der Zugriff hierüber findet über das Proc-Dateisystem unter
/proc/<PID>/attr/
statt.
Beispielsweise kann über
/proc/<PID>/attr/current
auf Profile-Eigenschaften zugegriffen werden. Sollte kein Profil für den entsprechenden Prozess angelegt sein,
so wird in current einfach “unconfined” stehen.
Eine schon Anfang Juni entdeckte Sicherheitslücke hat zur Folge, dass ein Prozess sich selbst zum Absturz bringen kann, indem er auf seinen eigenen
current-Eintrag schreibt:
echo 'AAA AAA' > /proc/$$/attr/current
Die Shell-Variable $$ enthält hierbei die Prozess-ID des Ech-Prozesses, das heißt, der Prozess selbst schreibt auf seinen eigenen current proc-Eintrag.
Ursache für diese Schwachstelle ist ein Programmierfehler in der “apparmor_setprocattr()”-Funktion in “security/apparmor/lsm.c”. Ein lokaler Angreifer
kann dies unter Umständen für Denial-of-Service-Attacken ausnutzen, da der gesamte Kernel dadurch in Halt versetzt wird. Bei dem Problem handelt es
sich um ein Nullzeiger-Dereferenz-Problem in folgendem Code-Fragment der “apparmor_setprocattr()”:
... } else { struct common_audit_data sa; COMON_AUDIT_DATA_INIT(&sa, NONE); sa.aad.op = OP_SETPROCATTR; sa.aad.info = name; sa.aad.error = -EINVAL; return aa_audit(AUDIT_APPARMOR_DENIED, NULL, GFP_KERNEL, &sa, NULL);
}
...
Die hier aufgerufenen “aa_audit()”-Funktion (security/apparmor/audit.c) ist für das Logging von Ereignissen zuständig, wobei als zweites Argument ein
struct aa_profile-Eintrag Zeiger übergeben wird. Im obigen Code-Fragment ist dieses Argument allerdings auf NULL gesetzt, was dazu führt, dass “aa_audit()”
auf Strukturelemente basierend auf einem Null-Zeiger zugreift:
int aa_audit(int type, struct aa_profile *profile, gfp_t gfp, struct common_audit_data *sa, void (*cb) (struct audit_buffer *, void *))
{ BUG_ON(!profile); if (type == AUDIT_APPARMOR_AUTO) { if (likely(!sa->aad.error)) { if (AUDIT_MODE(profile) != AUDIT_ALL) return 0; type = AUDIT_APPARMOR_AUDIT; } else if (COMPLAIN_MODE(profile)) type = AUDIT_APPARMOR_ALLOWED; else type = AUDIT_APPARMOR_DENIED; } if (AUDIT_MODE(profile) == AUDIT_QUIET || (type == AUDIT_APPARMOR_DENIED && AUDIT_MODE(profile) == AUDIT_QUIET)) return sa->aad.error; if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED) type = AUDIT_APPARMOR_KILL; if (!unconfined(profile)) sa->aad.profile = profile; aa_audit_msg(type, sa, cb); if (sa->aad.type == AUDIT_APPARMOR_KILL) (void)send_sig_info(SIGKILL, NULL, sa->tsk ? sa->tsk : current); if (sa->aad.type == AUDIT_APPARMOR_ALLOWED) return complain_error(sa->aad.error); return sa->aad.error;
}
Dieser Nullzeiger-Dereferenzfehler hat dann den Absturz der Anwendung zur Folge. Der Programmierfehler kann korrigiert werden, indem “aa_audit()” statt NULL
das korrekte Profile übergeben wird:
... return aa_audit(AUDIT_APPARMOR_DENIED, _aa_current_profile(), GFP_KERNEL, &sa, NULL); ...
Damit ist die Attacke nicht mehr möglich. Betroffen sind die Versionen 2.6.38 und älter.

