Skip to main content

rbpf/
lib.rs

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