1*fae6e9adSlinfeng use super::super::Result; 2*fae6e9adSlinfeng use crate::bpf::map::BpfMap; 3*fae6e9adSlinfeng use crate::bpf::prog::util::VerifierLogLevel; 4*fae6e9adSlinfeng use crate::bpf::prog::BpfProg; 5*fae6e9adSlinfeng use crate::filesystem::vfs::file::FileDescriptorVec; 6*fae6e9adSlinfeng use crate::include::bindings::linux_bpf::*; 7*fae6e9adSlinfeng use crate::libs::casting::DowncastArc; 8*fae6e9adSlinfeng use crate::libs::rwlock::RwLock; 9*fae6e9adSlinfeng use alloc::{sync::Arc, vec::Vec}; 10*fae6e9adSlinfeng use log::{error, info}; 11*fae6e9adSlinfeng use rbpf::ebpf; 12*fae6e9adSlinfeng use rbpf::ebpf::to_insn_vec; 13*fae6e9adSlinfeng use system_error::SystemError; 14*fae6e9adSlinfeng 15*fae6e9adSlinfeng /// The BPF program verifier. 16*fae6e9adSlinfeng /// 17*fae6e9adSlinfeng /// See https://docs.kernel.org/bpf/verifier.html 18*fae6e9adSlinfeng #[derive(Debug)] 19*fae6e9adSlinfeng pub struct BpfProgVerifier<'a> { 20*fae6e9adSlinfeng prog: BpfProg, 21*fae6e9adSlinfeng _log_level: VerifierLogLevel, 22*fae6e9adSlinfeng _log_buf: &'a mut [u8], 23*fae6e9adSlinfeng } 24*fae6e9adSlinfeng 25*fae6e9adSlinfeng impl<'a> BpfProgVerifier<'a> { new(prog: BpfProg, log_level: VerifierLogLevel, log_buf: &'a mut [u8]) -> Self26*fae6e9adSlinfeng pub fn new(prog: BpfProg, log_level: VerifierLogLevel, log_buf: &'a mut [u8]) -> Self { 27*fae6e9adSlinfeng Self { 28*fae6e9adSlinfeng prog, 29*fae6e9adSlinfeng _log_level: log_level, 30*fae6e9adSlinfeng _log_buf: log_buf, 31*fae6e9adSlinfeng } 32*fae6e9adSlinfeng } 33*fae6e9adSlinfeng /// Relocate the program. 34*fae6e9adSlinfeng /// 35*fae6e9adSlinfeng /// This function will relocate the program, and update the program's instructions. relocation(&mut self, fd_table: &Arc<RwLock<FileDescriptorVec>>) -> Result<()>36*fae6e9adSlinfeng fn relocation(&mut self, fd_table: &Arc<RwLock<FileDescriptorVec>>) -> Result<()> { 37*fae6e9adSlinfeng let instructions = self.prog.insns_mut(); 38*fae6e9adSlinfeng let mut fmt_insn = to_insn_vec(instructions); 39*fae6e9adSlinfeng let mut index = 0; 40*fae6e9adSlinfeng let mut raw_file_ptr = vec![]; 41*fae6e9adSlinfeng loop { 42*fae6e9adSlinfeng if index >= fmt_insn.len() { 43*fae6e9adSlinfeng break; 44*fae6e9adSlinfeng } 45*fae6e9adSlinfeng let mut insn = fmt_insn[index].clone(); 46*fae6e9adSlinfeng if insn.opc == ebpf::LD_DW_IMM { 47*fae6e9adSlinfeng // relocate the instruction 48*fae6e9adSlinfeng let mut next_insn = fmt_insn[index + 1].clone(); 49*fae6e9adSlinfeng // the imm is the map_fd because user lib has already done the relocation 50*fae6e9adSlinfeng let map_fd = insn.imm as usize; 51*fae6e9adSlinfeng let src_reg = insn.src; 52*fae6e9adSlinfeng // See https://www.kernel.org/doc/html/latest/bpf/standardization/instruction-set.html#id23 53*fae6e9adSlinfeng let ptr = match src_reg as u32 { 54*fae6e9adSlinfeng BPF_PSEUDO_MAP_VALUE => { 55*fae6e9adSlinfeng // dst = map_val(map_by_fd(imm)) + next_imm 56*fae6e9adSlinfeng // map_val(map) gets the address of the first value in a given map 57*fae6e9adSlinfeng let file = fd_table 58*fae6e9adSlinfeng .read() 59*fae6e9adSlinfeng .get_file_by_fd(map_fd as i32) 60*fae6e9adSlinfeng .ok_or(SystemError::EBADF)?; 61*fae6e9adSlinfeng let bpf_map = file 62*fae6e9adSlinfeng .inode() 63*fae6e9adSlinfeng .downcast_arc::<BpfMap>() 64*fae6e9adSlinfeng .ok_or(SystemError::EINVAL)?; 65*fae6e9adSlinfeng let first_value_ptr = 66*fae6e9adSlinfeng bpf_map.inner_map().lock().first_value_ptr()? as usize; 67*fae6e9adSlinfeng let offset = next_insn.imm as usize; 68*fae6e9adSlinfeng info!( 69*fae6e9adSlinfeng "Relocate for BPF_PSEUDO_MAP_VALUE, instruction index: {}, map_fd: {}", 70*fae6e9adSlinfeng index, map_fd 71*fae6e9adSlinfeng ); 72*fae6e9adSlinfeng Some(first_value_ptr + offset) 73*fae6e9adSlinfeng } 74*fae6e9adSlinfeng BPF_PSEUDO_MAP_FD => { 75*fae6e9adSlinfeng // dst = map_by_fd(imm) 76*fae6e9adSlinfeng // map_by_fd(imm) means to convert a 32-bit file descriptor into an address of a map 77*fae6e9adSlinfeng let bpf_map = fd_table 78*fae6e9adSlinfeng .read() 79*fae6e9adSlinfeng .get_file_by_fd(map_fd as i32) 80*fae6e9adSlinfeng .ok_or(SystemError::EBADF)? 81*fae6e9adSlinfeng .inode() 82*fae6e9adSlinfeng .downcast_arc::<BpfMap>() 83*fae6e9adSlinfeng .ok_or(SystemError::EINVAL)?; 84*fae6e9adSlinfeng // todo!(warning: We need release after prog unload) 85*fae6e9adSlinfeng let map_ptr = Arc::into_raw(bpf_map) as usize; 86*fae6e9adSlinfeng info!( 87*fae6e9adSlinfeng "Relocate for BPF_PSEUDO_MAP_FD, instruction index: {}, map_fd: {}, ptr: {:#x}", 88*fae6e9adSlinfeng index, map_fd, map_ptr 89*fae6e9adSlinfeng ); 90*fae6e9adSlinfeng raw_file_ptr.push(map_ptr); 91*fae6e9adSlinfeng Some(map_ptr) 92*fae6e9adSlinfeng } 93*fae6e9adSlinfeng ty => { 94*fae6e9adSlinfeng error!( 95*fae6e9adSlinfeng "relocation for ty: {} not implemented, instruction index: {}", 96*fae6e9adSlinfeng ty, index 97*fae6e9adSlinfeng ); 98*fae6e9adSlinfeng None 99*fae6e9adSlinfeng } 100*fae6e9adSlinfeng }; 101*fae6e9adSlinfeng if let Some(ptr) = ptr { 102*fae6e9adSlinfeng // The current ins store the map_data_ptr low 32 bits, 103*fae6e9adSlinfeng // the next ins store the map_data_ptr high 32 bits 104*fae6e9adSlinfeng insn.imm = ptr as i32; 105*fae6e9adSlinfeng next_insn.imm = (ptr >> 32) as i32; 106*fae6e9adSlinfeng fmt_insn[index] = insn; 107*fae6e9adSlinfeng fmt_insn[index + 1] = next_insn; 108*fae6e9adSlinfeng index += 2; 109*fae6e9adSlinfeng } else { 110*fae6e9adSlinfeng index += 1; 111*fae6e9adSlinfeng } 112*fae6e9adSlinfeng } else { 113*fae6e9adSlinfeng index += 1; 114*fae6e9adSlinfeng } 115*fae6e9adSlinfeng } 116*fae6e9adSlinfeng let fmt_insn = fmt_insn 117*fae6e9adSlinfeng .iter() 118*fae6e9adSlinfeng .flat_map(|ins| ins.to_vec()) 119*fae6e9adSlinfeng .collect::<Vec<u8>>(); 120*fae6e9adSlinfeng instructions.copy_from_slice(&fmt_insn); 121*fae6e9adSlinfeng for ptr in raw_file_ptr { 122*fae6e9adSlinfeng self.prog.insert_map(ptr); 123*fae6e9adSlinfeng } 124*fae6e9adSlinfeng Ok(()) 125*fae6e9adSlinfeng } 126*fae6e9adSlinfeng verify(mut self, fd_table: &Arc<RwLock<FileDescriptorVec>>) -> Result<BpfProg>127*fae6e9adSlinfeng pub fn verify(mut self, fd_table: &Arc<RwLock<FileDescriptorVec>>) -> Result<BpfProg> { 128*fae6e9adSlinfeng self.relocation(fd_table)?; 129*fae6e9adSlinfeng Ok(self.prog) 130*fae6e9adSlinfeng } 131*fae6e9adSlinfeng } 132