diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index b7eb9447..4f417fc0 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -28,8 +28,8 @@ use crate::{ }, sys::{ bpf_load_btf, bpf_map_freeze, bpf_map_update_elem_ptr, is_btf_datasec_supported, - is_btf_float_supported, is_btf_func_global_supported, is_btf_func_supported, - is_btf_supported, is_prog_name_supported, + is_btf_decl_tag_supported, is_btf_float_supported, is_btf_func_global_supported, + is_btf_func_supported, is_btf_supported, is_btf_type_tag_supported, is_prog_name_supported, }, util::{bytes_of, possible_cpus, VerifierLog, POSSIBLE_CPUS}, }; @@ -91,6 +91,8 @@ pub(crate) struct Features { pub btf_func_global: bool, pub btf_datasec: bool, pub btf_float: bool, + pub btf_decl_tag: bool, + pub btf_type_tag: bool, } impl Features { @@ -119,6 +121,12 @@ impl Features { self.btf_float = is_btf_float_supported(); debug!("[FEAT PROBE] BTF float support: {}", self.btf_float); + + self.btf_decl_tag = is_btf_decl_tag_supported(); + debug!("[FEAT PROBE] BTF decl_tag support: {}", self.btf_decl_tag); + + self.btf_type_tag = is_btf_type_tag_supported(); + debug!("[FEAT PROBE] BTF type_tag support: {}", self.btf_type_tag); } } } diff --git a/aya/src/obj/btf/btf.rs b/aya/src/obj/btf/btf.rs index ed42627e..1b4bc3a7 100644 --- a/aya/src/obj/btf/btf.rs +++ b/aya/src/obj/btf/btf.rs @@ -323,7 +323,7 @@ impl Btf { use BtfType::*; match ty { - Volatile(ty) | Const(ty) | Restrict(ty) | Typedef(ty) => { + Volatile(ty) | Const(ty) | Restrict(ty) | Typedef(ty) | TypeTag(ty) => { // Safety: union type_id = unsafe { ty.__bindgen_anon_1.type_ }; continue; @@ -391,7 +391,13 @@ impl Btf { unsafe { ty.__bindgen_anon_1.size as usize } } Ptr(_) => mem::size_of::<*const c_void>(), // FIXME - Typedef(ty) | Volatile(ty) | Const(ty) | Restrict(ty) | Var(ty, _) => { + Typedef(ty) + | Volatile(ty) + | Const(ty) + | Restrict(ty) + | Var(ty, _) + | DeclTag(ty, _) + | TypeTag(ty) => { // Safety: union type_id = unsafe { ty.__bindgen_anon_1.type_ }; continue; @@ -606,6 +612,24 @@ impl Btf { btf.add_type(BtfType::Float(*ty)); } } + BtfType::DeclTag(ty, btf_decl_tag) => { + if !features.btf_decl_tag { + debug!("{}: not supported. replacing with INT", kind); + let int_type = BtfType::new_int(ty.name_off, 1, 0, 0); + btf.add_type(int_type); + } else { + btf.add_type(BtfType::DeclTag(*ty, *btf_decl_tag)); + } + } + BtfType::TypeTag(ty) => { + if !features.btf_type_tag { + debug!("{}: not supported. replacing with CONST", kind); + let const_type = BtfType::new_const(unsafe { ty.__bindgen_anon_1.type_ }); + btf.add_type(const_type); + } else { + btf.add_type(BtfType::TypeTag(*ty)); + } + } // The type does not need sanitizing ty => { btf.add_type(ty.clone()); @@ -1028,6 +1052,14 @@ mod tests { let func = BtfType::new_func(add, func_proto_type_id, btf_func_linkage::BTF_FUNC_GLOBAL); btf.add_type(func); + let name_offset = btf.add_string("int".to_string()); + let type_tag = BtfType::new_type_tag(name_offset, int_type_id); + btf.add_type(type_tag); + + let name_offset = btf.add_string("decl_tag".to_string()); + let decl_tag = BtfType::new_decl_tag(name_offset, var_type_id, -1); + btf.add_type(decl_tag); + let cases = HashMap::from([ ( "noop", @@ -1038,6 +1070,8 @@ mod tests { btf_func_global: true, btf_datasec: true, btf_float: true, + btf_decl_tag: true, + btf_type_tag: true, }, ), ( @@ -1049,6 +1083,8 @@ mod tests { btf_func_global: true, btf_datasec: false, btf_float: true, + btf_decl_tag: true, + btf_type_tag: true, }, ), ( @@ -1060,6 +1096,8 @@ mod tests { btf_func_global: true, btf_datasec: true, btf_float: false, + btf_decl_tag: true, + btf_type_tag: true, }, ), ( @@ -1071,6 +1109,8 @@ mod tests { btf_func_global: true, btf_datasec: true, btf_float: true, + btf_decl_tag: true, + btf_type_tag: true, }, ), ( @@ -1082,6 +1122,34 @@ mod tests { btf_func_global: false, btf_datasec: true, btf_float: true, + btf_decl_tag: true, + btf_type_tag: true, + }, + ), + ( + "no decl tag", + Features { + bpf_name: true, + btf: true, + btf_func: true, + btf_func_global: true, + btf_datasec: true, + btf_float: true, + btf_decl_tag: false, + btf_type_tag: true, + }, + ), + ( + "no type tag", + Features { + bpf_name: true, + btf: true, + btf_func: true, + btf_func_global: true, + btf_datasec: true, + btf_float: true, + btf_decl_tag: true, + btf_type_tag: false, }, ), ( @@ -1093,6 +1161,8 @@ mod tests { btf_func_global: false, btf_datasec: false, btf_float: false, + btf_decl_tag: false, + btf_type_tag: false, }, ), ]); diff --git a/aya/src/obj/btf/types.rs b/aya/src/obj/btf/types.rs index b046d5e3..d1fdfc02 100644 --- a/aya/src/obj/btf/types.rs +++ b/aya/src/obj/btf/types.rs @@ -8,11 +8,12 @@ use object::Endianness; use crate::{ generated::{ - btf_array, btf_enum, btf_func_linkage, btf_member, btf_param, btf_type, + btf_array, btf_decl_tag, btf_enum, btf_func_linkage, btf_member, btf_param, btf_type, btf_type__bindgen_ty_1, btf_var, btf_var_secinfo, BTF_KIND_ARRAY, BTF_KIND_CONST, - BTF_KIND_DATASEC, BTF_KIND_ENUM, BTF_KIND_FLOAT, BTF_KIND_FUNC, BTF_KIND_FUNC_PROTO, - BTF_KIND_FWD, BTF_KIND_INT, BTF_KIND_PTR, BTF_KIND_RESTRICT, BTF_KIND_STRUCT, - BTF_KIND_TYPEDEF, BTF_KIND_UNION, BTF_KIND_UNKN, BTF_KIND_VAR, BTF_KIND_VOLATILE, + BTF_KIND_DATASEC, BTF_KIND_DECL_TAG, BTF_KIND_ENUM, BTF_KIND_FLOAT, BTF_KIND_FUNC, + BTF_KIND_FUNC_PROTO, BTF_KIND_FWD, BTF_KIND_INT, BTF_KIND_PTR, BTF_KIND_RESTRICT, + BTF_KIND_STRUCT, BTF_KIND_TYPEDEF, BTF_KIND_TYPE_TAG, BTF_KIND_UNION, BTF_KIND_UNKN, + BTF_KIND_VAR, BTF_KIND_VOLATILE, }, obj::btf::{Btf, BtfError, MAX_RESOLVE_DEPTH}, }; @@ -36,6 +37,8 @@ pub(crate) enum BtfType { FuncProto(btf_type, Vec), Var(btf_type, btf_var), DataSec(btf_type, Vec), + DeclTag(btf_type, btf_decl_tag), + TypeTag(btf_type), } #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -58,6 +61,8 @@ pub(crate) enum BtfKind { FuncProto = BTF_KIND_FUNC_PROTO, Var = BTF_KIND_VAR, DataSec = BTF_KIND_DATASEC, + DeclTag = BTF_KIND_DECL_TAG, + TypeTag = BTF_KIND_TYPE_TAG, } impl TryFrom for BtfKind { @@ -83,6 +88,8 @@ impl TryFrom for BtfKind { BTF_KIND_FUNC_PROTO => FuncProto, BTF_KIND_VAR => Var, BTF_KIND_DATASEC => DataSec, + BTF_KIND_DECL_TAG => DeclTag, + BTF_KIND_TYPE_TAG => TypeTag, kind => return Err(BtfError::InvalidTypeKind { kind }), }) } @@ -108,6 +115,8 @@ impl Display for BtfKind { BtfKind::FuncProto => write!(f, "[FUNC_PROTO]"), BtfKind::Var => write!(f, "[VAR]"), BtfKind::DataSec => write!(f, "[DATASEC]"), + BtfKind::DeclTag => write!(f, "[DECL_TAG]"), + BtfKind::TypeTag => write!(f, "[TYPE_TAG]"), } } } @@ -177,6 +186,8 @@ impl BtfType { BtfKind::FuncProto => FuncProto(ty, unsafe { read_array(data, vlen)? }), BtfKind::Var => Var(ty, unsafe { read(data)? }), BtfKind::DataSec => DataSec(ty, unsafe { read_array(data, vlen)? }), + BtfKind::DeclTag => DeclTag(ty, unsafe { read(data)? }), + BtfKind::TypeTag => TypeTag(ty), }) } @@ -193,7 +204,8 @@ impl BtfType { | BtfType::Ptr(btf_type) | BtfType::Typedef(btf_type) | BtfType::Func(btf_type) - | BtfType::Float(btf_type) => bytes_of::(btf_type).to_vec(), + | BtfType::Float(btf_type) + | BtfType::TypeTag(btf_type) => bytes_of::(btf_type).to_vec(), BtfType::Int(btf_type, len) => { let mut buf = bytes_of::(btf_type).to_vec(); buf.append(&mut len.to_ne_bytes().to_vec()); @@ -238,6 +250,11 @@ impl BtfType { buf } BtfType::Unknown => vec![], + BtfType::DeclTag(btf_type, btf_decl_tag) => { + let mut buf = bytes_of::(btf_type).to_vec(); + buf.append(&mut bytes_of::(btf_decl_tag).to_vec()); + buf + } } } @@ -248,7 +265,7 @@ impl BtfType { match self { Unknown => ty_size, Fwd(_) | Const(_) | Volatile(_) | Restrict(_) | Ptr(_) | Typedef(_) | Func(_) - | Float(_) => ty_size, + | Float(_) | TypeTag(_) => ty_size, Int(_, _) => ty_size + mem::size_of::(), Enum(ty, _) => ty_size + type_vlen(ty) * mem::size_of::(), Array(_, _) => ty_size + mem::size_of::(), @@ -257,6 +274,7 @@ impl BtfType { FuncProto(ty, _) => ty_size + type_vlen(ty) * mem::size_of::(), Var(_, _) => ty_size + mem::size_of::(), DataSec(ty, _) => ty_size + type_vlen(ty) * mem::size_of::(), + DeclTag(_, _) => ty_size + mem::size_of::(), } } @@ -280,6 +298,8 @@ impl BtfType { FuncProto(ty, _) => ty, Var(ty, _) => ty, DataSec(ty, _) => ty, + DeclTag(ty, _) => ty, + TypeTag(ty) => ty, }) } @@ -408,6 +428,43 @@ impl BtfType { }; BtfType::Array(btf_type, btf_array) } + + pub(crate) fn new_decl_tag(name_off: u32, type_: u32, component_idx: i32) -> BtfType { + let info = (BTF_KIND_DECL_TAG) << 24; + let mut btf_type = unsafe { std::mem::zeroed::() }; + btf_type.name_off = name_off; + btf_type.info = info; + btf_type.__bindgen_anon_1.type_ = type_; + let btf_decl_tag = btf_decl_tag { component_idx }; + BtfType::DeclTag(btf_type, btf_decl_tag) + } + + pub(crate) fn new_type_tag(name_off: u32, type_: u32) -> BtfType { + let info = (BTF_KIND_TYPE_TAG) << 24; + let mut btf_type = unsafe { std::mem::zeroed::() }; + btf_type.name_off = name_off; + btf_type.info = info; + btf_type.__bindgen_anon_1.type_ = type_; + BtfType::TypeTag(btf_type) + } + + pub(crate) fn new_ptr(type_: u32) -> BtfType { + let info = (BTF_KIND_PTR) << 24; + let mut btf_type = unsafe { std::mem::zeroed::() }; + btf_type.name_off = 0; + btf_type.info = info; + btf_type.__bindgen_anon_1.type_ = type_; + BtfType::Ptr(btf_type) + } + + pub(crate) fn new_const(type_: u32) -> BtfType { + let info = (BTF_KIND_CONST) << 24; + let mut btf_type = unsafe { std::mem::zeroed::() }; + btf_type.name_off = 0; + btf_type.info = info; + btf_type.__bindgen_anon_1.type_ = type_; + BtfType::Const(btf_type) + } } fn type_kind(ty: &btf_type) -> Result { diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index 35d13640..3f198360 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -670,6 +670,66 @@ pub(crate) fn is_btf_float_supported() -> bool { } } +pub(crate) fn is_btf_decl_tag_supported() -> bool { + let mut btf = Btf::new(); + let name_offset = btf.add_string("int".to_string()); + let int_type = BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0); + let int_type_id = btf.add_type(int_type); + + let name_offset = btf.add_string("foo".to_string()); + let var_type = BtfType::new_var(name_offset, int_type_id, BTF_VAR_STATIC); + let var_type_id = btf.add_type(var_type); + + let name_offset = btf.add_string("decl_tag".to_string()); + let decl_tag = BtfType::new_decl_tag(name_offset, var_type_id, -1); + btf.add_type(decl_tag); + + let btf_bytes = btf.to_bytes(); + + let mut attr = unsafe { mem::zeroed::() }; + let u = unsafe { &mut attr.__bindgen_anon_7 }; + u.btf = btf_bytes.as_ptr() as u64; + u.btf_size = btf_bytes.len() as u32; + + match sys_bpf(bpf_cmd::BPF_BTF_LOAD, &attr) { + Ok(v) => { + let fd = v as RawFd; + unsafe { close(fd) }; + true + } + Err(_) => false, + } +} + +pub(crate) fn is_btf_type_tag_supported() -> bool { + let mut btf = Btf::new(); + + let int_type = BtfType::new_int(0, 4, BTF_INT_SIGNED, 0); + let int_type_id = btf.add_type(int_type); + + let name_offset = btf.add_string("int".to_string()); + let type_tag = BtfType::new_type_tag(name_offset, int_type_id); + let type_tag_type = btf.add_type(type_tag); + + btf.add_type(BtfType::new_ptr(type_tag_type)); + + let btf_bytes = btf.to_bytes(); + + let mut attr = unsafe { mem::zeroed::() }; + let u = unsafe { &mut attr.__bindgen_anon_7 }; + u.btf = btf_bytes.as_ptr() as u64; + u.btf_size = btf_bytes.len() as u32; + + match sys_bpf(bpf_cmd::BPF_BTF_LOAD, &attr) { + Ok(v) => { + let fd = v as RawFd; + unsafe { close(fd) }; + true + } + Err(_) => false, + } +} + pub fn sys_bpf(cmd: bpf_cmd, attr: &bpf_attr) -> SysResult { syscall(Syscall::Bpf { cmd, attr }) }