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.

Merge branch 'dst_cache-fix-possible-races'

Eric Dumazet says:

====================
dst_cache: fix possible races

This series is inspired by various undisclosed syzbot
reports hinting at corruptions in dst_cache structures.

It seems at least four users of dst_cache are racy against
BH reentrancy.

Last patch is adding a DEBUG_NET check to catch future misuses.
====================

Link: https://lore.kernel.org/r/20240531132636.2637995-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+24 -21
+2
net/core/dst_cache.c
··· 27 27 static void dst_cache_per_cpu_dst_set(struct dst_cache_pcpu *dst_cache, 28 28 struct dst_entry *dst, u32 cookie) 29 29 { 30 + DEBUG_NET_WARN_ON_ONCE(!in_softirq()); 30 31 dst_release(dst_cache->dst); 31 32 if (dst) 32 33 dst_hold(dst); ··· 41 40 { 42 41 struct dst_entry *dst; 43 42 43 + DEBUG_NET_WARN_ON_ONCE(!in_softirq()); 44 44 dst = idst->dst; 45 45 if (!dst) 46 46 goto fail;
+6 -1
net/ipv6/ila/ila_lwt.c
··· 58 58 return orig_dst->lwtstate->orig_output(net, sk, skb); 59 59 } 60 60 61 + local_bh_disable(); 61 62 dst = dst_cache_get(&ilwt->dst_cache); 63 + local_bh_enable(); 62 64 if (unlikely(!dst)) { 63 65 struct ipv6hdr *ip6h = ipv6_hdr(skb); 64 66 struct flowi6 fl6; ··· 88 86 goto drop; 89 87 } 90 88 91 - if (ilwt->connected) 89 + if (ilwt->connected) { 90 + local_bh_disable(); 92 91 dst_cache_set_ip6(&ilwt->dst_cache, dst, &fl6.saddr); 92 + local_bh_enable(); 93 + } 93 94 } 94 95 95 96 skb_dst_set(skb, dst);
+4 -4
net/ipv6/ioam6_iptunnel.c
··· 351 351 goto drop; 352 352 353 353 if (!ipv6_addr_equal(&orig_daddr, &ipv6_hdr(skb)->daddr)) { 354 - preempt_disable(); 354 + local_bh_disable(); 355 355 dst = dst_cache_get(&ilwt->cache); 356 - preempt_enable(); 356 + local_bh_enable(); 357 357 358 358 if (unlikely(!dst)) { 359 359 struct ipv6hdr *hdr = ipv6_hdr(skb); ··· 373 373 goto drop; 374 374 } 375 375 376 - preempt_disable(); 376 + local_bh_disable(); 377 377 dst_cache_set_ip6(&ilwt->cache, dst, &fl6.saddr); 378 - preempt_enable(); 378 + local_bh_enable(); 379 379 } 380 380 381 381 skb_dst_drop(skb);
+6 -8
net/ipv6/rpl_iptunnel.c
··· 212 212 if (unlikely(err)) 213 213 goto drop; 214 214 215 - preempt_disable(); 215 + local_bh_disable(); 216 216 dst = dst_cache_get(&rlwt->cache); 217 - preempt_enable(); 217 + local_bh_enable(); 218 218 219 219 if (unlikely(!dst)) { 220 220 struct ipv6hdr *hdr = ipv6_hdr(skb); ··· 234 234 goto drop; 235 235 } 236 236 237 - preempt_disable(); 237 + local_bh_disable(); 238 238 dst_cache_set_ip6(&rlwt->cache, dst, &fl6.saddr); 239 - preempt_enable(); 239 + local_bh_enable(); 240 240 } 241 241 242 242 skb_dst_drop(skb); ··· 268 268 return err; 269 269 } 270 270 271 - preempt_disable(); 271 + local_bh_disable(); 272 272 dst = dst_cache_get(&rlwt->cache); 273 - preempt_enable(); 274 273 275 274 if (!dst) { 276 275 ip6_route_input(skb); 277 276 dst = skb_dst(skb); 278 277 if (!dst->error) { 279 - preempt_disable(); 280 278 dst_cache_set_ip6(&rlwt->cache, dst, 281 279 &ipv6_hdr(skb)->saddr); 282 - preempt_enable(); 283 280 } 284 281 } else { 285 282 skb_dst_drop(skb); 286 283 skb_dst_set(skb, dst); 287 284 } 285 + local_bh_enable(); 288 286 289 287 err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev)); 290 288 if (unlikely(err))
+6 -8
net/ipv6/seg6_iptunnel.c
··· 464 464 465 465 slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate); 466 466 467 - preempt_disable(); 467 + local_bh_disable(); 468 468 dst = dst_cache_get(&slwt->cache); 469 - preempt_enable(); 470 469 471 470 if (!dst) { 472 471 ip6_route_input(skb); 473 472 dst = skb_dst(skb); 474 473 if (!dst->error) { 475 - preempt_disable(); 476 474 dst_cache_set_ip6(&slwt->cache, dst, 477 475 &ipv6_hdr(skb)->saddr); 478 - preempt_enable(); 479 476 } 480 477 } else { 481 478 skb_dst_drop(skb); 482 479 skb_dst_set(skb, dst); 483 480 } 481 + local_bh_enable(); 484 482 485 483 err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev)); 486 484 if (unlikely(err)) ··· 534 536 535 537 slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate); 536 538 537 - preempt_disable(); 539 + local_bh_disable(); 538 540 dst = dst_cache_get(&slwt->cache); 539 - preempt_enable(); 541 + local_bh_enable(); 540 542 541 543 if (unlikely(!dst)) { 542 544 struct ipv6hdr *hdr = ipv6_hdr(skb); ··· 556 558 goto drop; 557 559 } 558 560 559 - preempt_disable(); 561 + local_bh_disable(); 560 562 dst_cache_set_ip6(&slwt->cache, dst, &fl6.saddr); 561 - preempt_enable(); 563 + local_bh_enable(); 562 564 } 563 565 564 566 skb_dst_drop(skb);