xref: /DragonOS/kernel/crates/rbpf/src/lib.rs (revision 55e6f0b65f91b32638fd56581f711a816eccdcd1)
1 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
2 // Derived from uBPF <https://github.com/iovisor/ubpf>
3 // Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
4 // Copyright 2023 Isovalent, Inc. <quentin@isovalent.com>
5 
6 //! Virtual machine and JIT compiler for eBPF programs.
7 #![doc(
8     html_logo_url = "https://raw.githubusercontent.com/qmonnet/rbpf/main/misc/rbpf.png",
9     html_favicon_url = "https://raw.githubusercontent.com/qmonnet/rbpf/main/misc/rbpf.ico"
10 )]
11 #![warn(missing_docs)]
12 // There are unused mut warnings due to unsafe code.
13 #![allow(unused_mut)]
14 // Allows old-style clippy
15 #![allow(renamed_and_removed_lints)]
16 #![cfg_attr(
17     clippy,
18     allow(
19         redundant_field_names,
20         single_match,
21         cast_lossless,
22         doc_markdown,
23         match_same_arms,
24         unreadable_literal
25     )
26 )]
27 // Configures the crate to be `no_std` when `std` feature is disabled.
28 #![cfg_attr(not(feature = "std"), no_std)]
29 extern crate alloc;
30 use alloc::{collections::BTreeMap, format, vec, vec::Vec};
31 
32 use byteorder::{ByteOrder, LittleEndian};
33 
34 type HashMap<K, V> = BTreeMap<K, V>;
35 #[cfg(feature = "cranelift")]
36 type HashSet<T> = alloc::collections::BTreeSet<T>;
37 mod asm_parser;
38 pub mod assembler;
39 #[cfg(feature = "cranelift")]
40 mod cranelift;
41 pub mod disassembler;
42 pub mod ebpf;
43 pub mod helpers;
44 pub mod insn_builder;
45 mod interpreter;
46 #[cfg(all(not(windows), feature = "std"))]
47 mod jit;
48 #[cfg(not(feature = "std"))]
49 mod no_std_error;
50 mod stack;
51 mod verifier;
52 
53 #[cfg(feature = "std")]
54 pub use std::io::{Error, ErrorKind};
55 
56 /// In no_std we use a custom implementation of the error which acts as a
57 /// replacement for the io Error.
58 #[cfg(not(feature = "std"))]
59 pub use crate::no_std_error::{Error, ErrorKind};
60 
61 /// eBPF verification function that returns an error if the program does not meet its requirements.
62 ///
63 /// Some examples of things the verifier may reject the program for:
64 ///
65 ///   - Program does not terminate.
66 ///   - Unknown instructions.
67 ///   - Bad formed instruction.
68 ///   - Unknown eBPF helper index.
69 pub type Verifier = fn(prog: &[u8]) -> Result<(), Error>;
70 
71 /// eBPF helper function.
72 pub type Helper = fn(u64, u64, u64, u64, u64) -> u64;
73 
74 // A metadata buffer with two offset indications. It can be used in one kind of eBPF VM to simulate
75 // the use of a metadata buffer each time the program is executed, without the user having to
76 // actually handle it. The offsets are used to tell the VM where in the buffer the pointers to
77 // packet data start and end should be stored each time the program is run on a new packet.
78 struct MetaBuff {
79     data_offset: usize,
80     data_end_offset: usize,
81     buffer: Vec<u8>,
82 }
83 
84 /// A virtual machine to run eBPF program. This kind of VM is used for programs expecting to work
85 /// on a metadata buffer containing pointers to packet data.
86 ///
87 /// # Examples
88 ///
89 /// ```
90 /// let prog = &[
91 ///     0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff at offset 8 into R1.
92 ///     0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
93 ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
94 /// ];
95 /// let mem = &mut [
96 ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
97 /// ];
98 ///
99 /// // Just for the example we create our metadata buffer from scratch, and we store the pointers
100 /// // to packet data start and end in it.
101 /// let mut mbuff = [0u8; 32];
102 /// unsafe {
103 ///     let mut data     = mbuff.as_ptr().offset(8)  as *mut u64;
104 ///     let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
105 ///     *data     = mem.as_ptr() as u64;
106 ///     *data_end = mem.as_ptr() as u64 + mem.len() as u64;
107 /// }
108 ///
109 /// // Instantiate a VM.
110 /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
111 ///
112 /// // Provide both a reference to the packet data, and to the metadata buffer.
113 /// let res = vm.execute_program(mem, &mut mbuff).unwrap();
114 /// assert_eq!(res, 0x2211);
115 /// ```
116 pub struct EbpfVmMbuff<'a> {
117     prog: Option<&'a [u8]>,
118     verifier: Verifier,
119     #[cfg(all(not(windows), feature = "std"))]
120     jit: Option<jit::JitMemory<'a>>,
121     #[cfg(feature = "cranelift")]
122     cranelift_prog: Option<cranelift::CraneliftProgram>,
123     helpers: HashMap<u32, ebpf::Helper>,
124 }
125 
126 impl<'a> EbpfVmMbuff<'a> {
127     /// Create a new virtual machine instance, and load an eBPF program into that instance.
128     /// When attempting to load the program, it passes through a simple verifier.
129     ///
130     /// # Examples
131     ///
132     /// ```
133     /// let prog = &[
134     ///     0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into R1.
135     ///     0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
136     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
137     /// ];
138     ///
139     /// // Instantiate a VM.
140     /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
141     /// ```
142     pub fn new(prog: Option<&'a [u8]>) -> Result<EbpfVmMbuff<'a>, Error> {
143         if let Some(prog) = prog {
144             verifier::check(prog)?;
145         }
146 
147         Ok(EbpfVmMbuff {
148             prog,
149             verifier: verifier::check,
150             #[cfg(all(not(windows), feature = "std"))]
151             jit: None,
152             #[cfg(feature = "cranelift")]
153             cranelift_prog: None,
154             helpers: HashMap::new(),
155         })
156     }
157 
158     /// Load a new eBPF program into the virtual machine instance.
159     ///
160     /// # Examples
161     ///
162     /// ```
163     /// let prog1 = &[
164     ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
165     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
166     /// ];
167     /// let prog2 = &[
168     ///     0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into R1.
169     ///     0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
170     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
171     /// ];
172     ///
173     /// // Instantiate a VM.
174     /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog1)).unwrap();
175     /// vm.set_program(prog2).unwrap();
176     /// ```
177     pub fn set_program(&mut self, prog: &'a [u8]) -> Result<(), Error> {
178         (self.verifier)(prog)?;
179         self.prog = Some(prog);
180         Ok(())
181     }
182 
183     /// Set a new verifier function. The function should return an `Error` if the program should be
184     /// rejected by the virtual machine. If a program has been loaded to the VM already, the
185     /// verifier is immediately run.
186     ///
187     /// # Examples
188     ///
189     /// ```
190     /// use rbpf::{Error, ErrorKind};
191     /// use rbpf::ebpf;
192     ///
193     /// // Define a simple verifier function.
194     /// fn verifier(prog: &[u8]) -> Result<(), Error> {
195     ///     let last_insn = ebpf::get_insn(prog, (prog.len() / ebpf::INSN_SIZE) - 1);
196     ///     if last_insn.opc != ebpf::EXIT {
197     ///         return Err(Error::new(ErrorKind::Other,
198     ///                    "[Verifier] Error: program does not end with “EXIT” instruction"));
199     ///     }
200     ///     Ok(())
201     /// }
202     ///
203     /// let prog1 = &[
204     ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
205     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
206     /// ];
207     ///
208     /// // Instantiate a VM.
209     /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog1)).unwrap();
210     /// // Change the verifier.
211     /// vm.set_verifier(verifier).unwrap();
212     /// ```
213     pub fn set_verifier(&mut self, verifier: Verifier) -> Result<(), Error> {
214         if let Some(prog) = self.prog {
215             verifier(prog)?;
216         }
217         self.verifier = verifier;
218         Ok(())
219     }
220 
221     /// Register a built-in or user-defined helper function in order to use it later from within
222     /// the eBPF program. The helper is registered into a hashmap, so the `key` can be any `u32`.
223     ///
224     /// If using JIT-compiled eBPF programs, be sure to register all helpers before compiling the
225     /// program. You should be able to change registered helpers after compiling, but not to add
226     /// new ones (i.e. with new keys).
227     ///
228     /// # Examples
229     ///
230     /// ```
231     /// use rbpf::helpers;
232     ///
233     /// // This program was compiled with clang, from a C program containing the following single
234     /// // instruction: `return bpf_trace_printk("foo %c %c %c\n", 10, 1, 2, 3);`
235     /// let prog = &[
236     ///     0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load 0 as u64 into r1 (That would be
237     ///     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // replaced by tc by the address of
238     ///                                                     // the format string, in the .map
239     ///                                                     // section of the ELF file).
240     ///     0xb7, 0x02, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, // mov r2, 10
241     ///     0xb7, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // mov r3, 1
242     ///     0xb7, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // mov r4, 2
243     ///     0xb7, 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // mov r5, 3
244     ///     0x85, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, // call helper with key 6
245     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
246     /// ];
247     ///
248     /// // Instantiate a VM.
249     /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
250     ///
251     /// // Register a helper.
252     /// // On running the program this helper will print the content of registers r3, r4 and r5 to
253     /// // standard output.
254     /// # #[cfg(feature = "std")]
255     /// vm.register_helper(6, helpers::bpf_trace_printf).unwrap();
256     /// ```
257     pub fn register_helper(&mut self, key: u32, function: Helper) -> Result<(), Error> {
258         self.helpers.insert(key, function);
259         Ok(())
260     }
261 
262     /// Execute the program loaded, with the given packet data and metadata buffer.
263     ///
264     /// If the program is made to be compatible with Linux kernel, it is expected to load the
265     /// address of the beginning and of the end of the memory area used for packet data from the
266     /// metadata buffer, at some appointed offsets. It is up to the user to ensure that these
267     /// pointers are correctly stored in the buffer.
268     ///
269     /// # Examples
270     ///
271     /// ```
272     /// let prog = &[
273     ///     0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into R1.
274     ///     0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
275     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
276     /// ];
277     /// let mem = &mut [
278     ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
279     /// ];
280     ///
281     /// // Just for the example we create our metadata buffer from scratch, and we store the
282     /// // pointers to packet data start and end in it.
283     /// let mut mbuff = [0u8; 32];
284     /// unsafe {
285     ///     let mut data     = mbuff.as_ptr().offset(8)  as *mut u64;
286     ///     let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
287     ///     *data     = mem.as_ptr() as u64;
288     ///     *data_end = mem.as_ptr() as u64 + mem.len() as u64;
289     /// }
290     ///
291     /// // Instantiate a VM.
292     /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
293     ///
294     /// // Provide both a reference to the packet data, and to the metadata buffer.
295     /// let res = vm.execute_program(mem, &mut mbuff).unwrap();
296     /// assert_eq!(res, 0x2211);
297     /// ```
298     pub fn execute_program(&self, mem: &[u8], mbuff: &[u8]) -> Result<u64, Error> {
299         interpreter::execute_program(self.prog, mem, mbuff, &self.helpers)
300     }
301 
302     /// JIT-compile the loaded program. No argument required for this.
303     ///
304     /// If using helper functions, be sure to register them into the VM before calling this
305     /// function.
306     ///
307     /// # Examples
308     ///
309     /// ```
310     /// let prog = &[
311     ///     0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into R1.
312     ///     0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
313     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
314     /// ];
315     ///
316     /// // Instantiate a VM.
317     /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
318     ///
319     /// vm.jit_compile();
320     /// ```
321     #[cfg(all(not(windows), feature = "std"))]
322     pub fn jit_compile(&mut self) -> Result<(), Error> {
323         let prog = match self.prog {
324             Some(prog) => prog,
325             None => Err(Error::new(
326                 ErrorKind::Other,
327                 "Error: No program set, call prog_set() to load one",
328             ))?,
329         };
330         self.jit = Some(jit::JitMemory::new(prog, &self.helpers, true, false)?);
331         Ok(())
332     }
333 
334     /// Execute the previously JIT-compiled program, with the given packet data and metadata
335     /// buffer, in a manner very similar to `execute_program()`.
336     ///
337     /// If the program is made to be compatible with Linux kernel, it is expected to load the
338     /// address of the beginning and of the end of the memory area used for packet data from the
339     /// metadata buffer, at some appointed offsets. It is up to the user to ensure that these
340     /// pointers are correctly stored in the buffer.
341     ///
342     /// # Safety
343     ///
344     /// **WARNING:** JIT-compiled assembly code is not safe, in particular there is no runtime
345     /// check for memory access; so if the eBPF program attempts erroneous accesses, this may end
346     /// very bad (program may segfault). It may be wise to check that the program works with the
347     /// interpreter before running the JIT-compiled version of it.
348     ///
349     /// For this reason the function should be called from within an `unsafe` bloc.
350     ///
351     /// # Examples
352     ///
353     /// ```
354     /// let prog = &[
355     ///     0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into r1.
356     ///     0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
357     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
358     /// ];
359     /// let mem = &mut [
360     ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
361     /// ];
362     ///
363     /// // Just for the example we create our metadata buffer from scratch, and we store the
364     /// // pointers to packet data start and end in it.
365     /// let mut mbuff = [0u8; 32];
366     /// unsafe {
367     ///     let mut data     = mbuff.as_ptr().offset(8)  as *mut u64;
368     ///     let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
369     ///     *data     = mem.as_ptr() as u64;
370     ///     *data_end = mem.as_ptr() as u64 + mem.len() as u64;
371     /// }
372     ///
373     /// // Instantiate a VM.
374     /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
375     ///
376     /// # #[cfg(all(not(windows), feature = "std"))]
377     /// vm.jit_compile();
378     ///
379     /// // Provide both a reference to the packet data, and to the metadata buffer.
380     /// # #[cfg(all(not(windows), feature = "std"))]
381     /// unsafe {
382     ///     let res = vm.execute_program_jit(mem, &mut mbuff).unwrap();
383     ///     assert_eq!(res, 0x2211);
384     /// }
385     /// ```
386     #[cfg(all(not(windows), feature = "std"))]
387     pub unsafe fn execute_program_jit(
388         &self,
389         mem: &mut [u8],
390         mbuff: &'a mut [u8],
391     ) -> Result<u64, Error> {
392         // If packet data is empty, do not send the address of an empty slice; send a null pointer
393         //  as first argument instead, as this is uBPF's behavior (empty packet should not happen
394         //  in the kernel; anyway the verifier would prevent the use of uninitialized registers).
395         //  See `mul_loop` test.
396         let mem_ptr = match mem.len() {
397             0 => std::ptr::null_mut(),
398             _ => mem.as_ptr() as *mut u8,
399         };
400         // The last two arguments are not used in this function. They would be used if there was a
401         // need to indicate to the JIT at which offset in the mbuff mem_ptr and mem_ptr + mem.len()
402         // should be stored; this is what happens with struct EbpfVmFixedMbuff.
403         match &self.jit {
404             Some(jit) => Ok(jit.get_prog()(
405                 mbuff.as_ptr() as *mut u8,
406                 mbuff.len(),
407                 mem_ptr,
408                 mem.len(),
409                 0,
410                 0,
411             )),
412             None => Err(Error::new(
413                 ErrorKind::Other,
414                 "Error: program has not been JIT-compiled",
415             )),
416         }
417     }
418 
419     /// Compile the loaded program using the Cranelift JIT.
420     ///
421     /// If using helper functions, be sure to register them into the VM before calling this
422     /// function.
423     ///
424     /// # Examples
425     ///
426     /// ```
427     /// let prog = &[
428     ///     0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into R1.
429     ///     0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
430     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
431     /// ];
432     ///
433     /// // Instantiate a VM.
434     /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
435     ///
436     /// vm.cranelift_compile();
437     /// ```
438     #[cfg(feature = "cranelift")]
439     pub fn cranelift_compile(&mut self) -> Result<(), Error> {
440         use crate::cranelift::CraneliftCompiler;
441 
442         let prog = match self.prog {
443             Some(prog) => prog,
444             None => Err(Error::new(
445                 ErrorKind::Other,
446                 "Error: No program set, call prog_set() to load one",
447             ))?,
448         };
449 
450         let mut compiler = CraneliftCompiler::new(self.helpers.clone());
451         let program = compiler.compile_function(prog)?;
452 
453         self.cranelift_prog = Some(program);
454         Ok(())
455     }
456 
457     /// Execute the previously compiled program, with the given packet data and metadata
458     /// buffer, in a manner very similar to `execute_program()`.
459     ///
460     /// If the program is made to be compatible with Linux kernel, it is expected to load the
461     /// address of the beginning and of the end of the memory area used for packet data from the
462     /// metadata buffer, at some appointed offsets. It is up to the user to ensure that these
463     /// pointers are correctly stored in the buffer.
464     ///
465     ///
466     /// # Examples
467     ///
468     /// ```
469     /// let prog = &[
470     ///     0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into r1.
471     ///     0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
472     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
473     /// ];
474     /// let mem = &mut [
475     ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
476     /// ];
477     ///
478     /// // Just for the example we create our metadata buffer from scratch, and we store the
479     /// // pointers to packet data start and end in it.
480     /// let mut mbuff = [0u8; 32];
481     /// unsafe {
482     ///     let mut data     = mbuff.as_ptr().offset(8)  as *mut u64;
483     ///     let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
484     ///     *data     = mem.as_ptr() as u64;
485     ///     *data_end = mem.as_ptr() as u64 + mem.len() as u64;
486     /// }
487     ///
488     /// // Instantiate a VM.
489     /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
490     ///
491     /// vm.cranelift_compile();
492     ///
493     /// // Provide both a reference to the packet data, and to the metadata buffer.
494     /// let res = vm.execute_program_cranelift(mem, &mut mbuff).unwrap();
495     /// assert_eq!(res, 0x2211);
496     /// ```
497     #[cfg(feature = "cranelift")]
498     pub fn execute_program_cranelift(
499         &self,
500         mem: &mut [u8],
501         mbuff: &'a mut [u8],
502     ) -> Result<u64, Error> {
503         // If packet data is empty, do not send the address of an empty slice; send a null pointer
504         //  as first argument instead, as this is uBPF's behavior (empty packet should not happen
505         //  in the kernel; anyway the verifier would prevent the use of uninitialized registers).
506         //  See `mul_loop` test.
507         let mem_ptr = match mem.len() {
508             0 => core::ptr::null_mut(),
509             _ => mem.as_ptr() as *mut u8,
510         };
511 
512         // The last two arguments are not used in this function. They would be used if there was a
513         // need to indicate to the JIT at which offset in the mbuff mem_ptr and mem_ptr + mem.len()
514         // should be stored; this is what happens with struct EbpfVmFixedMbuff.
515         match &self.cranelift_prog {
516             Some(prog) => {
517                 Ok(prog.execute(mem_ptr, mem.len(), mbuff.as_ptr() as *mut u8, mbuff.len()))
518             }
519             None => Err(Error::new(
520                 ErrorKind::Other,
521                 "Error: program has not been compiled with cranelift",
522             )),
523         }
524     }
525 }
526 
527 /// A virtual machine to run eBPF program. This kind of VM is used for programs expecting to work
528 /// on a metadata buffer containing pointers to packet data, but it internally handles the buffer
529 /// so as to save the effort to manually handle the metadata buffer for the user.
530 ///
531 /// This struct implements a static internal buffer that is passed to the program. The user has to
532 /// indicate the offset values at which the eBPF program expects to find the start and the end of
533 /// packet data in the buffer. On calling the `execute_program()` or `execute_program_jit()` functions, the
534 /// struct automatically updates the addresses in this static buffer, at the appointed offsets, for
535 /// the start and the end of the packet data the program is called upon.
536 ///
537 /// # Examples
538 ///
539 /// This was compiled with clang from the following program, in C:
540 ///
541 /// ```c
542 /// #include <linux/bpf.h>
543 /// #include "path/to/linux/samples/bpf/bpf_helpers.h"
544 ///
545 /// SEC(".classifier")
546 /// int classifier(struct __sk_buff *skb)
547 /// {
548 ///   void *data = (void *)(long)skb->data;
549 ///   void *data_end = (void *)(long)skb->data_end;
550 ///
551 ///   // Check program is long enough.
552 ///   if (data + 5 > data_end)
553 ///     return 0;
554 ///
555 ///   return *((char *)data + 5);
556 /// }
557 /// ```
558 ///
559 /// Some small modifications have been brought to have it work, see comments.
560 ///
561 /// ```
562 /// let prog = &[
563 ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
564 ///     // Here opcode 0x61 had to be replace by 0x79 so as to load a 8-bytes long address.
565 ///     // Also, offset 0x4c had to be replace with e.g. 0x40 so as to prevent the two pointers
566 ///     // from overlapping in the buffer.
567 ///     0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load pointer to mem from r1[0x40] to r2
568 ///     0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
569 ///     // Here opcode 0x61 had to be replace by 0x79 so as to load a 8-bytes long address.
570 ///     0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load ptr to mem_end from r1[0x50] to r1
571 ///     0x2d, 0x12, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
572 ///     0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
573 ///     0x67, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, // r0 >>= 56
574 ///     0xc7, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, // r0 <<= 56 (arsh) extend byte sign to u64
575 ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
576 /// ];
577 /// let mem1 = &mut [
578 ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
579 /// ];
580 /// let mem2 = &mut [
581 ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x27
582 /// ];
583 ///
584 /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
585 /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
586 ///
587 /// // Provide only a reference to the packet data. We do not manage the metadata buffer.
588 /// let res = vm.execute_program(mem1).unwrap();
589 /// assert_eq!(res, 0xffffffffffffffdd);
590 ///
591 /// let res = vm.execute_program(mem2).unwrap();
592 /// assert_eq!(res, 0x27);
593 /// ```
594 pub struct EbpfVmFixedMbuff<'a> {
595     parent: EbpfVmMbuff<'a>,
596     mbuff: MetaBuff,
597 }
598 
599 impl<'a> EbpfVmFixedMbuff<'a> {
600     /// Create a new virtual machine instance, and load an eBPF program into that instance.
601     /// When attempting to load the program, it passes through a simple verifier.
602     ///
603     /// # Examples
604     ///
605     /// ```
606     /// let prog = &[
607     ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
608     ///     0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
609     ///     0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
610     ///     0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
611     ///     0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
612     ///     0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
613     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
614     /// ];
615     ///
616     /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
617     /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
618     /// ```
619     pub fn new(
620         prog: Option<&'a [u8]>,
621         data_offset: usize,
622         data_end_offset: usize,
623     ) -> Result<EbpfVmFixedMbuff<'a>, Error> {
624         let parent = EbpfVmMbuff::new(prog)?;
625         let get_buff_len = |x: usize, y: usize| if x >= y { x + 8 } else { y + 8 };
626         let buffer = vec![0u8; get_buff_len(data_offset, data_end_offset)];
627         let mbuff = MetaBuff {
628             data_offset,
629             data_end_offset,
630             buffer,
631         };
632         Ok(EbpfVmFixedMbuff { parent, mbuff })
633     }
634 
635     /// Load a new eBPF program into the virtual machine instance.
636     ///
637     /// At the same time, load new offsets for storing pointers to start and end of packet data in
638     /// the internal metadata buffer.
639     ///
640     /// # Examples
641     ///
642     /// ```
643     /// let prog1 = &[
644     ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
645     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
646     /// ];
647     /// let prog2 = &[
648     ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
649     ///     0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
650     ///     0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
651     ///     0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
652     ///     0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
653     ///     0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
654     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
655     /// ];
656     ///
657     /// let mem = &mut [
658     ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x27,
659     /// ];
660     ///
661     /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog1), 0, 0).unwrap();
662     /// vm.set_program(prog2, 0x40, 0x50);
663     ///
664     /// let res = vm.execute_program(mem).unwrap();
665     /// assert_eq!(res, 0x27);
666     /// ```
667     pub fn set_program(
668         &mut self,
669         prog: &'a [u8],
670         data_offset: usize,
671         data_end_offset: usize,
672     ) -> Result<(), Error> {
673         let get_buff_len = |x: usize, y: usize| if x >= y { x + 8 } else { y + 8 };
674         let buffer = vec![0u8; get_buff_len(data_offset, data_end_offset)];
675         self.mbuff.buffer = buffer;
676         self.mbuff.data_offset = data_offset;
677         self.mbuff.data_end_offset = data_end_offset;
678         self.parent.set_program(prog)?;
679         Ok(())
680     }
681 
682     /// Set a new verifier function. The function should return an `Error` if the program should be
683     /// rejected by the virtual machine. If a program has been loaded to the VM already, the
684     /// verifier is immediately run.
685     ///
686     /// # Examples
687     ///
688     /// ```
689     /// use rbpf::{Error, ErrorKind};
690     /// use rbpf::ebpf;
691     ///
692     /// // Define a simple verifier function.
693     /// fn verifier(prog: &[u8]) -> Result<(), Error> {
694     ///     let last_insn = ebpf::get_insn(prog, (prog.len() / ebpf::INSN_SIZE) - 1);
695     ///     if last_insn.opc != ebpf::EXIT {
696     ///         return Err(Error::new(ErrorKind::Other,
697     ///                    "[Verifier] Error: program does not end with “EXIT” instruction"));
698     ///     }
699     ///     Ok(())
700     /// }
701     ///
702     /// let prog1 = &[
703     ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
704     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
705     /// ];
706     ///
707     /// // Instantiate a VM.
708     /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog1)).unwrap();
709     /// // Change the verifier.
710     /// vm.set_verifier(verifier).unwrap();
711     /// ```
712     pub fn set_verifier(&mut self, verifier: Verifier) -> Result<(), Error> {
713         self.parent.set_verifier(verifier)
714     }
715 
716     /// Register a built-in or user-defined helper function in order to use it later from within
717     /// the eBPF program. The helper is registered into a hashmap, so the `key` can be any `u32`.
718     ///
719     /// If using JIT-compiled eBPF programs, be sure to register all helpers before compiling the
720     /// program. You should be able to change registered helpers after compiling, but not to add
721     /// new ones (i.e. with new keys).
722     ///
723     /// # Examples
724     ///
725     /// ```
726     /// #[cfg(feature = "std")] {
727     ///     use rbpf::helpers;
728     ///
729     ///     // This program was compiled with clang, from a C program containing the following single
730     ///     // instruction: `return bpf_trace_printk("foo %c %c %c\n", 10, 1, 2, 3);`
731     ///     let prog = &[
732     ///         0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
733     ///         0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
734     ///         0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
735     ///         0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
736     ///         0x2d, 0x12, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 6 instructions
737     ///         0x71, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r1
738     ///         0xb7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r2, 0
739     ///         0xb7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r3, 0
740     ///         0xb7, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r4, 0
741     ///         0xb7, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r5, 0
742     ///         0x85, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // call helper with key 1
743     ///         0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
744     ///     ];
745     ///
746     ///     let mem = &mut [
747     ///         0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x09,
748     ///     ];
749     ///
750     ///     // Instantiate a VM.
751     ///     let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
752     ///
753     ///     // Register a helper. This helper will store the result of the square root of r1 into r0.
754     ///     vm.register_helper(1, helpers::sqrti);
755     ///
756     ///     let res = vm.execute_program(mem).unwrap();
757     ///     assert_eq!(res, 3);
758     /// }
759     /// ```
760     pub fn register_helper(
761         &mut self,
762         key: u32,
763         function: fn(u64, u64, u64, u64, u64) -> u64,
764     ) -> Result<(), Error> {
765         self.parent.register_helper(key, function)
766     }
767 
768     /// Execute the program loaded, with the given packet data.
769     ///
770     /// If the program is made to be compatible with Linux kernel, it is expected to load the
771     /// address of the beginning and of the end of the memory area used for packet data from some
772     /// metadata buffer, which in the case of this VM is handled internally. The offsets at which
773     /// the addresses should be placed should have be set at the creation of the VM.
774     ///
775     /// # Examples
776     ///
777     /// ```
778     /// let prog = &[
779     ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
780     ///     0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
781     ///     0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
782     ///     0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
783     ///     0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
784     ///     0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
785     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
786     /// ];
787     /// let mem = &mut [
788     ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
789     /// ];
790     ///
791     /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
792     /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
793     ///
794     /// // Provide only a reference to the packet data. We do not manage the metadata buffer.
795     /// let res = vm.execute_program(mem).unwrap();
796     /// assert_eq!(res, 0xdd);
797     /// ```
798     pub fn execute_program(&mut self, mem: &'a mut [u8]) -> Result<u64, Error> {
799         let l = self.mbuff.buffer.len();
800         // Can this ever happen? Probably not, should be ensured at mbuff creation.
801         if self.mbuff.data_offset + 8 > l || self.mbuff.data_end_offset + 8 > l {
802             Err(Error::new(ErrorKind::Other, format!("Error: buffer too small ({:?}), cannot use data_offset {:?} and data_end_offset {:?}",
803             l, self.mbuff.data_offset, self.mbuff.data_end_offset)))?;
804         }
805         LittleEndian::write_u64(
806             &mut self.mbuff.buffer[(self.mbuff.data_offset)..],
807             mem.as_ptr() as u64,
808         );
809         LittleEndian::write_u64(
810             &mut self.mbuff.buffer[(self.mbuff.data_end_offset)..],
811             mem.as_ptr() as u64 + mem.len() as u64,
812         );
813         self.parent.execute_program(mem, &self.mbuff.buffer)
814     }
815 
816     /// JIT-compile the loaded program. No argument required for this.
817     ///
818     /// If using helper functions, be sure to register them into the VM before calling this
819     /// function.
820     ///
821     /// # Examples
822     ///
823     /// ```
824     /// let prog = &[
825     ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
826     ///     0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
827     ///     0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
828     ///     0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
829     ///     0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
830     ///     0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
831     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
832     /// ];
833     ///
834     /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
835     /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
836     ///
837     /// vm.jit_compile();
838     /// ```
839     #[cfg(all(not(windows), feature = "std"))]
840     pub fn jit_compile(&mut self) -> Result<(), Error> {
841         let prog = match self.parent.prog {
842             Some(prog) => prog,
843             None => Err(Error::new(
844                 ErrorKind::Other,
845                 "Error: No program set, call prog_set() to load one",
846             ))?,
847         };
848         self.parent.jit = Some(jit::JitMemory::new(prog, &self.parent.helpers, true, true)?);
849         Ok(())
850     }
851 
852     /// Execute the previously JIT-compiled program, with the given packet data, in a manner very
853     /// similar to `execute_program()`.
854     ///
855     /// If the program is made to be compatible with Linux kernel, it is expected to load the
856     /// address of the beginning and of the end of the memory area used for packet data from some
857     /// metadata buffer, which in the case of this VM is handled internally. The offsets at which
858     /// the addresses should be placed should have be set at the creation of the VM.
859     ///
860     /// # Safety
861     ///
862     /// **WARNING:** JIT-compiled assembly code is not safe, in particular there is no runtime
863     /// check for memory access; so if the eBPF program attempts erroneous accesses, this may end
864     /// very bad (program may segfault). It may be wise to check that the program works with the
865     /// interpreter before running the JIT-compiled version of it.
866     ///
867     /// For this reason the function should be called from within an `unsafe` bloc.
868     ///
869     /// # Examples
870     ///
871     /// ```
872     /// let prog = &[
873     ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
874     ///     0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
875     ///     0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
876     ///     0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
877     ///     0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
878     ///     0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
879     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
880     /// ];
881     /// let mem = &mut [
882     ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
883     /// ];
884     ///
885     /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
886     /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
887     ///
888     /// # #[cfg(all(not(windows), feature = "std"))]
889     /// vm.jit_compile();
890     ///
891     /// // Provide only a reference to the packet data. We do not manage the metadata buffer.
892     /// # #[cfg(all(not(windows), feature = "std"))]
893     /// unsafe {
894     ///     let res = vm.execute_program_jit(mem).unwrap();
895     ///     assert_eq!(res, 0xdd);
896     /// }
897     /// ```
898     // This struct redefines the `execute_program_jit()` function, in order to pass the offsets
899     // associated with the fixed mbuff.
900     #[cfg(all(not(windows), feature = "std"))]
901     pub unsafe fn execute_program_jit(&mut self, mem: &'a mut [u8]) -> Result<u64, Error> {
902         // If packet data is empty, do not send the address of an empty slice; send a null pointer
903         //  as first argument instead, as this is uBPF's behavior (empty packet should not happen
904         //  in the kernel; anyway the verifier would prevent the use of uninitialized registers).
905         //  See `mul_loop` test.
906         let mem_ptr = match mem.len() {
907             0 => core::ptr::null_mut(),
908             _ => mem.as_ptr() as *mut u8,
909         };
910 
911         match &self.parent.jit {
912             Some(jit) => Ok(jit.get_prog()(
913                 self.mbuff.buffer.as_ptr() as *mut u8,
914                 self.mbuff.buffer.len(),
915                 mem_ptr,
916                 mem.len(),
917                 self.mbuff.data_offset,
918                 self.mbuff.data_end_offset,
919             )),
920             None => Err(Error::new(
921                 ErrorKind::Other,
922                 "Error: program has not been JIT-compiled",
923             )),
924         }
925     }
926 
927     /// Compile the loaded program using the Cranelift JIT.
928     ///
929     /// If using helper functions, be sure to register them into the VM before calling this
930     /// function.
931     ///
932     /// # Examples
933     ///
934     /// ```
935     /// let prog = &[
936     ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
937     ///     0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
938     ///     0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
939     ///     0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
940     ///     0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
941     ///     0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
942     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
943     /// ];
944     ///
945     /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
946     /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
947     ///
948     /// vm.cranelift_compile();
949     /// ```
950     #[cfg(feature = "cranelift")]
951     pub fn cranelift_compile(&mut self) -> Result<(), Error> {
952         use crate::cranelift::CraneliftCompiler;
953 
954         let prog = match self.parent.prog {
955             Some(prog) => prog,
956             None => Err(Error::new(
957                 ErrorKind::Other,
958                 "Error: No program set, call prog_set() to load one",
959             ))?,
960         };
961 
962         let mut compiler = CraneliftCompiler::new(self.parent.helpers.clone());
963         let program = compiler.compile_function(prog)?;
964 
965         self.parent.cranelift_prog = Some(program);
966         Ok(())
967     }
968 
969     /// Execute the previously compiled program, with the given packet data and metadata
970     /// buffer, in a manner very similar to `execute_program()`.
971     ///
972     /// If the program is made to be compatible with Linux kernel, it is expected to load the
973     /// address of the beginning and of the end of the memory area used for packet data from some
974     /// metadata buffer, which in the case of this VM is handled internally. The offsets at which
975     /// the addresses should be placed should have be set at the creation of the VM.
976     ///
977     /// # Examples
978     ///
979     /// ```
980     /// let prog = &[
981     ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
982     ///     0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
983     ///     0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
984     ///     0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
985     ///     0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
986     ///     0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
987     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
988     /// ];
989     /// let mem = &mut [
990     ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
991     /// ];
992     ///
993     /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
994     /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
995     ///
996     /// vm.cranelift_compile();
997     ///
998     /// // Provide only a reference to the packet data. We do not manage the metadata buffer.
999     /// let res = vm.execute_program_cranelift(mem).unwrap();
1000     /// assert_eq!(res, 0xdd);
1001     /// ```
1002     #[cfg(feature = "cranelift")]
1003     pub fn execute_program_cranelift(&mut self, mem: &'a mut [u8]) -> Result<u64, Error> {
1004         // If packet data is empty, do not send the address of an empty slice; send a null pointer
1005         //  as first argument instead, as this is uBPF's behavior (empty packet should not happen
1006         //  in the kernel; anyway the verifier would prevent the use of uninitialized registers).
1007         //  See `mul_loop` test.
1008         let mem_ptr = match mem.len() {
1009             0 => core::ptr::null_mut(),
1010             _ => mem.as_ptr() as *mut u8,
1011         };
1012 
1013         let l = self.mbuff.buffer.len();
1014         // Can this ever happen? Probably not, should be ensured at mbuff creation.
1015         if self.mbuff.data_offset + 8 > l || self.mbuff.data_end_offset + 8 > l {
1016             Err(Error::new(ErrorKind::Other, format!("Error: buffer too small ({:?}), cannot use data_offset {:?} and data_end_offset {:?}",
1017             l, self.mbuff.data_offset, self.mbuff.data_end_offset)))?;
1018         }
1019         LittleEndian::write_u64(
1020             &mut self.mbuff.buffer[(self.mbuff.data_offset)..],
1021             mem.as_ptr() as u64,
1022         );
1023         LittleEndian::write_u64(
1024             &mut self.mbuff.buffer[(self.mbuff.data_end_offset)..],
1025             mem.as_ptr() as u64 + mem.len() as u64,
1026         );
1027 
1028         match &self.parent.cranelift_prog {
1029             Some(prog) => Ok(prog.execute(
1030                 mem_ptr,
1031                 mem.len(),
1032                 self.mbuff.buffer.as_ptr() as *mut u8,
1033                 self.mbuff.buffer.len(),
1034             )),
1035             None => Err(Error::new(
1036                 ErrorKind::Other,
1037                 "Error: program has not been compiled with cranelift",
1038             )),
1039         }
1040     }
1041 }
1042 
1043 /// A virtual machine to run eBPF program. This kind of VM is used for programs expecting to work
1044 /// directly on the memory area representing packet data.
1045 ///
1046 /// # Examples
1047 ///
1048 /// ```
1049 /// let prog = &[
1050 ///     0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
1051 ///     0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
1052 ///     0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
1053 ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1054 /// ];
1055 /// let mem = &mut [
1056 ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
1057 /// ];
1058 ///
1059 /// // Instantiate a VM.
1060 /// let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
1061 ///
1062 /// // Provide only a reference to the packet data.
1063 /// let res = vm.execute_program(mem).unwrap();
1064 /// assert_eq!(res, 0x22cc);
1065 /// ```
1066 pub struct EbpfVmRaw<'a> {
1067     parent: EbpfVmMbuff<'a>,
1068 }
1069 
1070 impl<'a> EbpfVmRaw<'a> {
1071     /// Create a new virtual machine instance, and load an eBPF program into that instance.
1072     /// When attempting to load the program, it passes through a simple verifier.
1073     ///
1074     /// # Examples
1075     ///
1076     /// ```
1077     /// let prog = &[
1078     ///     0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
1079     ///     0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
1080     ///     0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
1081     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1082     /// ];
1083     ///
1084     /// // Instantiate a VM.
1085     /// let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
1086     /// ```
1087     pub fn new(prog: Option<&'a [u8]>) -> Result<EbpfVmRaw<'a>, Error> {
1088         let parent = EbpfVmMbuff::new(prog)?;
1089         Ok(EbpfVmRaw { parent })
1090     }
1091 
1092     /// Load a new eBPF program into the virtual machine instance.
1093     ///
1094     /// # Examples
1095     ///
1096     /// ```
1097     /// let prog1 = &[
1098     ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
1099     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1100     /// ];
1101     /// let prog2 = &[
1102     ///     0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
1103     ///     0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
1104     ///     0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
1105     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1106     /// ];
1107     ///
1108     /// let mem = &mut [
1109     ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x27,
1110     /// ];
1111     ///
1112     /// let mut vm = rbpf::EbpfVmRaw::new(Some(prog1)).unwrap();
1113     /// vm.set_program(prog2);
1114     ///
1115     /// let res = vm.execute_program(mem).unwrap();
1116     /// assert_eq!(res, 0x22cc);
1117     /// ```
1118     pub fn set_program(&mut self, prog: &'a [u8]) -> Result<(), Error> {
1119         self.parent.set_program(prog)?;
1120         Ok(())
1121     }
1122 
1123     /// Set a new verifier function. The function should return an `Error` if the program should be
1124     /// rejected by the virtual machine. If a program has been loaded to the VM already, the
1125     /// verifier is immediately run.
1126     ///
1127     /// # Examples
1128     ///
1129     /// ```
1130     /// use rbpf::{Error, ErrorKind};
1131     /// use rbpf::ebpf;
1132     ///
1133     /// // Define a simple verifier function.
1134     /// fn verifier(prog: &[u8]) -> Result<(), Error> {
1135     ///     let last_insn = ebpf::get_insn(prog, (prog.len() / ebpf::INSN_SIZE) - 1);
1136     ///     if last_insn.opc != ebpf::EXIT {
1137     ///         return Err(Error::new(ErrorKind::Other,
1138     ///                    "[Verifier] Error: program does not end with “EXIT” instruction"));
1139     ///     }
1140     ///     Ok(())
1141     /// }
1142     ///
1143     /// let prog1 = &[
1144     ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
1145     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1146     /// ];
1147     ///
1148     /// // Instantiate a VM.
1149     /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog1)).unwrap();
1150     /// // Change the verifier.
1151     /// vm.set_verifier(verifier).unwrap();
1152     /// ```
1153     pub fn set_verifier(&mut self, verifier: Verifier) -> Result<(), Error> {
1154         self.parent.set_verifier(verifier)
1155     }
1156 
1157     /// Register a built-in or user-defined helper function in order to use it later from within
1158     /// the eBPF program. The helper is registered into a hashmap, so the `key` can be any `u32`.
1159     ///
1160     /// If using JIT-compiled eBPF programs, be sure to register all helpers before compiling the
1161     /// program. You should be able to change registered helpers after compiling, but not to add
1162     /// new ones (i.e. with new keys).
1163     ///
1164     /// # Examples
1165     ///
1166     /// ```
1167     /// #[cfg(feature = "std")] {
1168     ///     use rbpf::helpers;
1169     ///
1170     ///     let prog = &[
1171     ///         0x79, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxdw r1, r1[0x00]
1172     ///         0xb7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r2, 0
1173     ///         0xb7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r3, 0
1174     ///         0xb7, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r4, 0
1175     ///         0xb7, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r5, 0
1176     ///         0x85, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // call helper with key 1
1177     ///         0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1178     ///     ];
1179     ///
1180     ///     let mem = &mut [
1181     ///         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
1182     ///     ];
1183     ///
1184     ///     // Instantiate a VM.
1185     ///     let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
1186     ///
1187     ///     // Register a helper. This helper will store the result of the square root of r1 into r0.
1188     ///     vm.register_helper(1, helpers::sqrti);
1189     ///
1190     ///     let res = vm.execute_program(mem).unwrap();
1191     ///     assert_eq!(res, 0x10000000);
1192     /// }
1193     /// ```
1194     pub fn register_helper(
1195         &mut self,
1196         key: u32,
1197         function: fn(u64, u64, u64, u64, u64) -> u64,
1198     ) -> Result<(), Error> {
1199         self.parent.register_helper(key, function)
1200     }
1201 
1202     /// Register a set of built-in or user-defined helper functions in order to use them later from
1203     /// within the eBPF program. The helpers are registered into a hashmap, so the `key` can be any
1204     /// `u32`.
1205     #[allow(clippy::type_complexity)]
1206     pub fn register_helper_set(
1207         &mut self,
1208         helpers: &HashMap<u32, fn(u64, u64, u64, u64, u64) -> u64>,
1209     ) -> Result<(), Error> {
1210         for (key, function) in helpers {
1211             self.parent.register_helper(*key, *function)?;
1212         }
1213         Ok(())
1214     }
1215 
1216     /// Execute the program loaded, with the given packet data.
1217     ///
1218     /// # Examples
1219     ///
1220     /// ```
1221     /// let prog = &[
1222     ///     0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
1223     ///     0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
1224     ///     0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
1225     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1226     /// ];
1227     ///
1228     /// let mem = &mut [
1229     ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x27
1230     /// ];
1231     ///
1232     /// let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
1233     ///
1234     /// let res = vm.execute_program(mem).unwrap();
1235     /// assert_eq!(res, 0x22cc);
1236     /// ```
1237     pub fn execute_program(&self, mem: &'a mut [u8]) -> Result<u64, Error> {
1238         self.parent.execute_program(mem, &[])
1239     }
1240 
1241     /// JIT-compile the loaded program. No argument required for this.
1242     ///
1243     /// If using helper functions, be sure to register them into the VM before calling this
1244     /// function.
1245     ///
1246     /// # Examples
1247     ///
1248     /// ```
1249     /// let prog = &[
1250     ///     0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
1251     ///     0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
1252     ///     0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
1253     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1254     /// ];
1255     ///
1256     /// let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
1257     ///
1258     /// vm.jit_compile();
1259     /// ```
1260     #[cfg(all(not(windows), feature = "std"))]
1261     pub fn jit_compile(&mut self) -> Result<(), Error> {
1262         let prog = match self.parent.prog {
1263             Some(prog) => prog,
1264             None => Err(Error::new(
1265                 ErrorKind::Other,
1266                 "Error: No program set, call prog_set() to load one",
1267             ))?,
1268         };
1269         self.parent.jit = Some(jit::JitMemory::new(
1270             prog,
1271             &self.parent.helpers,
1272             false,
1273             false,
1274         )?);
1275         Ok(())
1276     }
1277 
1278     /// Execute the previously JIT-compiled program, with the given packet data, in a manner very
1279     /// similar to `execute_program()`.
1280     ///
1281     /// # Safety
1282     ///
1283     /// **WARNING:** JIT-compiled assembly code is not safe, in particular there is no runtime
1284     /// check for memory access; so if the eBPF program attempts erroneous accesses, this may end
1285     /// very bad (program may segfault). It may be wise to check that the program works with the
1286     /// interpreter before running the JIT-compiled version of it.
1287     ///
1288     /// For this reason the function should be called from within an `unsafe` bloc.
1289     ///
1290     /// # Examples
1291     ///
1292     /// ```
1293     /// let prog = &[
1294     ///     0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
1295     ///     0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
1296     ///     0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
1297     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1298     /// ];
1299     ///
1300     /// let mem = &mut [
1301     ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x27
1302     /// ];
1303     ///
1304     /// let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
1305     ///
1306     /// # #[cfg(all(not(windows), feature = "std"))]
1307     /// vm.jit_compile();
1308     ///
1309     /// # #[cfg(all(not(windows), feature = "std"))]
1310     /// unsafe {
1311     ///     let res = vm.execute_program_jit(mem).unwrap();
1312     ///     assert_eq!(res, 0x22cc);
1313     /// }
1314     /// ```
1315     #[cfg(all(not(windows), feature = "std"))]
1316     pub unsafe fn execute_program_jit(&self, mem: &'a mut [u8]) -> Result<u64, Error> {
1317         let mut mbuff = vec![];
1318         self.parent.execute_program_jit(mem, &mut mbuff)
1319     }
1320 
1321     /// Compile the loaded program using the Cranelift JIT.
1322     ///
1323     /// If using helper functions, be sure to register them into the VM before calling this
1324     /// function.
1325     ///
1326     /// # Examples
1327     ///
1328     /// ```
1329     /// let prog = &[
1330     ///     0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
1331     ///     0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
1332     ///     0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
1333     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1334     /// ];
1335     ///
1336     /// let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
1337     ///
1338     /// vm.cranelift_compile();
1339     /// ```
1340     #[cfg(feature = "cranelift")]
1341     pub fn cranelift_compile(&mut self) -> Result<(), Error> {
1342         use crate::cranelift::CraneliftCompiler;
1343 
1344         let prog = match self.parent.prog {
1345             Some(prog) => prog,
1346             None => Err(Error::new(
1347                 ErrorKind::Other,
1348                 "Error: No program set, call prog_set() to load one",
1349             ))?,
1350         };
1351 
1352         let mut compiler = CraneliftCompiler::new(self.parent.helpers.clone());
1353         let program = compiler.compile_function(prog)?;
1354 
1355         self.parent.cranelift_prog = Some(program);
1356         Ok(())
1357     }
1358 
1359     /// Execute the previously compiled program, with the given packet data, in a manner very
1360     /// similar to `execute_program()`.
1361     ///
1362     /// # Examples
1363     ///
1364     /// ```
1365     /// let prog = &[
1366     ///     0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
1367     ///     0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
1368     ///     0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
1369     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1370     /// ];
1371     ///
1372     /// let mem = &mut [
1373     ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x27
1374     /// ];
1375     ///
1376     /// let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
1377     ///
1378     /// vm.cranelift_compile();
1379     ///
1380     /// let res = vm.execute_program_cranelift(mem).unwrap();
1381     /// assert_eq!(res, 0x22cc);
1382     /// ```
1383     #[cfg(feature = "cranelift")]
1384     pub fn execute_program_cranelift(&self, mem: &'a mut [u8]) -> Result<u64, Error> {
1385         let mut mbuff = vec![];
1386         self.parent.execute_program_cranelift(mem, &mut mbuff)
1387     }
1388 }
1389 
1390 /// A virtual machine to run eBPF program. This kind of VM is used for programs that do not work
1391 /// with any memory area—no metadata buffer, no packet data either.
1392 ///
1393 /// # Examples
1394 ///
1395 /// ```
1396 /// let prog = &[
1397 ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
1398 ///     0xb7, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // mov r1, 1
1399 ///     0xb7, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // mov r2, 2
1400 ///     0xb7, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // mov r3, 3
1401 ///     0xb7, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, // mov r4, 4
1402 ///     0xb7, 0x05, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // mov r5, 5
1403 ///     0xb7, 0x06, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, // mov r6, 6
1404 ///     0xb7, 0x07, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, // mov r7, 7
1405 ///     0xb7, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, // mov r8, 8
1406 ///     0x4f, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // or r0, r5
1407 ///     0x47, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, // or r0, 0xa0
1408 ///     0x57, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, // and r0, 0xa3
1409 ///     0xb7, 0x09, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, // mov r9, 0x91
1410 ///     0x5f, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // and r0, r9
1411 ///     0x67, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, // lsh r0, 32
1412 ///     0x67, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, // lsh r0, 22
1413 ///     0x6f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // lsh r0, r8
1414 ///     0x77, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, // rsh r0, 32
1415 ///     0x77, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, // rsh r0, 19
1416 ///     0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // rsh r0, r7
1417 ///     0xa7, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // xor r0, 0x03
1418 ///     0xaf, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // xor r0, r2
1419 ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1420 /// ];
1421 ///
1422 /// // Instantiate a VM.
1423 /// let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
1424 ///
1425 /// // Provide only a reference to the packet data.
1426 /// let res = vm.execute_program().unwrap();
1427 /// assert_eq!(res, 0x11);
1428 /// ```
1429 pub struct EbpfVmNoData<'a> {
1430     parent: EbpfVmRaw<'a>,
1431 }
1432 
1433 impl<'a> EbpfVmNoData<'a> {
1434     /// Create a new virtual machine instance, and load an eBPF program into that instance.
1435     /// When attempting to load the program, it passes through a simple verifier.
1436     ///
1437     /// # Examples
1438     ///
1439     /// ```
1440     /// let prog = &[
1441     ///     0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
1442     ///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
1443     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1444     /// ];
1445     ///
1446     /// // Instantiate a VM.
1447     /// let vm = rbpf::EbpfVmNoData::new(Some(prog));
1448     /// ```
1449     pub fn new(prog: Option<&'a [u8]>) -> Result<EbpfVmNoData<'a>, Error> {
1450         let parent = EbpfVmRaw::new(prog)?;
1451         Ok(EbpfVmNoData { parent })
1452     }
1453 
1454     /// Load a new eBPF program into the virtual machine instance.
1455     ///
1456     /// # Examples
1457     ///
1458     /// ```
1459     /// let prog1 = &[
1460     ///     0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
1461     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1462     /// ];
1463     /// let prog2 = &[
1464     ///     0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
1465     ///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
1466     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1467     /// ];
1468     ///
1469     /// let mut vm = rbpf::EbpfVmNoData::new(Some(prog1)).unwrap();
1470     ///
1471     /// let res = vm.execute_program().unwrap();
1472     /// assert_eq!(res, 0x2211);
1473     ///
1474     /// vm.set_program(prog2);
1475     ///
1476     /// let res = vm.execute_program().unwrap();
1477     /// assert_eq!(res, 0x1122);
1478     /// ```
1479     pub fn set_program(&mut self, prog: &'a [u8]) -> Result<(), Error> {
1480         self.parent.set_program(prog)?;
1481         Ok(())
1482     }
1483 
1484     /// Set a new verifier function. The function should return an `Error` if the program should be
1485     /// rejected by the virtual machine. If a program has been loaded to the VM already, the
1486     /// verifier is immediately run.
1487     ///
1488     /// # Examples
1489     ///
1490     /// ```
1491     /// use rbpf::{Error, ErrorKind};
1492     /// use rbpf::ebpf;
1493     ///
1494     /// // Define a simple verifier function.
1495     /// fn verifier(prog: &[u8]) -> Result<(), Error> {
1496     ///     let last_insn = ebpf::get_insn(prog, (prog.len() / ebpf::INSN_SIZE) - 1);
1497     ///     if last_insn.opc != ebpf::EXIT {
1498     ///         return Err(Error::new(ErrorKind::Other,
1499     ///                    "[Verifier] Error: program does not end with “EXIT” instruction"));
1500     ///     }
1501     ///     Ok(())
1502     /// }
1503     ///
1504     /// let prog1 = &[
1505     ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
1506     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1507     /// ];
1508     ///
1509     /// // Instantiate a VM.
1510     /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog1)).unwrap();
1511     /// // Change the verifier.
1512     /// vm.set_verifier(verifier).unwrap();
1513     /// ```
1514     pub fn set_verifier(&mut self, verifier: Verifier) -> Result<(), Error> {
1515         self.parent.set_verifier(verifier)
1516     }
1517 
1518     /// Register a built-in or user-defined helper function in order to use it later from within
1519     /// the eBPF program. The helper is registered into a hashmap, so the `key` can be any `u32`.
1520     ///
1521     /// If using JIT-compiled eBPF programs, be sure to register all helpers before compiling the
1522     /// program. You should be able to change registered helpers after compiling, but not to add
1523     /// new ones (i.e. with new keys).
1524     ///
1525     /// # Examples
1526     ///
1527     /// ```
1528     /// #[cfg(feature = "std")] {
1529     ///     use rbpf::helpers;
1530     ///
1531     ///     let prog = &[
1532     ///         0xb7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // mov r1, 0x010000000
1533     ///         0xb7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r2, 0
1534     ///         0xb7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r3, 0
1535     ///         0xb7, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r4, 0
1536     ///         0xb7, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r5, 0
1537     ///         0x85, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // call helper with key 1
1538     ///         0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1539     ///     ];
1540     ///
1541     ///     let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
1542     ///
1543     ///     // Register a helper. This helper will store the result of the square root of r1 into r0.
1544     ///     vm.register_helper(1, helpers::sqrti).unwrap();
1545     ///
1546     ///     let res = vm.execute_program().unwrap();
1547     ///     assert_eq!(res, 0x1000);
1548     /// }
1549     /// ```
1550     pub fn register_helper(
1551         &mut self,
1552         key: u32,
1553         function: fn(u64, u64, u64, u64, u64) -> u64,
1554     ) -> Result<(), Error> {
1555         self.parent.register_helper(key, function)
1556     }
1557 
1558     /// JIT-compile the loaded program. No argument required for this.
1559     ///
1560     /// If using helper functions, be sure to register them into the VM before calling this
1561     /// function.
1562     ///
1563     /// # Examples
1564     ///
1565     /// ```
1566     /// let prog = &[
1567     ///     0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
1568     ///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
1569     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1570     /// ];
1571     ///
1572     /// let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
1573     ///
1574     ///
1575     /// vm.jit_compile();
1576     /// ```
1577     #[cfg(all(not(windows), feature = "std"))]
1578     pub fn jit_compile(&mut self) -> Result<(), Error> {
1579         self.parent.jit_compile()
1580     }
1581 
1582     /// Execute the program loaded, without providing pointers to any memory area whatsoever.
1583     ///
1584     /// # Examples
1585     ///
1586     /// ```
1587     /// let prog = &[
1588     ///     0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
1589     ///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
1590     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1591     /// ];
1592     ///
1593     /// let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
1594     ///
1595     /// // For this kind of VM, the `execute_program()` function needs no argument.
1596     /// let res = vm.execute_program().unwrap();
1597     /// assert_eq!(res, 0x1122);
1598     /// ```
1599     pub fn execute_program(&self) -> Result<u64, Error> {
1600         self.parent.execute_program(&mut [])
1601     }
1602 
1603     /// Execute the previously JIT-compiled program, without providing pointers to any memory area
1604     /// whatsoever, in a manner very similar to `execute_program()`.
1605     ///
1606     /// # Safety
1607     ///
1608     /// **WARNING:** JIT-compiled assembly code is not safe, in particular there is no runtime
1609     /// check for memory access; so if the eBPF program attempts erroneous accesses, this may end
1610     /// very bad (program may segfault). It may be wise to check that the program works with the
1611     /// interpreter before running the JIT-compiled version of it.
1612     ///
1613     /// For this reason the function should be called from within an `unsafe` bloc.
1614     ///
1615     /// # Examples
1616     ///
1617     /// ```
1618     /// let prog = &[
1619     ///     0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
1620     ///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
1621     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1622     /// ];
1623     ///
1624     /// let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
1625     ///
1626     /// # #[cfg(all(not(windows), feature = "std"))]
1627     /// vm.jit_compile();
1628     ///
1629     /// # #[cfg(all(not(windows), feature = "std"))]
1630     /// unsafe {
1631     ///     let res = vm.execute_program_jit().unwrap();
1632     ///     assert_eq!(res, 0x1122);
1633     /// }
1634     /// ```
1635     #[cfg(all(not(windows), feature = "std"))]
1636     pub unsafe fn execute_program_jit(&self) -> Result<u64, Error> {
1637         self.parent.execute_program_jit(&mut [])
1638     }
1639 
1640     /// Compile the loaded program using the Cranelift JIT.
1641     ///
1642     /// If using helper functions, be sure to register them into the VM before calling this
1643     /// function.
1644     ///
1645     /// # Examples
1646     ///
1647     /// ```
1648     /// let prog = &[
1649     ///     0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
1650     ///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
1651     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1652     /// ];
1653     ///
1654     /// let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
1655     ///
1656     ///
1657     /// vm.cranelift_compile();
1658     /// ```
1659     #[cfg(feature = "cranelift")]
1660     pub fn cranelift_compile(&mut self) -> Result<(), Error> {
1661         self.parent.cranelift_compile()
1662     }
1663 
1664     /// Execute the previously JIT-compiled program, without providing pointers to any memory area
1665     /// whatsoever, in a manner very similar to `execute_program()`.
1666     ///
1667     /// # Examples
1668     ///
1669     /// ```
1670     /// let prog = &[
1671     ///     0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
1672     ///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
1673     ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
1674     /// ];
1675     ///
1676     /// let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
1677     ///
1678     /// vm.cranelift_compile();
1679     ///
1680     /// let res = vm.execute_program_cranelift().unwrap();
1681     /// assert_eq!(res, 0x1122);
1682     /// ```
1683     #[cfg(feature = "cranelift")]
1684     pub fn execute_program_cranelift(&self) -> Result<u64, Error> {
1685         self.parent.execute_program_cranelift(&mut [])
1686     }
1687 }
1688 
1689 /// EbpfVm with Owned data
1690 pub struct EbpfVmRawOwned {
1691     parent: EbpfVmRaw<'static>,
1692     data_len: usize,
1693     data_cap: usize,
1694 }
1695 
1696 impl EbpfVmRawOwned {
1697     /// Create a new virtual machine instance, and load an eBPF program into that instance.
1698     /// When attempting to load the program, it passes through a simple verifier.
1699     pub fn new(prog: Option<Vec<u8>>) -> Result<EbpfVmRawOwned, Error> {
1700         let (prog, data_len, data_cap) = match prog {
1701             Some(prog) => {
1702                 let data_len = prog.len();
1703                 let data_cap = prog.capacity();
1704                 let slice = prog.leak();
1705                 let slice = unsafe { core::slice::from_raw_parts(slice.as_ptr(), data_len) };
1706                 (Some(slice), data_len, data_cap)
1707             }
1708             None => (None, 0, 0),
1709         };
1710         let parent = EbpfVmRaw::new(prog)?;
1711         Ok(Self {
1712             parent,
1713             data_len,
1714             data_cap,
1715         })
1716     }
1717     /// Load a new eBPF program into the virtual machine instance
1718     pub fn set_program(&mut self, prog: Vec<u8>) -> Result<(), Error> {
1719         self.data_len = prog.len();
1720         self.data_cap = prog.capacity();
1721         let slice = prog.leak();
1722         self.parent.set_program(slice)?;
1723         Ok(())
1724     }
1725 
1726     /// Set a new verifier function. The function should return an Error if the program should be rejected by the virtual machine.
1727     /// If a program has been loaded to the VM already, the verifier is immediately run.
1728     pub fn set_verifier(&mut self, verifier: Verifier) -> Result<(), Error> {
1729         self.parent.set_verifier(verifier)
1730     }
1731 
1732     /// Register a built-in or user-defined helper function in order to use it later from within the eBPF program.
1733     /// The helper is registered into a hashmap, so the key can be any u32.
1734     /// If using JIT-compiled eBPF programs, be sure to register all helpers before compiling the program.
1735     /// You should be able to change registered helpers after compiling, but not to add new ones (i. e. with new keys).
1736     pub fn register_helper(
1737         &mut self,
1738         key: u32,
1739         function: fn(u64, u64, u64, u64, u64) -> u64,
1740     ) -> Result<(), Error> {
1741         self.parent.register_helper(key, function)
1742     }
1743 
1744     /// Register a set of built-in or user-defined helper functions in order to use them later from
1745     /// within the eBPF program. The helpers are registered into a hashmap, so the `key` can be any
1746     /// `u32`.
1747     #[allow(clippy::type_complexity)]
1748     pub fn register_helper_set(
1749         &mut self,
1750         helpers: &HashMap<u32, fn(u64, u64, u64, u64, u64) -> u64>,
1751     ) -> Result<(), Error> {
1752         for (key, function) in helpers {
1753             self.parent.register_helper(*key, *function)?;
1754         }
1755         Ok(())
1756     }
1757 
1758     /// Execute the previously JIT-compiled program, with the given packet data, in a manner very similar to execute_program().
1759     ///
1760     /// Safety
1761     ///
1762     /// **WARNING:** JIT-compiled assembly code is not safe, in particular there is no runtime check for memory access;
1763     /// so if the eBPF program attempts erroneous accesses, this may end very bad (program may segfault).
1764     /// It may be wise to check that the program works with the interpreter before running the JIT-compiled version of it.
1765     ///
1766     /// For this reason the function should be called from within an unsafe bloc.
1767     pub fn execute_program(&self, mem: &mut [u8]) -> Result<u64, Error> {
1768         self.parent.execute_program(mem)
1769     }
1770 }
1771 
1772 impl Drop for EbpfVmRawOwned {
1773     fn drop(&mut self) {
1774         match self.parent.parent.prog {
1775             Some(prog) => unsafe {
1776                 let ptr = prog.as_ptr();
1777                 let _prog = Vec::from_raw_parts(ptr as *mut u8, self.data_len, self.data_cap);
1778             },
1779             None => {}
1780         };
1781     }
1782 }
1783