diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index 7be24f67..791959f1 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -13,10 +13,11 @@ use aya_obj::{ FuncLinkage, FuncProto, FuncSecInfo, Int, IntEncoding, LineSecInfo, Ptr, TypeTag, Var, VarLinkage, }, - copy_instructions, generated::{ - bpf_attach_type, bpf_attr, bpf_btf_info, bpf_cmd, bpf_insn, bpf_link_info, bpf_map_info, - bpf_map_type, bpf_prog_info, bpf_prog_type, bpf_stats_type, BPF_F_REPLACE, + bpf_attach_type, bpf_attr, bpf_btf_info, bpf_cmd, bpf_func_id::*, bpf_insn, bpf_link_info, + bpf_map_info, bpf_map_type, bpf_prog_info, bpf_prog_type, bpf_stats_type, BPF_ALU64, + BPF_CALL, BPF_DW, BPF_EXIT, BPF_F_REPLACE, BPF_IMM, BPF_JMP, BPF_K, BPF_LD, BPF_MEM, + BPF_MOV, BPF_PSEUDO_MAP_VALUE, BPF_ST, BPF_SUB, BPF_X, }, maps::{bpf_map_def, LegacyMap}, EbpfSectionKind, VerifierLog, @@ -741,6 +742,16 @@ pub(crate) fn is_prog_name_supported() -> bool { }) } +fn new_insn(code: u8, dst_reg: u8, src_reg: u8, offset: i16, imm: i32) -> bpf_insn { + let mut insn = unsafe { mem::zeroed::() }; + insn.code = code; + insn.set_dst_reg(dst_reg); + insn.set_src_reg(src_reg); + insn.off = offset; + insn.imm = imm; + insn +} + fn with_trivial_prog(op: F) -> T where F: FnOnce(&mut bpf_attr) -> T, @@ -748,20 +759,13 @@ where let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_3 }; - // The fields conforming an encoded basic instruction are stored in the following order: - // opcode:8 src_reg:4 dst_reg:4 offset:16 imm:32 - In little-endian BPF. - // opcode:8 dst_reg:4 src_reg:4 offset:16 imm:32 - In big-endian BPF. - // Multi-byte fields ('imm' and 'offset') are stored using endian order. - // https://www.kernel.org/doc/html/v6.4-rc7/bpf/instruction-set.html#instruction-encoding - let prog: &[u8] = &[ - 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r0 = 0 - 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit - ]; + let mov64_imm = (BPF_ALU64 | BPF_MOV | BPF_K) as _; + let exit = (BPF_JMP | BPF_EXIT) as _; + let insns = [new_insn(mov64_imm, 0, 0, 0, 0), new_insn(exit, 0, 0, 0, 0)]; let gpl = c"GPL"; u.license = gpl.as_ptr() as u64; - let insns = copy_instructions(prog).unwrap(); u.insn_cnt = insns.len() as u32; u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT as u32; @@ -801,34 +805,23 @@ pub(crate) fn is_probe_read_kernel_supported() -> bool { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_3 }; - // The fields conforming an encoded basic instruction are stored in the following order: - // opcode:8 src_reg:4 dst_reg:4 offset:16 imm:32 - In little-endian BPF. - // opcode:8 dst_reg:4 src_reg:4 offset:16 imm:32 - In big-endian BPF. - // Multi-byte fields ('imm' and 'offset') are stored using endian order. - // https://www.kernel.org/doc/html/v6.4-rc7/bpf/instruction-set.html#instruction-encoding - #[cfg(target_endian = "little")] - let prog: &[u8] = &[ - 0xbf, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // r1 = r10 - 0x07, 0x01, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, // r1 -= 8 - 0xb7, 0x02, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, // r2 = 8 - 0xb7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // r3 = 0 - 0x85, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, // call 113 - 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit - ]; - #[cfg(target_endian = "big")] - let prog: &[u8] = &[ - 0xbf, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // r1 = r10 - 0x07, 0x10, 0x00, 0x00, 0xff, 0xff, 0xff, 0xf8, // r1 -= 8 - 0xb7, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, // r2 = 8 - 0xb7, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // r3 = 0 - 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, // call 113 - 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit + let mov64_reg = (BPF_ALU64 | BPF_MOV | BPF_X) as _; + let sub64_imm = (BPF_ALU64 | BPF_SUB | BPF_K) as _; + let mov64_imm = (BPF_ALU64 | BPF_MOV | BPF_K) as _; + let call = (BPF_JMP | BPF_CALL) as _; + let exit = (BPF_JMP | BPF_EXIT) as _; + let insns = [ + new_insn(mov64_reg, 1, 10, 0, 0), + new_insn(sub64_imm, 1, 0, 0, 8), + new_insn(mov64_imm, 2, 0, 0, 8), + new_insn(mov64_imm, 3, 0, 0, 0), + new_insn(call, 0, 0, 0, BPF_FUNC_probe_read_kernel as _), + new_insn(exit, 0, 0, 0, 0), ]; let gpl = c"GPL"; u.license = gpl.as_ptr() as u64; - let insns = copy_instructions(prog).unwrap(); u.insn_cnt = insns.len() as u32; u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT as u32; @@ -860,30 +853,6 @@ pub(crate) fn is_bpf_global_data_supported() -> bool { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_3 }; - // The fields conforming an encoded basic instruction are stored in the following order: - // opcode:8 src_reg:4 dst_reg:4 offset:16 imm:32 - In little-endian BPF. - // opcode:8 dst_reg:4 src_reg:4 offset:16 imm:32 - In big-endian BPF. - // Multi-byte fields ('imm' and 'offset') are stored using endian order. - // https://www.kernel.org/doc/html/v6.4-rc7/bpf/instruction-set.html#instruction-encoding - #[cfg(target_endian = "little")] - let prog: &[u8] = &[ - 0x18, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ld_pseudo r1, 0x2, 0x0 - 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // - 0x7a, 0x01, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, // stdw [r1 + 0x0], 0x2a - 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r0 = 0 - 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit - ]; - #[cfg(target_endian = "big")] - let prog: &[u8] = &[ - 0x18, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, // ld_pseudo r1, 0x2, 0x0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // - 0x7a, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, // stdw [r1 + 0x0], 0x2a - 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r0 = 0 - 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit - ]; - - let mut insns = copy_instructions(prog).unwrap(); - let map = MapData::create( aya_obj::Map::Legacy(LegacyMap { def: bpf_map_def { @@ -903,7 +872,19 @@ pub(crate) fn is_bpf_global_data_supported() -> bool { ); if let Ok(map) = map { - insns[0].imm = map.fd().as_fd().as_raw_fd(); + let ld_map_value = (BPF_LD | BPF_DW | BPF_IMM) as _; + let pseudo_map_value = BPF_PSEUDO_MAP_VALUE as _; + let fd = map.fd().as_fd().as_raw_fd(); + let st_mem = (BPF_ST | BPF_DW | BPF_MEM) as _; + let mov64_imm = (BPF_ALU64 | BPF_MOV | BPF_K) as _; + let exit = (BPF_JMP | BPF_EXIT) as _; + let insns = [ + new_insn(ld_map_value, 1, pseudo_map_value, 0, fd), + new_insn(0, 0, 0, 0, 0), + new_insn(st_mem, 1, 0, 0, 42), + new_insn(mov64_imm, 0, 0, 0, 0), + new_insn(exit, 0, 0, 0, 0), + ]; let gpl = c"GPL"; u.license = gpl.as_ptr() as u64; @@ -921,26 +902,16 @@ pub(crate) fn is_bpf_cookie_supported() -> bool { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_3 }; - // The fields conforming an encoded basic instruction are stored in the following order: - // opcode:8 src_reg:4 dst_reg:4 offset:16 imm:32 - In little-endian BPF. - // opcode:8 dst_reg:4 src_reg:4 offset:16 imm:32 - In big-endian BPF. - // Multi-byte fields ('imm' and 'offset') are stored using endian order. - // https://www.kernel.org/doc/html/v6.4-rc7/bpf/instruction-set.html#instruction-encoding - #[cfg(target_endian = "little")] - let prog: &[u8] = &[ - 0x85, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, // call bpf_get_attach_cookie - 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit - ]; - #[cfg(target_endian = "big")] - let prog: &[u8] = &[ - 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, // call bpf_get_attach_cookie - 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit + let call = (BPF_JMP | BPF_CALL) as _; + let exit = (BPF_JMP | BPF_EXIT) as _; + let insns = [ + new_insn(call, 0, 0, 0, BPF_FUNC_get_attach_cookie as _), + new_insn(exit, 0, 0, 0, 0), ]; let gpl = c"GPL"; u.license = gpl.as_ptr() as u64; - let insns = copy_instructions(prog).unwrap(); u.insn_cnt = insns.len() as u32; u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_KPROBE as u32;