xref: /DragonOS/kernel/src/bpf/prog/verifier.rs (revision fae6e9ade46a52976ad5d099643d51cc20876448)
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