Re: Add variable offset to packet pointer in XDP/TC programs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Nov 9, 2021 at 5:47 AM Federico Parola
<federico.parola@xxxxxxxxx> wrote:
>
> Thanks for your answer.

Please do not top post and don't drop mailing list.

> If I perform something like:
>
> *(__u16 *)data &= 0xefff;
> data += *(__u16 *)data;
>
> To limit the max value of my offset the program is accepted, is this
> what you mean with "clamping"?

kinda. I don't think you meant to mangle the packet in the above.

> So packet pointers are stored on 16 bits? And every time we add an
> offset we must guarantee not to overflow these size?

no. the pointers are 64-bit, but there could be additional alu ops
on them. So MAX_PACKET_OFF was picked as the practical limit.

Do you have a real life use case where you need to add full u16?

>
> On 09/11/21 06:29, Alexei Starovoitov wrote:
> > On Mon, Nov 8, 2021 at 6:04 AM Federico Parola
> > <federico.parola@xxxxxxxxx> wrote:
> >>
> >> Dear all,
> >> I found out that every time an offset stored in a 2 (or more) bytes
> >> variable is added to a packet pointer subsequent checks against packet
> >> boundaries become ineffective.
> >> Here is a toy example to test the problem (it doesn't do anything useful):
> >>
> >> int test(struct __sk_buff *ctx) {
> >>       void *data = (void *)(long)ctx->data;
> >>       void *data_end = (void *)(long)ctx->data_end;
> >>
> >>       /* Skipping an amount of bytes stored in __u8 works */
> >>       if (data + sizeof(__u8) > data_end)
> >>           return TC_ACT_OK;
> >>       bpf_trace_printk("Skipping %d bytes", *(__u8 *)data);
> >>       data += *(__u8 *)data;
> >>
> >>       /* Skipping an amount of bytes stored in __u16 works but... */
> >>       if (data + sizeof(__u16) > data_end)
> >>           return TC_ACT_OK;
> >>       bpf_trace_printk("Skipping %d bytes", *(__u16 *)data);
> >>       data += *(__u16 *)data;
> >>
> >>       /* ...this check is not effective and packet access is rejected */
> >>       if (data + sizeof(__u8) > data_end)
> >>           return TC_ACT_OK;
> >>       bpf_trace_printk("Next byte is %x", *(__u8 *)data);
> >>
> >>       return TC_ACT_OK;
> >> }
> >>
> >> My practical use case would be skipping variable-size TLS header
> >> extensions until I reach the desired one (the length of these options is
> >> 2 bytes long).
> >> Another use case can be found here:
> >> https://lists.iovisor.org/g/iovisor-dev/topic/access_packet_payload_in_tc/86442134
> >> After I use the bpf_skb_pull_data() I would like to directly jump to the
> >> part of packet I was working on and avoid re-parsing everything from
> >> scratch, however if I save the offset in a 2 bytes variable and then add
> >> it to the packet pointer I'm no longer able to access it (if the offset
> >> is stored in a 1 byte var everything works).
> >>
> >> Is this a verifier bug?
> >
> > It's because of:
> >          if (dst_reg->umax_value > MAX_PACKET_OFF ||
> >              dst_reg->umax_value + dst_reg->off > MAX_PACKET_OFF)
> >                  /* Risk of overflow.  For instance, ptr + (1<<63) may be less
> >                   * than pkt_end, but that's because it's also less than pkt.
> >                   */
> >                  return;
> >
> > by adding u16 scalar the offset becomes bigger than MAX_PACKET_OFF.
> > Could you try clamping the value before 'data += ' ?
> >



[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux