amt->nr_tunnels is protected by amt->lock. But, amt_request_handler() has been using this variable without the amt->lock. So, it expands context of amt->lock in the amt_request_handler() to protect amt->nr_tunnels variable.
Unified · Split
| @@ -2679,7 +2679,9 @@ static bool amt_request_handler(struct amt_dev *amt, struct sk_buff *skb) · 2678 unmodified lines | ||
| 2679 | 2679 | if (tunnel->ip4 == iph->saddr) |
| 2680 | 2680 | goto send; |
| 2681 | 2681 | |
| 2682 | + spin_lock_bh(&amt->lock); | |
| 2682 | 2683 | if (amt->nr_tunnels >= amt->max_tunnels) { |
| 2684 | + spin_unlock_bh(&amt->lock); | |
| 2683 | 2685 | icmp_ndo_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); |
| 2684 | 2686 | return true; |
| 2685 | 2687 | } |
| @@ -2687,8 +2689,10 @@ static bool amt_request_handler(struct amt_dev *amt, struct sk_buff *skb) · 1 unmodified line | ||
| 2687 | 2689 | tunnel = kzalloc(sizeof(*tunnel) + |
| 2688 | 2690 | (sizeof(struct hlist_head) * amt->hash_buckets), |
| 2689 | 2691 | GFP_ATOMIC); |
| 2690 | − if (!tunnel) | |
| 2692 | + if (!tunnel) { | |
| 2693 | + spin_unlock_bh(&amt->lock); | |
| 2691 | 2694 | return true; |
| 2695 | + } | |
| 2692 | 2696 | |
| 2693 | 2697 | tunnel->source_port = udph->source; |
| 2694 | 2698 | tunnel->ip4 = iph->saddr; |
| @@ -2701,10 +2705,9 @@ static bool amt_request_handler(struct amt_dev *amt, struct sk_buff *skb) · 6 unmodified lines | ||
| 2701 | 2705 | |
| 2702 | 2706 | INIT_DELAYED_WORK(&tunnel->gc_wq, amt_tunnel_expire); |
| 2703 | 2707 | |
| 2704 | − spin_lock_bh(&amt->lock); | |
| 2705 | 2708 | list_add_tail_rcu(&tunnel->list, &amt->tunnel_list); |
| 2706 | 2709 | tunnel->key = amt->key; |
| 2707 | − amt_update_relay_status(tunnel, AMT_STATUS_RECEIVED_REQUEST, true); | |
| 2710 | + __amt_update_relay_status(tunnel, AMT_STATUS_RECEIVED_REQUEST, true); | |
| 2708 | 2711 | amt->nr_tunnels++; |
| 2709 | 2712 | mod_delayed_work(amt_wq, &tunnel->gc_wq, |
| 2710 | 2713 | msecs_to_jiffies(amt_gmi(amt))); |