On Thu, Sep 10, 2026 at 1:31 PM Farhad Alemi <[email protected]> wrote: > > lowpan_header_compress() pays for the IPHC header it pushes by first > calling skb_pull(skb, sizeof(struct ipv6hdr)), but that pull is a no-op > when skb->len is shorter than an IPv6 header, so the unpaid skb_push() can > drive skb->data below skb->head and into skb_under_panic(). > lowpan_nhc_check_compression() has the same missing length check, > committing to the next-header compression path without requiring the > nhc->nexthdrlen transport bytes that nhc->compress() reads and > lowpan_nhc_do_compression() then pulls. Return -EINVAL from > lowpan_header_compress() when pskb_may_pull() cannot produce a full IPv6 > header, and return -ENOENT from lowpan_nhc_check_compression() unless the > IPv6 header plus nhc->nexthdrlen bytes are present, so that the nexthdr > falls back to its inline encoding. > > Closes: > https://lore.kernel.org/all/CA+0ovCjTsygN76s2o=tzqpqw8v2gbhmrnz+q6g-nab3cq-y...@mail.gmail.com/ > Signed-off-by: Farhad Alemi <[email protected]>
Notes in a semi random order. 1) You forgot to tag the net tree in your patch. 2) You forgot the Fixes: tag Please look at Documentation/process/maintainer-netdev.rst for more details. 3) In net/6lowpan/nhc.c, calling pskb_may_pull() inside lowpan_nhc_check_compression() can reallocate skb->head (via pskb_expand_head()). When this happens, the 'hdr' pointer in lowpan_header_compress() becomes dangling. lowpan_header_compress() continues to dereference hdr throughout the rest of the function (hdr->nexthdr, hdr->hop_limit, hdr->saddr, hdr->daddr), leading to a use-after-free. 4) Callers of lowpan_header_compress() do not check its return value. In net/bluetooth/6lowpan.c (setup_header()) and net/ieee802154/6lowpan/tx.c (lowpan_header()), the return code of lowpan_header_compress() is completely ignored. If it returns -EINVAL, they proceed to transmit the malformed/uncompressed skb anyway. 5) In net/bluetooth/6lowpan.c:setup_header(), there is already an out-of-bounds read before lowpan_header_compress() is even called: hdr = ipv6_hdr(skb); ... memcpy(&ipv6_daddr, &hdr->daddr, sizeof(ipv6_daddr)); If skb->len is less than sizeof(struct ipv6hdr), reading hdr->daddr is already out of bounds. The driver's transmit path (bt_xmit / setup_header) needs to validate skb length / pskb_may_pull before touching the IPv6 header, and must check the return value of lowpan_header_compress(). Thanks.

