aya
aya copied to clipboard
Access packet data as &[u8] from XdpContext
Hi,
I'm trying to use pdu
to do some packet parsing from the XdpContext
.
This seemed to work at some point in redbpf
examples at https://github.com/rebpf/rebpf/blob/50e235721228c1ece2c685f9357a954bd4a322d3/examples/packet_parser/src/kern.rs#L44
[EDIT] So I ported this function to XdpContext in aya-bpf here source : https://sourcegraph.com/github.com/rebpf/rebpf@50e235721228c1ece2c685f9357a954bd4a322d3/-/blob/rebpf/src/libbpf.rs?L547:12#tab=def
I'm trying to access it like so :
#[inline(always)]
fn try_dns_snoop(ctx: XdpContext) -> Result<u32, Error> {
let buf: &[u8] = if let Some(buf) = ctx.data_buffer() {
buf
} else {
return Ok(xdp_action::XDP_PASS);
};
//let ether = EthernetPdu::new(buf)?;
let first_byte = buf[0];
let log_entry = PacketLog {
first_byte: first_byte,
};
unsafe {
EVENTS.output(&ctx, &log_entry, 0);
}
Ok(xdp_action::XDP_PASS)
}
But the verifier complains about out of packet access :
0: R1=ctx(id=0,off=0,imm=0) R10=fp0
0: (61) r2 = *(u32 *)(r1 +0)
1: R1=ctx(id=0,off=0,imm=0) R2_w=pkt(id=0,off=0,r=0,imm=0) R10=fp0
1: (15) if r2 == 0x0 goto pc+17
R1=ctx(id=0,off=0,imm=0) R2_w=pkt(id=0,off=0,r=0,imm=0) R10=fp0
2: R1=ctx(id=0,off=0,imm=0) R2_w=pkt(id=0,off=0,r=0,imm=0) R10=fp0
2: (61) r3 = *(u32 *)(r1 +4)
3: R1=ctx(id=0,off=0,imm=0) R2_w=pkt(id=0,off=0,r=0,imm=0) R3_w=pkt_end(id=0,off=0,imm=0) R10=fp0
3: (3d) if r2 >= r3 goto pc+15
R1=ctx(id=0,off=0,imm=0) R2_w=pkt(id=0,off=0,r=0,imm=0) R3_w=pkt_end(id=0,off=0,imm=0) R10=fp0
4: R1=ctx(id=0,off=0,imm=0) R2_w=pkt(id=0,off=0,r=0,imm=0) R3_w=pkt_end(id=0,off=0,imm=0) R10=fp0
4: (71) r2 = *(u8 *)(r2 +0)
invalid access to packet, off=0 size=1, R2(id=0,off=0,r=0)
R2 offset is outside of the packet
verification time 29 usec
stack depth 0
processed 5 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
Am I holding this wrong ?
I can't see the source of the function that you've ported - both links show redbpf code, not aya.
You need to make sure that you check that the offset you are reading is within the bounds of the packet or the verifier will complain like this. See https://aya-rs.github.io/book/start/logging-packets.html#getting-packet-data-from-the-context for an example function that has a check like this.
In your example, you'd need to check first_byte
is in bounds before you use it.
Hi dave-tucker, and thanks for the response :) I've updated the issue with a link to my fork. So I understand it now, every access needs to be verified, you cannot just validate the buffer up until some point once and go ham.
This means pdu
needs to be changed quite a bit to work in a bpf context.
I've found a fork here that does this (partially) https://github.com/uccidibuti/pdu
Now I can parse the data into a EthernetPdu
and use (some of) pdu's api.
I think it would be nice to have those methods I added back in XdpContext, so i'll open a PR
Hi dave-tucker, and thanks for the response :) I've updated the issue with a link to my fork. So I understand it now, every access needs to be verified, you cannot just validate the buffer up until some point once and go ham.
This is why I didn't add a method that returns a slice btw. Returning a slice but then not being able to use it like you would use any other slice in rust doesn't seem very intuitive.
I'm very much in favor of having an API that returns something slice-like, but it needs to work without having to do extra validation with pointers and stuff, else I think it actually becomes worse than telling people to just use pointers.
I'm very much in favor of having an API that returns something slice-like,
To expand a bit on this: it should be possible to create an API that returns a slice (or something that behaves like a slice), that does packet boundary checks internally in a way that the verifier is able to follow. It will probably require a bit of back and forth with the verifier, but I believe it should be possible.
Yes I'm seeing that now from looking at the bpf branch of pdu from https://github.com/uccidibuti/pdu.
I'm very much in favor of having an API that returns something slice-like,
To expand a bit on this: it should be possible to create an API that returns a slice (or something that behaves like a slice), that does packet boundary checks internally in a way that the verifier is able to follow. It will probably require a bit of back and forth with the verifier, but I believe it should be possible.
I think that would be a very nice api.