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