xref: /DragonOS/kernel/crates/rbpf/src/interpreter.rs (revision 55e6f0b65f91b32638fd56581f711a816eccdcd1)
1 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
2 // Derived from uBPF <https://github.com/iovisor/ubpf>
3 // Copyright 2015 Big Switch Networks, Inc
4 //      (uBPF: VM architecture, parts of the interpreter, originally in C)
5 // Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
6 //      (Translation to Rust, MetaBuff/multiple classes addition, hashmaps for helpers)
7 
8 use crate::{
9     ebpf::{self, Insn},
10     helpers::BPF_FUNC_MAPPER,
11     stack::StackFrame,
12     *,
13 };
14 
15 #[cfg(not(feature = "user"))]
16 #[allow(unused)]
17 fn check_mem(
18     addr: u64,
19     len: usize,
20     access_type: &str,
21     insn_ptr: usize,
22     mbuff: &[u8],
23     mem: &[u8],
24     stack: &[u8],
25 ) -> Result<(), Error> {
26     log::trace!(
27         "check_mem: addr {:#x}, len {}, access_type {}, insn_ptr {}",
28         addr,
29         len,
30         access_type,
31         insn_ptr
32     );
33     log::trace!(
34         "check_mem: mbuff: {:#x}/{:#x}, mem: {:#x}/{:#x}, stack: {:#x}/{:#x}",
35         mbuff.as_ptr() as u64,
36         mbuff.len(),
37         mem.as_ptr() as u64,
38         mem.len(),
39         stack.as_ptr() as u64,
40         stack.len()
41     );
42     Ok(())
43 }
44 
45 #[cfg(feature = "user")]
46 fn check_mem(
47     addr: u64,
48     len: usize,
49     access_type: &str,
50     insn_ptr: usize,
51     mbuff: &[u8],
52     mem: &[u8],
53     stack: &[u8],
54 ) -> Result<(), Error> {
55     if let Some(addr_end) = addr.checked_add(len as u64) {
56         if mbuff.as_ptr() as u64 <= addr && addr_end <= mbuff.as_ptr() as u64 + mbuff.len() as u64 {
57             return Ok(());
58         }
59         if mem.as_ptr() as u64 <= addr && addr_end <= mem.as_ptr() as u64 + mem.len() as u64 {
60             return Ok(());
61         }
62         if stack.as_ptr() as u64 <= addr && addr_end <= stack.as_ptr() as u64 + stack.len() as u64 {
63             return Ok(());
64         }
65     }
66 
67     Err(Error::new(ErrorKind::Other, format!(
68         "Error: out of bounds memory {} (insn #{:?}), addr {:#x}, size {:?}\nmbuff: {:#x}/{:#x}, mem: {:#x}/{:#x}, stack: {:#x}/{:#x}",
69         access_type, insn_ptr, addr, len,
70         mbuff.as_ptr() as u64, mbuff.len(),
71         mem.as_ptr() as u64, mem.len(),
72         stack.as_ptr() as u64, stack.len()
73     )))
74 }
75 
76 #[inline]
77 fn do_jump(insn_ptr: &mut usize, insn: &Insn) {
78     *insn_ptr = (*insn_ptr as i16 + insn.off) as usize;
79 }
80 
81 #[allow(unknown_lints)]
82 #[allow(cyclomatic_complexity)]
83 pub fn execute_program(
84     prog_: Option<&[u8]>,
85     mem: &[u8],
86     mbuff: &[u8],
87     helpers: &HashMap<u32, ebpf::Helper>,
88 ) -> Result<u64, Error> {
89     const U32MAX: u64 = u32::MAX as u64;
90     const SHIFT_MASK_64: u64 = 0x3f;
91 
92     let prog = match prog_ {
93         Some(prog) => prog,
94         None => Err(Error::new(
95             ErrorKind::Other,
96             "Error: No program set, call prog_set() to load one",
97         ))?,
98     };
99     let mut stacks = Vec::new();
100     let stack = StackFrame::new();
101     // R1 points to beginning of memory area, R10 to stack
102     let mut reg: [u64; 11] = [
103         0,
104         0,
105         0,
106         0,
107         0,
108         0,
109         0,
110         0,
111         0,
112         0,
113         stack.as_ptr() as u64 + stack.len() as u64,
114     ];
115     stacks.push(stack);
116     if !mbuff.is_empty() {
117         reg[1] = mbuff.as_ptr() as u64;
118     } else if !mem.is_empty() {
119         reg[1] = mem.as_ptr() as u64;
120     }
121     let check_mem_load =
122         |stack: &[u8], addr: u64, len: usize, insn_ptr: usize| -> Result<(), Error> {
123             check_mem(addr, len, "load", insn_ptr, mbuff, mem, stack)
124         };
125     let check_mem_store =
126         |stack: &[u8], addr: u64, len: usize, insn_ptr: usize| -> Result<(), Error> {
127             check_mem(addr, len, "store", insn_ptr, mbuff, mem, stack)
128         };
129 
130     // Loop on instructions
131     let mut insn_ptr: usize = 0;
132     while insn_ptr * ebpf::INSN_SIZE < prog.len() {
133         let insn = ebpf::get_insn(prog, insn_ptr);
134         insn_ptr += 1;
135         let _dst = insn.dst as usize;
136         let _src = insn.src as usize;
137 
138         match insn.opc {
139             // BPF_LD class
140             // LD_ABS_* and LD_IND_* are supposed to load pointer to data from metadata buffer.
141             // Since this pointer is constant, and since we already know it (mem), do not
142             // bother re-fetching it, just use mem already.
143             ebpf::LD_ABS_B => {
144                 reg[0] = unsafe {
145                     let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u8;
146                     check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
147                     x.read_unaligned() as u64
148                 }
149             }
150             ebpf::LD_ABS_H => {
151                 reg[0] = unsafe {
152                     let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u16;
153                     check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
154                     x.read_unaligned() as u64
155                 }
156             }
157             ebpf::LD_ABS_W => {
158                 reg[0] = unsafe {
159                     let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u32;
160                     check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
161                     x.read_unaligned() as u64
162                 }
163             }
164             ebpf::LD_ABS_DW => {
165                 log::info!("executing LD_ABS_DW, set reg[{}] to {:#x}", _dst, insn.imm);
166                 reg[0] = unsafe {
167                     let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u64;
168                     check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
169                     x.read_unaligned()
170                 }
171             }
172             ebpf::LD_IND_B => {
173                 reg[0] = unsafe {
174                     let x =
175                         (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u8;
176                     check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
177                     x.read_unaligned() as u64
178                 }
179             }
180             ebpf::LD_IND_H => {
181                 reg[0] = unsafe {
182                     let x =
183                         (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u16;
184                     check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
185                     x.read_unaligned() as u64
186                 }
187             }
188             ebpf::LD_IND_W => {
189                 reg[0] = unsafe {
190                     let x =
191                         (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u32;
192                     check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
193                     x.read_unaligned() as u64
194                 }
195             }
196             ebpf::LD_IND_DW => {
197                 reg[0] = unsafe {
198                     let x =
199                         (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u64;
200                     check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
201                     x.read_unaligned()
202                 }
203             }
204 
205             ebpf::LD_DW_IMM => {
206                 let next_insn = ebpf::get_insn(prog, insn_ptr);
207                 insn_ptr += 1;
208                 // log::warn!(
209                 //     "executing LD_DW_IMM, set reg[{}] to {:#x}",
210                 //     _dst,
211                 //     ((insn.imm as u32) as u64) + ((next_insn.imm as u64) << 32)
212                 // );
213                 reg[_dst] = ((insn.imm as u32) as u64) + ((next_insn.imm as u64) << 32);
214             }
215 
216             // BPF_LDX class
217             ebpf::LD_B_REG => {
218                 reg[_dst] = unsafe {
219                     #[allow(clippy::cast_ptr_alignment)]
220                     let x = (reg[_src] as *const u8).offset(insn.off as isize);
221                     check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 1, insn_ptr)?;
222                     x.read_unaligned() as u64
223                 }
224             }
225             ebpf::LD_H_REG => {
226                 reg[_dst] = unsafe {
227                     #[allow(clippy::cast_ptr_alignment)]
228                     let x = (reg[_src] as *const u8).offset(insn.off as isize) as *const u16;
229                     check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 2, insn_ptr)?;
230                     x.read_unaligned() as u64
231                 }
232             }
233             ebpf::LD_W_REG => {
234                 reg[_dst] = unsafe {
235                     #[allow(clippy::cast_ptr_alignment)]
236                     let x = (reg[_src] as *const u8).offset(insn.off as isize) as *const u32;
237                     check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 4, insn_ptr)?;
238                     // log::warn!(
239                     //     "executing LD_W_REG, the ptr is REG:{} -> [{:#x}] + {:#x}",
240                     //     _src,
241                     //     reg[_src],
242                     //     insn.off
243                     // );
244                     x.read_unaligned() as u64
245                 }
246             }
247             ebpf::LD_DW_REG => {
248                 reg[_dst] = unsafe {
249                     #[allow(clippy::cast_ptr_alignment)]
250                     let x = (reg[_src] as *const u8).offset(insn.off as isize) as *const u64;
251                     check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
252                     x.read_unaligned()
253                 }
254             }
255 
256             // BPF_ST class
257             ebpf::ST_B_IMM => unsafe {
258                 let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u8;
259                 check_mem_store(stacks.last().unwrap().as_slice(), x as u64, 1, insn_ptr)?;
260                 x.write_unaligned(insn.imm as u8);
261             },
262             ebpf::ST_H_IMM => unsafe {
263                 #[allow(clippy::cast_ptr_alignment)]
264                 let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u16;
265                 check_mem_store(stacks.last().unwrap().as_slice(), x as u64, 2, insn_ptr)?;
266                 x.write_unaligned(insn.imm as u16);
267             },
268             ebpf::ST_W_IMM => unsafe {
269                 #[allow(clippy::cast_ptr_alignment)]
270                 let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u32;
271                 check_mem_store(stacks.last().unwrap().as_slice(), x as u64, 4, insn_ptr)?;
272                 x.write_unaligned(insn.imm as u32);
273             },
274             ebpf::ST_DW_IMM => unsafe {
275                 #[allow(clippy::cast_ptr_alignment)]
276                 let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u64;
277                 check_mem_store(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
278                 x.write_unaligned(insn.imm as u64);
279             },
280 
281             // BPF_STX class
282             ebpf::ST_B_REG => unsafe {
283                 let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u8;
284                 check_mem_store(stacks.last().unwrap().as_slice(), x as u64, 1, insn_ptr)?;
285                 x.write_unaligned(reg[_src] as u8);
286             },
287             ebpf::ST_H_REG => unsafe {
288                 #[allow(clippy::cast_ptr_alignment)]
289                 let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u16;
290                 check_mem_store(stacks.last().unwrap().as_slice(), x as u64, 2, insn_ptr)?;
291                 x.write_unaligned(reg[_src] as u16);
292             },
293             ebpf::ST_W_REG => unsafe {
294                 #[allow(clippy::cast_ptr_alignment)]
295                 let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u32;
296                 check_mem_store(stacks.last().unwrap().as_slice(), x as u64, 4, insn_ptr)?;
297                 x.write_unaligned(reg[_src] as u32);
298             },
299             ebpf::ST_DW_REG => unsafe {
300                 #[allow(clippy::cast_ptr_alignment)]
301                 let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u64;
302                 check_mem_store(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
303                 x.write_unaligned(reg[_src]);
304             },
305             ebpf::ST_W_XADD => unimplemented!(),
306             ebpf::ST_DW_XADD => unimplemented!(),
307 
308             // BPF_ALU class
309             // TODO Check how overflow works in kernel. Should we &= U32MAX all src register value
310             // before we do the operation?
311             // Cf ((0x11 << 32) - (0x1 << 32)) as u32 VS ((0x11 << 32) as u32 - (0x1 << 32) as u32
312             ebpf::ADD32_IMM => reg[_dst] = (reg[_dst] as i32).wrapping_add(insn.imm) as u64, //((reg[_dst] & U32MAX) + insn.imm  as u64)     & U32MAX,
313             ebpf::ADD32_REG => reg[_dst] = (reg[_dst] as i32).wrapping_add(reg[_src] as i32) as u64, //((reg[_dst] & U32MAX) + (reg[_src] & U32MAX)) & U32MAX,
314             ebpf::SUB32_IMM => reg[_dst] = (reg[_dst] as i32).wrapping_sub(insn.imm) as u64,
315             ebpf::SUB32_REG => reg[_dst] = (reg[_dst] as i32).wrapping_sub(reg[_src] as i32) as u64,
316             ebpf::MUL32_IMM => reg[_dst] = (reg[_dst] as i32).wrapping_mul(insn.imm) as u64,
317             ebpf::MUL32_REG => reg[_dst] = (reg[_dst] as i32).wrapping_mul(reg[_src] as i32) as u64,
318             ebpf::DIV32_IMM if insn.imm as u32 == 0 => reg[_dst] = 0,
319             ebpf::DIV32_IMM => reg[_dst] = (reg[_dst] as u32 / insn.imm as u32) as u64,
320             ebpf::DIV32_REG if reg[_src] as u32 == 0 => reg[_dst] = 0,
321             ebpf::DIV32_REG => reg[_dst] = (reg[_dst] as u32 / reg[_src] as u32) as u64,
322             ebpf::OR32_IMM => reg[_dst] = (reg[_dst] as u32 | insn.imm as u32) as u64,
323             ebpf::OR32_REG => reg[_dst] = (reg[_dst] as u32 | reg[_src] as u32) as u64,
324             ebpf::AND32_IMM => reg[_dst] = (reg[_dst] as u32 & insn.imm as u32) as u64,
325             ebpf::AND32_REG => reg[_dst] = (reg[_dst] as u32 & reg[_src] as u32) as u64,
326             // As for the 64-bit version, we should mask the number of bits to shift with
327             // 0x1f, but .wrappping_shr() already takes care of it for us.
328             ebpf::LSH32_IMM => reg[_dst] = (reg[_dst] as u32).wrapping_shl(insn.imm as u32) as u64,
329             ebpf::LSH32_REG => reg[_dst] = (reg[_dst] as u32).wrapping_shl(reg[_src] as u32) as u64,
330             ebpf::RSH32_IMM => reg[_dst] = (reg[_dst] as u32).wrapping_shr(insn.imm as u32) as u64,
331             ebpf::RSH32_REG => reg[_dst] = (reg[_dst] as u32).wrapping_shr(reg[_src] as u32) as u64,
332             ebpf::NEG32 => {
333                 reg[_dst] = (reg[_dst] as i32).wrapping_neg() as u64;
334                 reg[_dst] &= U32MAX;
335             }
336             ebpf::MOD32_IMM if insn.imm as u32 == 0 => (),
337             ebpf::MOD32_IMM => reg[_dst] = (reg[_dst] as u32 % insn.imm as u32) as u64,
338             ebpf::MOD32_REG if reg[_src] as u32 == 0 => (),
339             ebpf::MOD32_REG => reg[_dst] = (reg[_dst] as u32 % reg[_src] as u32) as u64,
340             ebpf::XOR32_IMM => reg[_dst] = (reg[_dst] as u32 ^ insn.imm as u32) as u64,
341             ebpf::XOR32_REG => reg[_dst] = (reg[_dst] as u32 ^ reg[_src] as u32) as u64,
342             ebpf::MOV32_IMM => reg[_dst] = insn.imm as u32 as u64,
343             ebpf::MOV32_REG => reg[_dst] = (reg[_src] as u32) as u64,
344             // As for the 64-bit version, we should mask the number of bits to shift with
345             // 0x1f, but .wrappping_shr() already takes care of it for us.
346             ebpf::ARSH32_IMM => {
347                 reg[_dst] = (reg[_dst] as i32).wrapping_shr(insn.imm as u32) as u64;
348                 reg[_dst] &= U32MAX;
349             }
350             ebpf::ARSH32_REG => {
351                 reg[_dst] = (reg[_dst] as i32).wrapping_shr(reg[_src] as u32) as u64;
352                 reg[_dst] &= U32MAX;
353             }
354             ebpf::LE => {
355                 reg[_dst] = match insn.imm {
356                     16 => (reg[_dst] as u16).to_le() as u64,
357                     32 => (reg[_dst] as u32).to_le() as u64,
358                     64 => reg[_dst].to_le(),
359                     _ => unreachable!(),
360                 };
361             }
362             ebpf::BE => {
363                 reg[_dst] = match insn.imm {
364                     16 => (reg[_dst] as u16).to_be() as u64,
365                     32 => (reg[_dst] as u32).to_be() as u64,
366                     64 => reg[_dst].to_be(),
367                     _ => unreachable!(),
368                 };
369             }
370 
371             // BPF_ALU64 class
372             ebpf::ADD64_IMM => reg[_dst] = reg[_dst].wrapping_add(insn.imm as u64),
373             ebpf::ADD64_REG => reg[_dst] = reg[_dst].wrapping_add(reg[_src]),
374             ebpf::SUB64_IMM => reg[_dst] = reg[_dst].wrapping_sub(insn.imm as u64),
375             ebpf::SUB64_REG => reg[_dst] = reg[_dst].wrapping_sub(reg[_src]),
376             ebpf::MUL64_IMM => reg[_dst] = reg[_dst].wrapping_mul(insn.imm as u64),
377             ebpf::MUL64_REG => reg[_dst] = reg[_dst].wrapping_mul(reg[_src]),
378             ebpf::DIV64_IMM if insn.imm == 0 => reg[_dst] = 0,
379             ebpf::DIV64_IMM => reg[_dst] /= insn.imm as u64,
380             ebpf::DIV64_REG if reg[_src] == 0 => reg[_dst] = 0,
381             ebpf::DIV64_REG => reg[_dst] /= reg[_src],
382             ebpf::OR64_IMM => reg[_dst] |= insn.imm as u64,
383             ebpf::OR64_REG => reg[_dst] |= reg[_src],
384             ebpf::AND64_IMM => reg[_dst] &= insn.imm as u64,
385             ebpf::AND64_REG => reg[_dst] &= reg[_src],
386             ebpf::LSH64_IMM => reg[_dst] <<= insn.imm as u64 & SHIFT_MASK_64,
387             ebpf::LSH64_REG => reg[_dst] <<= reg[_src] & SHIFT_MASK_64,
388             ebpf::RSH64_IMM => reg[_dst] >>= insn.imm as u64 & SHIFT_MASK_64,
389             ebpf::RSH64_REG => reg[_dst] >>= reg[_src] & SHIFT_MASK_64,
390             ebpf::NEG64 => reg[_dst] = -(reg[_dst] as i64) as u64,
391             ebpf::MOD64_IMM if insn.imm == 0 => (),
392             ebpf::MOD64_IMM => reg[_dst] %= insn.imm as u64,
393             ebpf::MOD64_REG if reg[_src] == 0 => (),
394             ebpf::MOD64_REG => reg[_dst] %= reg[_src],
395             ebpf::XOR64_IMM => reg[_dst] ^= insn.imm as u64,
396             ebpf::XOR64_REG => reg[_dst] ^= reg[_src],
397             ebpf::MOV64_IMM => reg[_dst] = insn.imm as u64,
398             ebpf::MOV64_REG => reg[_dst] = reg[_src],
399             ebpf::ARSH64_IMM => {
400                 reg[_dst] = (reg[_dst] as i64 >> (insn.imm as u64 & SHIFT_MASK_64)) as u64
401             }
402             ebpf::ARSH64_REG => {
403                 reg[_dst] = (reg[_dst] as i64 >> (reg[_src] as u64 & SHIFT_MASK_64)) as u64
404             }
405 
406             // BPF_JMP class
407             // TODO: check this actually works as expected for signed / unsigned ops
408             ebpf::JA => do_jump(&mut insn_ptr, &insn),
409             ebpf::JEQ_IMM => {
410                 if reg[_dst] == insn.imm as u64 {
411                     do_jump(&mut insn_ptr, &insn);
412                 }
413             }
414             ebpf::JEQ_REG => {
415                 if reg[_dst] == reg[_src] {
416                     do_jump(&mut insn_ptr, &insn);
417                 }
418             }
419             ebpf::JGT_IMM => {
420                 if reg[_dst] > insn.imm as u64 {
421                     do_jump(&mut insn_ptr, &insn);
422                 }
423             }
424             ebpf::JGT_REG => {
425                 if reg[_dst] > reg[_src] {
426                     do_jump(&mut insn_ptr, &insn);
427                 }
428             }
429             ebpf::JGE_IMM => {
430                 if reg[_dst] >= insn.imm as u64 {
431                     do_jump(&mut insn_ptr, &insn);
432                 }
433             }
434             ebpf::JGE_REG => {
435                 if reg[_dst] >= reg[_src] {
436                     do_jump(&mut insn_ptr, &insn);
437                 }
438             }
439             ebpf::JLT_IMM => {
440                 if reg[_dst] < insn.imm as u64 {
441                     do_jump(&mut insn_ptr, &insn);
442                 }
443             }
444             ebpf::JLT_REG => {
445                 if reg[_dst] < reg[_src] {
446                     do_jump(&mut insn_ptr, &insn);
447                 }
448             }
449             ebpf::JLE_IMM => {
450                 if reg[_dst] <= insn.imm as u64 {
451                     do_jump(&mut insn_ptr, &insn);
452                 }
453             }
454             ebpf::JLE_REG => {
455                 if reg[_dst] <= reg[_src] {
456                     do_jump(&mut insn_ptr, &insn);
457                 }
458             }
459             ebpf::JSET_IMM => {
460                 if reg[_dst] & insn.imm as u64 != 0 {
461                     do_jump(&mut insn_ptr, &insn);
462                 }
463             }
464             ebpf::JSET_REG => {
465                 if reg[_dst] & reg[_src] != 0 {
466                     do_jump(&mut insn_ptr, &insn);
467                 }
468             }
469             ebpf::JNE_IMM => {
470                 if reg[_dst] != insn.imm as u64 {
471                     do_jump(&mut insn_ptr, &insn);
472                 }
473             }
474             ebpf::JNE_REG => {
475                 if reg[_dst] != reg[_src] {
476                     do_jump(&mut insn_ptr, &insn);
477                 }
478             }
479             ebpf::JSGT_IMM => {
480                 if reg[_dst] as i64 > insn.imm as i64 {
481                     do_jump(&mut insn_ptr, &insn);
482                 }
483             }
484             ebpf::JSGT_REG => {
485                 if reg[_dst] as i64 > reg[_src] as i64 {
486                     do_jump(&mut insn_ptr, &insn);
487                 }
488             }
489             ebpf::JSGE_IMM => {
490                 if reg[_dst] as i64 >= insn.imm as i64 {
491                     do_jump(&mut insn_ptr, &insn);
492                 }
493             }
494             ebpf::JSGE_REG => {
495                 if reg[_dst] as i64 >= reg[_src] as i64 {
496                     do_jump(&mut insn_ptr, &insn);
497                 }
498             }
499             ebpf::JSLT_IMM => {
500                 if (reg[_dst] as i64) < insn.imm as i64 {
501                     do_jump(&mut insn_ptr, &insn);
502                 }
503             }
504             ebpf::JSLT_REG => {
505                 if (reg[_dst] as i64) < reg[_src] as i64 {
506                     do_jump(&mut insn_ptr, &insn);
507                 }
508             }
509             ebpf::JSLE_IMM => {
510                 if reg[_dst] as i64 <= insn.imm as i64 {
511                     do_jump(&mut insn_ptr, &insn);
512                 }
513             }
514             ebpf::JSLE_REG => {
515                 if reg[_dst] as i64 <= reg[_src] as i64 {
516                     do_jump(&mut insn_ptr, &insn);
517                 }
518             }
519 
520             // BPF_JMP32 class
521             ebpf::JEQ_IMM32 => {
522                 if reg[_dst] as u32 == insn.imm as u32 {
523                     do_jump(&mut insn_ptr, &insn);
524                 }
525             }
526             ebpf::JEQ_REG32 => {
527                 if reg[_dst] as u32 == reg[_src] as u32 {
528                     do_jump(&mut insn_ptr, &insn);
529                 }
530             }
531             ebpf::JGT_IMM32 => {
532                 if reg[_dst] as u32 > insn.imm as u32 {
533                     do_jump(&mut insn_ptr, &insn);
534                 }
535             }
536             ebpf::JGT_REG32 => {
537                 if reg[_dst] as u32 > reg[_src] as u32 {
538                     do_jump(&mut insn_ptr, &insn);
539                 }
540             }
541             ebpf::JGE_IMM32 => {
542                 if reg[_dst] as u32 >= insn.imm as u32 {
543                     do_jump(&mut insn_ptr, &insn);
544                 }
545             }
546             ebpf::JGE_REG32 => {
547                 if reg[_dst] as u32 >= reg[_src] as u32 {
548                     do_jump(&mut insn_ptr, &insn);
549                 }
550             }
551             ebpf::JLT_IMM32 => {
552                 if (reg[_dst] as u32) < insn.imm as u32 {
553                     do_jump(&mut insn_ptr, &insn);
554                 }
555             }
556             ebpf::JLT_REG32 => {
557                 if (reg[_dst] as u32) < reg[_src] as u32 {
558                     do_jump(&mut insn_ptr, &insn);
559                 }
560             }
561             ebpf::JLE_IMM32 => {
562                 if reg[_dst] as u32 <= insn.imm as u32 {
563                     do_jump(&mut insn_ptr, &insn);
564                 }
565             }
566             ebpf::JLE_REG32 => {
567                 if reg[_dst] as u32 <= reg[_src] as u32 {
568                     do_jump(&mut insn_ptr, &insn);
569                 }
570             }
571             ebpf::JSET_IMM32 => {
572                 if reg[_dst] as u32 & insn.imm as u32 != 0 {
573                     do_jump(&mut insn_ptr, &insn);
574                 }
575             }
576             ebpf::JSET_REG32 => {
577                 if reg[_dst] as u32 & reg[_src] as u32 != 0 {
578                     do_jump(&mut insn_ptr, &insn);
579                 }
580             }
581             ebpf::JNE_IMM32 => {
582                 if reg[_dst] as u32 != insn.imm as u32 {
583                     do_jump(&mut insn_ptr, &insn);
584                 }
585             }
586             ebpf::JNE_REG32 => {
587                 if reg[_dst] as u32 != reg[_src] as u32 {
588                     do_jump(&mut insn_ptr, &insn);
589                 }
590             }
591             ebpf::JSGT_IMM32 => {
592                 if reg[_dst] as i32 > insn.imm {
593                     do_jump(&mut insn_ptr, &insn);
594                 }
595             }
596             ebpf::JSGT_REG32 => {
597                 if reg[_dst] as i32 > reg[_src] as i32 {
598                     do_jump(&mut insn_ptr, &insn);
599                 }
600             }
601             ebpf::JSGE_IMM32 => {
602                 if reg[_dst] as i32 >= insn.imm {
603                     do_jump(&mut insn_ptr, &insn);
604                 }
605             }
606             ebpf::JSGE_REG32 => {
607                 if reg[_dst] as i32 >= reg[_src] as i32 {
608                     do_jump(&mut insn_ptr, &insn);
609                 }
610             }
611             ebpf::JSLT_IMM32 => {
612                 if (reg[_dst] as i32) < insn.imm {
613                     do_jump(&mut insn_ptr, &insn);
614                 }
615             }
616             ebpf::JSLT_REG32 => {
617                 if (reg[_dst] as i32) < reg[_src] as i32 {
618                     do_jump(&mut insn_ptr, &insn);
619                 }
620             }
621             ebpf::JSLE_IMM32 => {
622                 if reg[_dst] as i32 <= insn.imm {
623                     do_jump(&mut insn_ptr, &insn);
624                 }
625             }
626             ebpf::JSLE_REG32 => {
627                 if reg[_dst] as i32 <= reg[_src] as i32 {
628                     do_jump(&mut insn_ptr, &insn);
629                 }
630             }
631 
632             // Do not delegate the check to the verifier, since registered functions can be
633             // changed after the program has been verified.
634             ebpf::CALL => {
635                 // See https://www.kernel.org/doc/html/latest/bpf/standardization/instruction-set.html#id16
636                 let src_reg = _src;
637                 let call_func_res = match src_reg {
638                     0 => {
639                         // Handle call by address to external function.
640                         if let Some(function) = helpers.get(&(insn.imm as u32)) {
641                             reg[0] = function(reg[1], reg[2], reg[3], reg[4], reg[5]);
642                             Ok(())
643                         }else {
644                             Err(format!(
645                                 "Error: unknown helper function (id: {:#x}) [{}], (instruction #{})",
646                                 insn.imm as u32,BPF_FUNC_MAPPER[insn.imm as usize],insn_ptr
647                             ))
648                         }
649                     }
650                     1 => {
651                         // bpf to bpf call
652                         // The function is in the same program, so we can just jump to the address
653                         if stacks.len() >= ebpf::RBPF_MAX_CALL_DEPTH{
654                             Err(format!(
655                                 "Error: bpf to bpf call stack limit reached (instruction #{}) max depth: {}",
656                                 insn_ptr, ebpf::RBPF_MAX_CALL_DEPTH
657                             ))
658                         }else {
659                             let mut pre_stack = stacks.last_mut().unwrap();
660                             // Save the callee saved registers
661                             pre_stack.save_registers(&reg[6..=9]);
662                             // Save the return address
663                             pre_stack.save_return_address(insn_ptr as u16);
664                             // save the stack pointer
665                             pre_stack.save_sp(reg[10] as u16);
666                             let mut stack = StackFrame::new();
667                             log::trace!("BPF TO BPF CALL: new pc: {} + {} = {}",insn_ptr ,insn.imm,insn_ptr + insn.imm as usize);
668                             reg[10] = stack.as_ptr() as u64 + stack.len() as u64;
669                             stacks.push(stack);
670                             insn_ptr += insn.imm as usize;
671                             Ok(())
672                         }
673                     }
674                     _ =>{
675                         Err(format!(
676                             "Error: the function call type (id: {:#x}) [{}], (instruction #{}) not supported",
677                             insn.imm as u32,BPF_FUNC_MAPPER[insn.imm as usize],insn_ptr
678                         ))
679                     }
680                 };
681                 if let Err(e) = call_func_res {
682                     Err(Error::new(ErrorKind::Other, e))?;
683                 }
684             }
685             ebpf::TAIL_CALL => unimplemented!(),
686             ebpf::EXIT => {
687                 if stacks.len() == 1 {
688                     return Ok(reg[0]);
689                 } else {
690                     // Pop the stack
691                     stacks.pop();
692                     let stack = stacks.last().unwrap();
693                     // Restore the callee saved registers
694                     reg[6..=9].copy_from_slice(&stack.get_registers());
695                     // Restore the return address
696                     insn_ptr = stack.get_return_address() as usize;
697                     // Restore the stack pointer
698                     reg[10] = stack.get_sp() as u64;
699                     log::trace!("EXIT: new pc: {}", insn_ptr);
700                 }
701             }
702 
703             _ => unreachable!(),
704         }
705     }
706 
707     unreachable!()
708 }
709