mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
bpf: Move the transport header with the moved headers
bpf_skb_net_hdr_pop() removes len bytes at offset off.
bpf_skb_net_hdr_push() does the opposite.
skb->data off
before | A | removed | B |
after | A | B |
skb->data off
mac_header and network_header move with A. transport_header moves only when
it is equal to network_header. inner_transport_header never moves. This is
correct only for a header in B. In bpf_lwt_seg6_adjust_srh()
transport_header is in A. bpf_skb_adjust_room() can remove both transport
headers. With an incorrect header offset, the stack can drop the skb or
read outside of it.
Also move transport_header with A when it is in A. Set it to offset off
when it is in the removed bytes. In BPF_ADJ_ROOM_MAC mode it is then equal
to network_header. Do not unset it, because skb_gso_validate_mac_len() uses
it without a check. After a removal, set inner_transport_header to off when
it is not in B and skb->encapsulation is set. A has only outer headers.
Fixes: fe94cc290f ("bpf: Add IPv6 Segment Routing helpers")
Fixes: 868d523535 ("bpf: add bpf_skb_adjust_room encap flags")
Signed-off-by: Chris Mason <mason@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-26-alexei.starovoitov@gmail.com
This commit is contained in:
parent
95f1d5e4ab
commit
a9d08fe60f
|
|
@ -3402,9 +3402,25 @@ static int bpf_skb_generic_pop(struct sk_buff *skb, u32 off, u32 len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* bpf_skb_net_hdr_push() inserts bytes at @off, bpf_skb_net_hdr_pop() removes
|
||||
* bytes at @off. Both move the bytes in front of @off together with skb->data,
|
||||
* and leave the rest of the packet where it is. Return true if the transport
|
||||
* header is in the part that moves. A transport header that is equal to the
|
||||
* network header stays equal to it.
|
||||
*/
|
||||
static bool bpf_skb_trans_hdr_moves(const struct sk_buff *skb, u32 off)
|
||||
{
|
||||
if (skb->transport_header == skb->network_header)
|
||||
return true;
|
||||
|
||||
return skb_transport_header_was_set(skb) &&
|
||||
(u32)skb_transport_offset(skb) < off;
|
||||
}
|
||||
|
||||
static int bpf_skb_net_hdr_push(struct sk_buff *skb, u32 off, u32 len)
|
||||
{
|
||||
bool trans_same = skb->transport_header == skb->network_header;
|
||||
bool trans_moves = bpf_skb_trans_hdr_moves(skb, off);
|
||||
int ret;
|
||||
|
||||
/* There's no need for __skb_push()/__skb_pull() pair to
|
||||
|
|
@ -3415,8 +3431,8 @@ static int bpf_skb_net_hdr_push(struct sk_buff *skb, u32 off, u32 len)
|
|||
if (likely(!ret)) {
|
||||
skb->mac_header -= len;
|
||||
skb->network_header -= len;
|
||||
if (trans_same)
|
||||
skb->transport_header = skb->network_header;
|
||||
if (trans_moves)
|
||||
skb->transport_header -= len;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -3424,7 +3440,7 @@ static int bpf_skb_net_hdr_push(struct sk_buff *skb, u32 off, u32 len)
|
|||
|
||||
static int bpf_skb_net_hdr_pop(struct sk_buff *skb, u32 off, u32 len)
|
||||
{
|
||||
bool trans_same = skb->transport_header == skb->network_header;
|
||||
bool trans_moves = bpf_skb_trans_hdr_moves(skb, off);
|
||||
int ret;
|
||||
|
||||
/* Same here, __skb_push()/__skb_pull() pair not needed. */
|
||||
|
|
@ -3432,8 +3448,17 @@ static int bpf_skb_net_hdr_pop(struct sk_buff *skb, u32 off, u32 len)
|
|||
if (likely(!ret)) {
|
||||
skb->mac_header += len;
|
||||
skb->network_header += len;
|
||||
if (trans_same)
|
||||
skb->transport_header = skb->network_header;
|
||||
if (trans_moves) {
|
||||
skb->transport_header += len;
|
||||
} else if (skb_transport_header_was_set(skb) &&
|
||||
skb_transport_offset(skb) < (int)off) {
|
||||
/* It was in the removed bytes or before skb->data. */
|
||||
skb_set_transport_header(skb, off);
|
||||
}
|
||||
/* Do not leave the inner transport header in front of @off. */
|
||||
if (skb->encapsulation &&
|
||||
skb_inner_transport_offset(skb) < (int)off)
|
||||
skb_set_inner_transport_header(skb, off);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user