mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
bpf: Don't look for the SRH again in the End.BPF helpers
A packet can have two SRHs. Thus input_action_end_bpf() uses
IP6_FH_F_SKIP_RH to skip routing headers with segments_left 0. The helpers
bpf_lwt_seg6_store_bytes() and bpf_lwt_seg6_adjust_srh() can reallocate the
head of the skb. Thus they look for the SRH again, but without this flag.
+------------------------+ <- the helpers: srh_state->srh
| SRH 1, segments_left 0 |
+------------------------+ <- input_action_end_bpf(): srh_state->srh
| SRH 2 | and srh_state->hdrlen
+------------------------+
Then the helpers check offset against the wrong limits. If a helper changes
TLVs, seg6_bpf_has_valid_srh() writes the length of SRH 2 to SRH 1.
Neither helper changes the offset of the SRH from skb->data. Calculate the
new address from this offset. To add IP6_FH_F_SKIP_RH is not sufficient,
because advance_nextseg() can set segments_left of SRH 2 to 0. The helper
bpf_lwt_seg6_action() can change the headers and still looks for the SRH.
Fixes: fbbc5bc2ab ("seg6: ignore routing header with segments left equal to 0")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-20-alexei.starovoitov@gmail.com
This commit is contained in:
parent
ac159f39b2
commit
45bcc58d57
|
|
@ -7024,12 +7024,13 @@ BPF_CALL_4(bpf_lwt_seg6_store_bytes, struct sk_buff *, skb, u32, offset,
|
|||
this_cpu_ptr(&seg6_bpf_srh_states);
|
||||
struct ipv6_sr_hdr *srh = srh_state->srh;
|
||||
void *srh_tlvs, *srh_end, *ptr;
|
||||
int srhoff = 0;
|
||||
int srhoff;
|
||||
|
||||
lockdep_assert_held(&srh_state->bh_lock);
|
||||
if (srh == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
srhoff = (unsigned char *)srh - skb->data;
|
||||
srh_tlvs = (void *)((char *)srh + ((srh->first_segment + 1) << 4));
|
||||
srh_end = (void *)((char *)srh + sizeof(*srh) + srh_state->hdrlen);
|
||||
|
||||
|
|
@ -7042,8 +7043,7 @@ BPF_CALL_4(bpf_lwt_seg6_store_bytes, struct sk_buff *, skb, u32, offset,
|
|||
|
||||
if (unlikely(bpf_try_make_writable(skb, offset + len)))
|
||||
return -EFAULT;
|
||||
if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL) < 0)
|
||||
return -EINVAL;
|
||||
/* The head may have moved. */
|
||||
srh_state->srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
|
||||
|
||||
memcpy(skb->data + offset, from, len);
|
||||
|
|
@ -7162,13 +7162,14 @@ BPF_CALL_3(bpf_lwt_seg6_adjust_srh, struct sk_buff *, skb, u32, offset,
|
|||
struct ipv6_sr_hdr *srh = srh_state->srh;
|
||||
void *srh_end, *srh_tlvs, *ptr;
|
||||
struct ipv6hdr *hdr;
|
||||
int srhoff = 0;
|
||||
int srhoff;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&srh_state->bh_lock);
|
||||
if (unlikely(srh == NULL))
|
||||
return -EINVAL;
|
||||
|
||||
srhoff = (unsigned char *)srh - skb->data;
|
||||
srh_tlvs = (void *)((unsigned char *)srh + sizeof(*srh) +
|
||||
((srh->first_segment + 1) << 4));
|
||||
srh_end = (void *)((unsigned char *)srh + sizeof(*srh) +
|
||||
|
|
@ -7200,8 +7201,7 @@ BPF_CALL_3(bpf_lwt_seg6_adjust_srh, struct sk_buff *, skb, u32, offset,
|
|||
hdr = (struct ipv6hdr *)skb->data;
|
||||
hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
|
||||
|
||||
if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL) < 0)
|
||||
return -EINVAL;
|
||||
/* The bytes in front of offset have moved together with skb->data. */
|
||||
srh_state->srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
|
||||
srh_state->hdrlen += len;
|
||||
srh_state->valid = false;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user