Before derefencing the encap pointer, commit e7cc082455cb ("udp: Support for error handlers of tunnels with arbitrary destination port") checks for a NULL value, but the two fetch operation can race with removal. Fix the above using a single access. Also fix a couple of type annotations, to make sparse happy.
Unified · Split
| @@ -420,17 +420,19 @@ EXPORT_SYMBOL(udpv6_encap_enable); · 419 unmodified lines | ||
| 420 | 420 | */ |
| 421 | 421 | static int __udp6_lib_err_encap_no_sk(struct sk_buff *skb, |
| 422 | 422 | struct inet6_skb_parm *opt, |
| 423 | − u8 type, u8 code, int offset, u32 info) | |
| 423 | + u8 type, u8 code, int offset, __be32 info) | |
| 424 | 424 | { |
| 425 | 425 | int i; |
| 426 | 426 | |
| 427 | 427 | for (i = 0; i < MAX_IPTUN_ENCAP_OPS; i++) { |
| 428 | 428 | int (*handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, |
| 429 | − u8 type, u8 code, int offset, u32 info); | |
| 429 | + u8 type, u8 code, int offset, __be32 info); | |
| 430 | + const struct ip6_tnl_encap_ops *encap; | |
| 430 | 431 | |
| 431 | − if (!ip6tun_encaps[i]) | |
| 432 | + encap = rcu_dereference(ip6tun_encaps[i]); | |
| 433 | + if (!encap) | |
| 432 | 434 | continue; |
| 433 | − handler = rcu_dereference(ip6tun_encaps[i]->err_handler); | |
| 435 | + handler = encap->err_handler; | |
| 434 | 436 | if (handler && !handler(skb, opt, type, code, offset, info)) |
| 435 | 437 | return 0; |
| 436 | 438 | } |