mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
geneve: validate inner network offset in geneve_gro_complete()
Even with both paths gated on gs->gro_hint, geneve_gro_complete()
re-derives the inner dispatch type and length from the packet and the
current gs->gro_hint, independently of geneve_gro_receive(). The two can
disagree if gs->gro_hint flips under a concurrent geneve_quiesce()/
geneve_unquiesce() (sk_user_data is NULL across a synchronize_net()), or if
the re-read option bytes differ from the ones receive parsed.
geneve_gro_receive() already records the inner network header position in
NAPI_GRO_CB()->inner_network_offset. Have geneve_gro_complete() compute the
offset it is about to dispatch at, adding ETH_HLEN in the ETH_P_TEB case
where eth_gro_complete() steps over the inner MAC header, and bail out if
it lands past inner_network_offset.
Use a lower bound rather than exact equality: between gh_len and the inner
L3 header, geneve_gro_receive() may also have pulled an inner VLAN tag
(vlan_gro_receive() advances the recorded offset past it), which only moves
inner_network_offset further out. A valid frame therefore always satisfies
inner_nh <= inner_network_offset, while a gh_len inflated by a hint
gro_receive() did not honour dispatches past the validated inner header,
i.e. the out-of-bounds completion. Only the latter is rejected.
Fixes: fd0dd79657 ("geneve: use GRO hint option in the RX path")
Suggested-by: Paolo Abeni <pabeni@redhat.com>
Co-developed-by: Weiming Shi <bestswngs@gmail.com>
Signed-off-by: Xiang Mei <xmei5@asu.edu>
Link: https://patch.msgid.link/20260618032622.484720-2-xmei5@asu.edu
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
2651c17444
commit
cbb0d30a1a
@@ -962,6 +962,20 @@ static int geneve_gro_complete(struct sock *sk, struct sk_buff *skb,
|
||||
type = gh->proto_type;
|
||||
geneve_sk_gro_hint_off(sk, gh, &type, &gh_len);
|
||||
|
||||
/* Bail out if we are about to dispatch past the inner network header
|
||||
* gro_receive() validated. An inner VLAN tag only pushes
|
||||
* inner_network_offset out, so use a lower bound.
|
||||
*/
|
||||
if (skb->encapsulation) {
|
||||
unsigned int inner_nh = nhoff + gh_len;
|
||||
|
||||
if (type == htons(ETH_P_TEB))
|
||||
inner_nh += ETH_HLEN;
|
||||
|
||||
if (unlikely(inner_nh > NAPI_GRO_CB(skb)->inner_network_offset))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* since skb->encapsulation is set, eth_gro_complete() sets the inner mac header */
|
||||
if (likely(type == htons(ETH_P_TEB)))
|
||||
return eth_gro_complete(skb, nhoff + gh_len);
|
||||
|
||||
Reference in New Issue
Block a user