fix(aya-ebpf): Add bounds check to SkBuff::load_bytes

This resolves the verifier error triggered by the test case added in the previous commit
reviewable/pr1218/r5
Ryan Alameddine 1 month ago
parent 25aa5ebcf2
commit 0b3c37bf73

@ -10,7 +10,7 @@ use aya_ebpf_bindings::helpers::{
}; };
use aya_ebpf_cty::c_long; use aya_ebpf_cty::c_long;
use crate::{EbpfContext, bindings::__sk_buff}; use crate::{EbpfContext, bindings::__sk_buff, check_bounds_signed};
pub struct SkBuff { pub struct SkBuff {
pub skb: *mut __sk_buff, pub skb: *mut __sk_buff,
@ -88,8 +88,12 @@ impl SkBuff {
#[inline(always)] #[inline(always)]
pub fn load_bytes(&self, offset: usize, dst: &mut [u8]) -> Result<usize, c_long> { pub fn load_bytes(&self, offset: usize, dst: &mut [u8]) -> Result<usize, c_long> {
let len = usize::try_from(self.len()).map_err(|core::num::TryFromIntError { .. }| -1)?; let len = usize::try_from(self.len()).map_err(|core::num::TryFromIntError { .. }| -1)?;
// 0 byte reads will trip the verifier. We need to ensure that the valid range of values for len is at least 1.
let len = len.checked_sub(offset).ok_or(-1)?; let len = len.checked_sub(offset).ok_or(-1)?;
let len = len.min(dst.len()); let len = len.min(dst.len());
if !check_bounds_signed(len as i64, 1, dst.len() as i64) {
return Err(-1);
}
let len_u32 = u32::try_from(len).map_err(|core::num::TryFromIntError { .. }| -1)?; let len_u32 = u32::try_from(len).map_err(|core::num::TryFromIntError { .. }| -1)?;
let ret = unsafe { let ret = unsafe {
bpf_skb_load_bytes( bpf_skb_load_bytes(

@ -3,11 +3,10 @@
use aya_ebpf::{macros::socket_filter, programs::SkBuffContext}; use aya_ebpf::{macros::socket_filter, programs::SkBuffContext};
#[socket_filter] #[socket_filter]
pub fn read_one(ctx: SkBuffContext) -> i64 { pub fn read_one(ctx: SkBuffContext) -> i64 {
// Read 1 byte // Read 1 byte
let mut dst = [0; 1]; let mut dst = [0; 2];
let _ = ctx.load_bytes(0, &mut dst); let _ = ctx.load_bytes(0, &mut dst);
0 0

@ -10,8 +10,8 @@ mod rbpf;
mod relocations; mod relocations;
mod ring_buf; mod ring_buf;
mod smoke; mod smoke;
mod socket_filter;
mod strncmp; mod strncmp;
mod tcx; mod tcx;
mod uprobe_cookie; mod uprobe_cookie;
mod xdp; mod xdp;
mod socket_filter;

@ -1,13 +1,8 @@
use aya::{programs::SocketFilter, Ebpf}; use aya::{Ebpf, programs::SocketFilter};
#[test] #[test]
fn socket_filter_load() { fn socket_filter_load() {
let mut bpf = Ebpf::load(crate::SOCKET_FILTER).unwrap(); let mut bpf = Ebpf::load(crate::SOCKET_FILTER).unwrap();
let prog: &mut SocketFilter = bpf let prog: &mut SocketFilter = bpf.program_mut("read_one").unwrap().try_into().unwrap();
.program_mut("read_one")
.unwrap()
.try_into()
.unwrap();
prog.load().unwrap(); prog.load().unwrap();
}
}

Loading…
Cancel
Save