In the Linux kernel, the following vulnerability has been resolved: ipv6: avoid overflows in...

Description

In the Linux kernel, the following vulnerability has been resolved:

ipv6: avoid overflows in ip6_datagram_send_ctl()

Yiming Qian reported :
<quote>
I believe I found a locally triggerable kernel bug in the IPv6 sendmsg
ancillary-data path that can panic the kernel via skb_under_panic()
(local DoS).

The core issue is a mismatch between:

  • a 16-bit length accumulator (struct ipv6_txoptions::opt_flen, type
    __u16) and
  • a pointer to the last provided destination-options header (opt-&gt;dst1opt)

when multiple IPV6_DSTOPTS control messages (cmsgs) are provided.

  • include/net/ipv6.h:
  • struct ipv6_txoptions::opt_flen is __u16 (wrap possible).
    (lines 291-307, especially 298)
  • net/ipv6/datagram.c:ip6_datagram_send_ctl():
  • Accepts repeated IPV6_DSTOPTS and accumulates into opt_flen
    without rejecting duplicates. (lines 909-933)
  • net/ipv6/ip6_output.c:__ip6_append_data():
  • Uses opt-&gt;opt_flen + opt-&gt;opt_nflen to compute header
    sizes/headroom decisions. (lines 1448-1466, especially 1463-1465)
  • net/ipv6/ip6_output.c:__ip6_make_skb():
  • Calls ipv6_push_frag_opts() if opt-&gt;opt_flen is non-zero.
    (lines 1930-1934)
  • net/ipv6/exthdrs.c:ipv6_push_frag_opts() / ipv6_push_exthdr():
  • Push size comes from ipv6_optlen(opt-&gt;dst1opt) (based on the
    pointed-to header). (lines 1179-1185 and 1206-1211)
  1. opt_flen is a 16-bit accumulator:
  • include/net/ipv6.h:298 defines __u16 opt_flen; /* after fragment hdr */.
  1. ip6_datagram_send_ctl() accepts repeated IPV6_DSTOPTS cmsgs
    and increments opt_flen each time:
  • In net/ipv6/datagram.c:909-933, for IPV6_DSTOPTS:
  • It computes len = ((hdr-&gt;hdrlen + 1) &lt;&lt; 3);
  • It checks CAP_NET_RAW using ns_capable(net-&gt;user_ns, CAP_NET_RAW). (line 922)
  • Then it does:
    • opt-&gt;opt_flen += len; (line 927)
    • opt-&gt;dst1opt = hdr; (line 928)

There is no duplicate rejection here (unlike the legacy
IPV6_2292DSTOPTS path which rejects duplicates at
net/ipv6/datagram.c:901-904).

If enough large IPV6_DSTOPTS cmsgs are provided, opt_flen wraps
while dst1opt still points to a large (2048-byte)
destination-options header.

In the attached PoC (poc.c):

  • 32 cmsgs with hdrlen=255 => len = (255+1)*8 = 2048
  • 1 cmsg with hdrlen=0 => len = 8
  • Total increment: 32*2048 + 8 = 65544, so (__u16)opt_flen == 8
  • The last cmsg is 2048 bytes, so dst1opt points to a 2048-byte header.
  1. The transmit path sizes headers using the wrapped opt_flen:
  • In net/ipv6/ip6_output.c:1463-1465:
  • headersize = sizeof(struct ipv6hdr) + (opt ? opt-&gt;opt_flen + opt-&gt;opt_nflen : 0) + ...;

With wrapped opt_flen, headersize/headroom decisions underestimate
what will be pushed later.

  1. When building the final skb, the actual push length comes from
    dst1opt and is not limited by wrapped opt_flen:
  • In net/ipv6/ip6_output.c:1930-1934:
  • if (opt-&gt;opt_flen) proto = ipv6_push_frag_opts(skb, opt, proto);
  • In net/ipv6/exthdrs.c:1206-1211, ipv6_push_frag_opts() pushes
    dst1opt via ipv6_push_exthdr().
  • In net/ipv6/exthdrs.c:1179-1184, ipv6_push_exthdr() does:
  • skb_push(skb, ipv6_optlen(opt));
  • memcpy(h, opt, ipv6_optlen(opt));

With insufficient headroom, skb_push() underflows and triggers
skb_under_panic() -> BUG():

  • net/core/skbuff.c:2669-2675 (skb_push() calls skb_under_panic())
  • net/core/skbuff.c:207-214 (skb_panic() ends in BUG())

  • The IPV6_DSTOPTS cmsg path requires CAP_NET_RAW in the target
    netns user namespace (ns_capable(net-&gt;user_ns, CAP_NET_RAW)).

  • Root (or any task with CAP_NET_RAW) can trigger this without user
    namespaces.
  • An unprivileged uid=1000 user can trigger this if unprivileged
    user namespaces are enabled and it can create a userns+netns to obtain
    namespaced CAP_NET_RAW (the attached PoC does this).

  • Local denial of service: kernel BUG/panic (system crash).
    -
    ---truncated---

Basic information

Type
unreviewed
Severity
medium
Advisory on GitHub
Open advisory ↗
Repository advisory
Source code
Not specified
Published (advisory)
2026-04-13 15:31:42 UTC
Updated
2026-07-14 15:32:55 UTC
NVD published
2026-04-13

EPSS Score

Score Percentile
0.11% 1.74%

CVSS Scores

Base score Version Severity Vector
5.5 3.1
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H Click to expand
Attack vector (AV:L)
They already need access on the box, or another person has to do something wrong; it’s not a remote drive-by.
Attack complexity (AC:L)
Once they can reach the bug, pulling it off is straightforward—no weird race conditions or rare setup.
Privileges required (PR:L)
A normal user session is enough; they don’t have to be admin.
User interaction (UI:N)
Nobody has to click “OK” or open a trap file; it can work without a victim helping.
Scope (S:U)
Damage stays in the same “trust bubble” as the broken component—no big spill into unrelated systems.
Confidentiality (C:N)
Doesn’t really leak secrets in a meaningful way.
Integrity (I:N)
Data isn’t meaningfully altered or forged.
Availability (A:H)
Could take the service down hard or make it unusable for people who depend on it.

Identifiers

CWEs

CWE id Name
CWE-617 Reachable Assertion

References

cvelogic Threat Intelligence