Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ipv6: do not use skb_header_pointer() in icmpv6_filter()

Prefer pskb_may_pull() to avoid a stack canary in raw6_local_deliver().

Note: skb->head can change, hence we reload ip6h pointer in
ipv6_raw_deliver()

$ scripts/bloat-o-meter -t vmlinux.old vmlinux.new
add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-86 (-86)
Function old new delta
raw6_local_deliver 780 694 -86
Total: Before=24889784, After=24889698, chg -0.00%

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260205211909.4115285-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Eric Dumazet and committed by
Jakub Kicinski
a14d9317 b6e2db0e

+16 -16
+16 -16
net/ipv6/raw.c
··· 90 90 * 0 - deliver 91 91 * 1 - block 92 92 */ 93 - static int icmpv6_filter(const struct sock *sk, const struct sk_buff *skb) 93 + static int icmpv6_filter(const struct sock *sk, struct sk_buff *skb) 94 94 { 95 - struct icmp6hdr _hdr; 96 95 const struct icmp6hdr *hdr; 96 + const __u32 *data; 97 + unsigned int type; 97 98 98 99 /* We require only the four bytes of the ICMPv6 header, not any 99 100 * additional bytes of message body in "struct icmp6hdr". 100 101 */ 101 - hdr = skb_header_pointer(skb, skb_transport_offset(skb), 102 - ICMPV6_HDRLEN, &_hdr); 103 - if (hdr) { 104 - const __u32 *data = &raw6_sk(sk)->filter.data[0]; 105 - unsigned int type = hdr->icmp6_type; 102 + if (!pskb_may_pull(skb, ICMPV6_HDRLEN)) 103 + return 1; 106 104 107 - return (data[type >> 5] & (1U << (type & 31))) != 0; 108 - } 109 - return 1; 105 + hdr = (struct icmp6hdr *)skb->data; 106 + type = hdr->icmp6_type; 107 + 108 + data = &raw6_sk(sk)->filter.data[0]; 109 + 110 + return (data[type >> 5] & (1U << (type & 31))) != 0; 110 111 } 111 112 112 113 #if IS_ENABLED(CONFIG_IPV6_MIP6) ··· 142 141 static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) 143 142 { 144 143 struct net *net = dev_net(skb->dev); 145 - const struct in6_addr *saddr; 146 - const struct in6_addr *daddr; 144 + const struct ipv6hdr *ip6h; 147 145 struct hlist_head *hlist; 148 - struct sock *sk; 149 146 bool delivered = false; 147 + struct sock *sk; 150 148 __u8 hash; 151 149 152 - saddr = &ipv6_hdr(skb)->saddr; 153 - daddr = saddr + 1; 150 + ip6h = ipv6_hdr(skb); 154 151 155 152 hash = raw_hashfunc(net, nexthdr); 156 153 hlist = &raw_v6_hashinfo.ht[hash]; ··· 156 157 sk_for_each_rcu(sk, hlist) { 157 158 int filtered; 158 159 159 - if (!raw_v6_match(net, sk, nexthdr, daddr, saddr, 160 + if (!raw_v6_match(net, sk, nexthdr, &ip6h->daddr, &ip6h->saddr, 160 161 inet6_iif(skb), inet6_sdif(skb))) 161 162 continue; 162 163 ··· 170 171 switch (nexthdr) { 171 172 case IPPROTO_ICMPV6: 172 173 filtered = icmpv6_filter(sk, skb); 174 + ip6h = ipv6_hdr(skb); 173 175 break; 174 176 175 177 #if IS_ENABLED(CONFIG_IPV6_MIP6)