gro: remove rcu_read_lock/rcu_read_unlock from gro_receive handlers
[ Upstream commit fc1ca3348a74a1afaa7ffebc2b2f2cc149e11278 ] All gro_receive() handlers are called from dev_gro_receive() while rcu_read_lock() has been called. There is no point stacking more rcu_read_lock() Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org> Stable-dep-of: 7e4196935069 ("fou: Fix null-ptr-deref in GRO.") Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
7630695a39
commit
c35b04ae63
9 changed files with 14 additions and 44 deletions
|
@ -528,18 +528,15 @@ static struct sk_buff *geneve_gro_receive(struct sock *sk,
|
||||||
|
|
||||||
type = gh->proto_type;
|
type = gh->proto_type;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
ptype = gro_find_receive_by_type(type);
|
ptype = gro_find_receive_by_type(type);
|
||||||
if (!ptype)
|
if (!ptype)
|
||||||
goto out_unlock;
|
goto out;
|
||||||
|
|
||||||
skb_gro_pull(skb, gh_len);
|
skb_gro_pull(skb, gh_len);
|
||||||
skb_gro_postpull_rcsum(skb, gh, gh_len);
|
skb_gro_postpull_rcsum(skb, gh, gh_len);
|
||||||
pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
|
pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
|
||||||
flush = 0;
|
flush = 0;
|
||||||
|
|
||||||
out_unlock:
|
|
||||||
rcu_read_unlock();
|
|
||||||
out:
|
out:
|
||||||
skb_gro_flush_final(skb, pp, flush);
|
skb_gro_flush_final(skb, pp, flush);
|
||||||
|
|
||||||
|
|
|
@ -482,10 +482,9 @@ static struct sk_buff *vlan_gro_receive(struct list_head *head,
|
||||||
|
|
||||||
type = vhdr->h_vlan_encapsulated_proto;
|
type = vhdr->h_vlan_encapsulated_proto;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
ptype = gro_find_receive_by_type(type);
|
ptype = gro_find_receive_by_type(type);
|
||||||
if (!ptype)
|
if (!ptype)
|
||||||
goto out_unlock;
|
goto out;
|
||||||
|
|
||||||
flush = 0;
|
flush = 0;
|
||||||
|
|
||||||
|
@ -504,8 +503,6 @@ static struct sk_buff *vlan_gro_receive(struct list_head *head,
|
||||||
skb_gro_postpull_rcsum(skb, vhdr, sizeof(*vhdr));
|
skb_gro_postpull_rcsum(skb, vhdr, sizeof(*vhdr));
|
||||||
pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
|
pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
|
||||||
|
|
||||||
out_unlock:
|
|
||||||
rcu_read_unlock();
|
|
||||||
out:
|
out:
|
||||||
skb_gro_flush_final(skb, pp, flush);
|
skb_gro_flush_final(skb, pp, flush);
|
||||||
|
|
||||||
|
|
|
@ -430,19 +430,16 @@ struct sk_buff *eth_gro_receive(struct list_head *head, struct sk_buff *skb)
|
||||||
|
|
||||||
type = eh->h_proto;
|
type = eh->h_proto;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
ptype = gro_find_receive_by_type(type);
|
ptype = gro_find_receive_by_type(type);
|
||||||
if (ptype == NULL) {
|
if (ptype == NULL) {
|
||||||
flush = 1;
|
flush = 1;
|
||||||
goto out_unlock;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
skb_gro_pull(skb, sizeof(*eh));
|
skb_gro_pull(skb, sizeof(*eh));
|
||||||
skb_gro_postpull_rcsum(skb, eh, sizeof(*eh));
|
skb_gro_postpull_rcsum(skb, eh, sizeof(*eh));
|
||||||
pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
|
pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
|
||||||
|
|
||||||
out_unlock:
|
|
||||||
rcu_read_unlock();
|
|
||||||
out:
|
out:
|
||||||
skb_gro_flush_final(skb, pp, flush);
|
skb_gro_flush_final(skb, pp, flush);
|
||||||
|
|
||||||
|
|
|
@ -1473,19 +1473,18 @@ struct sk_buff *inet_gro_receive(struct list_head *head, struct sk_buff *skb)
|
||||||
|
|
||||||
proto = iph->protocol;
|
proto = iph->protocol;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
ops = rcu_dereference(inet_offloads[proto]);
|
ops = rcu_dereference(inet_offloads[proto]);
|
||||||
if (!ops || !ops->callbacks.gro_receive)
|
if (!ops || !ops->callbacks.gro_receive)
|
||||||
goto out_unlock;
|
goto out;
|
||||||
|
|
||||||
if (*(u8 *)iph != 0x45)
|
if (*(u8 *)iph != 0x45)
|
||||||
goto out_unlock;
|
goto out;
|
||||||
|
|
||||||
if (ip_is_fragment(iph))
|
if (ip_is_fragment(iph))
|
||||||
goto out_unlock;
|
goto out;
|
||||||
|
|
||||||
if (unlikely(ip_fast_csum((u8 *)iph, 5)))
|
if (unlikely(ip_fast_csum((u8 *)iph, 5)))
|
||||||
goto out_unlock;
|
goto out;
|
||||||
|
|
||||||
id = ntohl(*(__be32 *)&iph->id);
|
id = ntohl(*(__be32 *)&iph->id);
|
||||||
flush = (u16)((ntohl(*(__be32 *)iph) ^ skb_gro_len(skb)) | (id & ~IP_DF));
|
flush = (u16)((ntohl(*(__be32 *)iph) ^ skb_gro_len(skb)) | (id & ~IP_DF));
|
||||||
|
@ -1562,9 +1561,6 @@ struct sk_buff *inet_gro_receive(struct list_head *head, struct sk_buff *skb)
|
||||||
pp = indirect_call_gro_receive(tcp4_gro_receive, udp4_gro_receive,
|
pp = indirect_call_gro_receive(tcp4_gro_receive, udp4_gro_receive,
|
||||||
ops->callbacks.gro_receive, head, skb);
|
ops->callbacks.gro_receive, head, skb);
|
||||||
|
|
||||||
out_unlock:
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
skb_gro_flush_final(skb, pp, flush);
|
skb_gro_flush_final(skb, pp, flush);
|
||||||
|
|
||||||
|
|
|
@ -246,17 +246,14 @@ static struct sk_buff *fou_gro_receive(struct sock *sk,
|
||||||
/* Flag this frame as already having an outer encap header */
|
/* Flag this frame as already having an outer encap header */
|
||||||
NAPI_GRO_CB(skb)->is_fou = 1;
|
NAPI_GRO_CB(skb)->is_fou = 1;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads;
|
offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads;
|
||||||
ops = rcu_dereference(offloads[proto]);
|
ops = rcu_dereference(offloads[proto]);
|
||||||
if (!ops || !ops->callbacks.gro_receive)
|
if (!ops || !ops->callbacks.gro_receive)
|
||||||
goto out_unlock;
|
goto out;
|
||||||
|
|
||||||
pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
|
pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
|
||||||
|
|
||||||
out_unlock:
|
out:
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
return pp;
|
return pp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,17 +435,14 @@ next_proto:
|
||||||
/* Flag this frame as already having an outer encap header */
|
/* Flag this frame as already having an outer encap header */
|
||||||
NAPI_GRO_CB(skb)->is_fou = 1;
|
NAPI_GRO_CB(skb)->is_fou = 1;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads;
|
offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads;
|
||||||
ops = rcu_dereference(offloads[proto]);
|
ops = rcu_dereference(offloads[proto]);
|
||||||
if (WARN_ON_ONCE(!ops || !ops->callbacks.gro_receive))
|
if (WARN_ON_ONCE(!ops || !ops->callbacks.gro_receive))
|
||||||
goto out_unlock;
|
goto out;
|
||||||
|
|
||||||
pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
|
pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
|
||||||
flush = 0;
|
flush = 0;
|
||||||
|
|
||||||
out_unlock:
|
|
||||||
rcu_read_unlock();
|
|
||||||
out:
|
out:
|
||||||
skb_gro_flush_final_remcsum(skb, pp, flush, &grc);
|
skb_gro_flush_final_remcsum(skb, pp, flush, &grc);
|
||||||
|
|
||||||
|
|
|
@ -158,10 +158,9 @@ static struct sk_buff *gre_gro_receive(struct list_head *head,
|
||||||
|
|
||||||
type = greh->protocol;
|
type = greh->protocol;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
ptype = gro_find_receive_by_type(type);
|
ptype = gro_find_receive_by_type(type);
|
||||||
if (!ptype)
|
if (!ptype)
|
||||||
goto out_unlock;
|
goto out;
|
||||||
|
|
||||||
grehlen = GRE_HEADER_SECTION;
|
grehlen = GRE_HEADER_SECTION;
|
||||||
|
|
||||||
|
@ -175,13 +174,13 @@ static struct sk_buff *gre_gro_receive(struct list_head *head,
|
||||||
if (skb_gro_header_hard(skb, hlen)) {
|
if (skb_gro_header_hard(skb, hlen)) {
|
||||||
greh = skb_gro_header_slow(skb, hlen, off);
|
greh = skb_gro_header_slow(skb, hlen, off);
|
||||||
if (unlikely(!greh))
|
if (unlikely(!greh))
|
||||||
goto out_unlock;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Don't bother verifying checksum if we're going to flush anyway. */
|
/* Don't bother verifying checksum if we're going to flush anyway. */
|
||||||
if ((greh->flags & GRE_CSUM) && !NAPI_GRO_CB(skb)->flush) {
|
if ((greh->flags & GRE_CSUM) && !NAPI_GRO_CB(skb)->flush) {
|
||||||
if (skb_gro_checksum_simple_validate(skb))
|
if (skb_gro_checksum_simple_validate(skb))
|
||||||
goto out_unlock;
|
goto out;
|
||||||
|
|
||||||
skb_gro_checksum_try_convert(skb, IPPROTO_GRE,
|
skb_gro_checksum_try_convert(skb, IPPROTO_GRE,
|
||||||
null_compute_pseudo);
|
null_compute_pseudo);
|
||||||
|
@ -225,8 +224,6 @@ static struct sk_buff *gre_gro_receive(struct list_head *head,
|
||||||
pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
|
pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
|
||||||
flush = 0;
|
flush = 0;
|
||||||
|
|
||||||
out_unlock:
|
|
||||||
rcu_read_unlock();
|
|
||||||
out:
|
out:
|
||||||
skb_gro_flush_final(skb, pp, flush);
|
skb_gro_flush_final(skb, pp, flush);
|
||||||
|
|
||||||
|
|
|
@ -628,13 +628,11 @@ struct sk_buff *udp4_gro_receive(struct list_head *head, struct sk_buff *skb)
|
||||||
inet_gro_compute_pseudo);
|
inet_gro_compute_pseudo);
|
||||||
skip:
|
skip:
|
||||||
NAPI_GRO_CB(skb)->is_ipv6 = 0;
|
NAPI_GRO_CB(skb)->is_ipv6 = 0;
|
||||||
rcu_read_lock();
|
|
||||||
|
|
||||||
if (static_branch_unlikely(&udp_encap_needed_key))
|
if (static_branch_unlikely(&udp_encap_needed_key))
|
||||||
sk = udp4_gro_lookup_skb(skb, uh->source, uh->dest);
|
sk = udp4_gro_lookup_skb(skb, uh->source, uh->dest);
|
||||||
|
|
||||||
pp = udp_gro_receive(head, skb, uh, sk);
|
pp = udp_gro_receive(head, skb, uh, sk);
|
||||||
rcu_read_unlock();
|
|
||||||
return pp;
|
return pp;
|
||||||
|
|
||||||
flush:
|
flush:
|
||||||
|
|
|
@ -209,7 +209,6 @@ INDIRECT_CALLABLE_SCOPE struct sk_buff *ipv6_gro_receive(struct list_head *head,
|
||||||
|
|
||||||
flush += ntohs(iph->payload_len) != skb_gro_len(skb);
|
flush += ntohs(iph->payload_len) != skb_gro_len(skb);
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
proto = iph->nexthdr;
|
proto = iph->nexthdr;
|
||||||
ops = rcu_dereference(inet6_offloads[proto]);
|
ops = rcu_dereference(inet6_offloads[proto]);
|
||||||
if (!ops || !ops->callbacks.gro_receive) {
|
if (!ops || !ops->callbacks.gro_receive) {
|
||||||
|
@ -222,7 +221,7 @@ INDIRECT_CALLABLE_SCOPE struct sk_buff *ipv6_gro_receive(struct list_head *head,
|
||||||
|
|
||||||
ops = rcu_dereference(inet6_offloads[proto]);
|
ops = rcu_dereference(inet6_offloads[proto]);
|
||||||
if (!ops || !ops->callbacks.gro_receive)
|
if (!ops || !ops->callbacks.gro_receive)
|
||||||
goto out_unlock;
|
goto out;
|
||||||
|
|
||||||
iph = ipv6_hdr(skb);
|
iph = ipv6_hdr(skb);
|
||||||
}
|
}
|
||||||
|
@ -280,9 +279,6 @@ not_same_flow:
|
||||||
pp = indirect_call_gro_receive_l4(tcp6_gro_receive, udp6_gro_receive,
|
pp = indirect_call_gro_receive_l4(tcp6_gro_receive, udp6_gro_receive,
|
||||||
ops->callbacks.gro_receive, head, skb);
|
ops->callbacks.gro_receive, head, skb);
|
||||||
|
|
||||||
out_unlock:
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
skb_gro_flush_final(skb, pp, flush);
|
skb_gro_flush_final(skb, pp, flush);
|
||||||
|
|
||||||
|
|
|
@ -144,13 +144,11 @@ struct sk_buff *udp6_gro_receive(struct list_head *head, struct sk_buff *skb)
|
||||||
|
|
||||||
skip:
|
skip:
|
||||||
NAPI_GRO_CB(skb)->is_ipv6 = 1;
|
NAPI_GRO_CB(skb)->is_ipv6 = 1;
|
||||||
rcu_read_lock();
|
|
||||||
|
|
||||||
if (static_branch_unlikely(&udpv6_encap_needed_key))
|
if (static_branch_unlikely(&udpv6_encap_needed_key))
|
||||||
sk = udp6_gro_lookup_skb(skb, uh->source, uh->dest);
|
sk = udp6_gro_lookup_skb(skb, uh->source, uh->dest);
|
||||||
|
|
||||||
pp = udp_gro_receive(head, skb, uh, sk);
|
pp = udp_gro_receive(head, skb, uh, sk);
|
||||||
rcu_read_unlock();
|
|
||||||
return pp;
|
return pp;
|
||||||
|
|
||||||
flush:
|
flush:
|
||||||
|
|
Loading…
Add table
Reference in a new issue