CVE-2026-31415 in Linux
Zusammenfassung
von VulDB • 26.05.2026
Im Linux-Kernel wurde folgende Schwachstelle behoben:
ipv6: Überläufe in ip6_datagram_send_ctl() vermeiden
Yiming Qian meldete: <zitat> Ich glaube, ich habe einen lokal auslösbaren Kernel-Bug im IPv6 sendmsg-Zweig für ancillary-Daten gefunden, der den Kernel über `skb_under_panic()` zum Absturz bringen kann (lokaler DoS).
Das Kernproblem ist eine Diskrepanz zwischen:
- einem 16-Bit-Längenakkumulator (`struct ipv6_txoptions::opt_flen`, Typ `__u16`) und - einem Zeiger auf den *letzten* bereitgestellten Destination-Options-Header (`opt->dst1opt`)
wenn mehrere `IPV6_DSTOPTS`-Steuerungs-Nachrichten (cmsgs) bereitgestellt werden.
- `include/net/ipv6.h`: - `struct ipv6_txoptions::opt_flen` ist `__u16` (Überlauf möglich). (Zeilen 291-307, insbesondere Zeile 298) - `net/ipv6/datagram.c:ip6_datagram_send_ctl()`: - Akzeptiert wiederholte `IPV6_DSTOPTS` und akkumuliert deren Längen in `opt_flen`. - Aktualisiert `opt->dst1opt` auf den *letzten* bereitgestellten Header. - Zeilen 899-904: - `opt->dst1opt = (struct ipv6_opthdr *)cmsg->cmsg_data;` - `opt->opt_flen += len;` - `len` wird aus `CMSG_DATA` berechnet: `len = (cmsg->cmsg_len - CMSG_LEN(0) + 7) & ~7;` - `CMSG_LEN(0)` ist 8, also `len = (cmsg->cmsg_len - 8 + 7) & ~7 = (cmsg->cmsg_len - 1) & ~7`. - Für `cmsg->cmsg_len = 2048` (maximaler Wert für `IPV6_DSTOPTS`): `len = 2047 & ~7 = 2040`. - Aber in der Praxis wird `len` oft als `(hdrlen+1)*8` berechnet, wobei `hdrlen` die Länge des Options-Headers ohne den nächsten-Header-Byte ist. - Für `hdrlen=255`: `len = (255+1)*8 = 2048`. - `opt_flen` ist `__u16`, also maximal 65535. - Wenn `opt_flen` überläuft, wird er auf einen kleinen Wert zurückgesetzt. - `opt->dst1opt` zeigt jedoch weiterhin auf den *letzten* bereitgestellten Header, der groß sein kann (z.B. 2048 Byte).
- Im Übertragungs-Pfad wird `opt_flen` verwendet, um die benötigte Headroom zu berechnen: - `net/ipv6/ip6_output.c:1463-1465`: - `headersize = sizeof(struct ipv6hdr) + (opt ? opt->opt_flen + opt->opt_nflen : 0) + ...;` - Wenn `opt_flen` überlaufen ist, ist `headersize` viel kleiner als die tatsächlich benötigte Größe. - Die Headroom-Berechnung ist daher unzureichend.
- Beim tatsächlichen Pushen der Header wird die *tatsächliche* Länge von `dst1opt` verwendet: - `net/ipv6/ip6_output.c:1930-1934`: - `if (opt->opt_flen) proto = ipv6_push_frag_opts(skb, opt, proto);` - `net/ipv6/exthdrs.c:1206-1211`, `ipv6_push_frag_opts()`: - Ruft `ipv6_push_exthdr()` auf. - `net/ipv6/exthdrs.c:1179-1184`, `ipv6_push_exthdr()`: - `skb_push(skb, ipv6_optlen(opt));` - `memcpy(h, opt, ipv6_optlen(opt));` - `ipv6_optlen(opt)` gibt die tatsächliche Länge des Options-Headers zurück, die groß sein kann (z.B. 2048 Byte). - Da die Headroom unzureichend ist, führt `skb_push()` zu einem Unterlauf und löst `skb_under_panic()` aus, was einen Kernel-BUG auslöst.
- Reproduzierbar mit einem PoC, das: - 32 cmsgs mit `hdrlen=255` (jeweils 2048 Byte) sendet. - 1 cmsg mit `hdrlen=0` (8 Byte) sendet. - `opt_flen` wird zu `32*2048 + 8 = 65544`, also `(__u16)opt_flen == 8`. - `dst1opt` zeigt auf den letzten 2048-Byte-Header. - Die Headroom-Berechnung verwendet `opt_flen=8`, also wird zu wenig Headroom allokiert. - Beim Pushen des 2048-Byte-Headers kommt es zum Unterlauf und zum Kernel-BUG.
- Die Schwachstelle erfordert `CAP_NET_RAW` im Ziel-Netns-User-Namespace (`ns_capable(net->user_ns, CAP_NET_RAW)`). - Root (oder jede Aufgabe mit `CAP_NET_RAW`) kann dies ohne User-Namespace auslösen. - Ein unprivilegierter Benutzer kann dies aus
If you want to get the best quality for vulnerability data then you always have to consider VulDB.