xref: /DragonOS/kernel/crates/rbpf/tests/misc.rs (revision f5b2038871d3441e1c7f32439ff422957e7ab828)
1 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
2 // Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
3 
4 // There are unused mut warnings due to unsafe code.
5 #![allow(unused_mut)]
6 #![allow(clippy::unreadable_literal)]
7 
8 // This crate would be needed to load bytecode from a BPF-compiled object file. Since the crate
9 // is not used anywhere else in the library, it is deactivated: we do not want to load and compile
10 // it just for the tests. If you want to use it, do not forget to add the following
11 // dependency to your Cargo.toml file:
12 //
13 // ---
14 // elf = "0.0.10"
15 // ---
16 //
17 // extern crate elf;
18 // use std::path::PathBuf;
19 
20 extern crate rbpf;
21 
22 #[cfg(feature = "std")]
23 use rbpf::helpers;
24 use rbpf::{assembler::assemble, Error, ErrorKind};
25 
26 // The following two examples have been compiled from C with the following command:
27 //
28 // ```bash
29 //  clang -O2 -emit-llvm -c <file.c> -o - | llc -march=bpf -filetype=obj -o <file.o>
30 // ```
31 //
32 // The C source code was the following:
33 //
34 // ```c
35 // #include <linux/ip.h>
36 // #include <linux/in.h>
37 // #include <linux/tcp.h>
38 // #include <linux/bpf.h>
39 //
40 // #define ETH_ALEN 6
41 // #define ETH_P_IP 0x0008 /* htons(0x0800) */
42 // #define TCP_HDR_LEN 20
43 //
44 // #define BLOCKED_TCP_PORT 0x9999
45 //
46 // struct eth_hdr {
47 //     unsigned char   h_dest[ETH_ALEN];
48 //     unsigned char   h_source[ETH_ALEN];
49 //     unsigned short  h_proto;
50 // };
51 //
52 // #define SEC(NAME) __attribute__((section(NAME), used))
53 // SEC(".classifier")
54 // int handle_ingress(struct __sk_buff *skb)
55 // {
56 //     void *data = (void *)(long)skb->data;
57 //     void *data_end = (void *)(long)skb->data_end;
58 //     struct eth_hdr *eth = data;
59 //     struct iphdr *iph = data + sizeof(*eth);
60 //     struct tcphdr *tcp = data + sizeof(*eth) + sizeof(*iph);
61 //
62 //     /* single length check */
63 //     if (data + sizeof(*eth) + sizeof(*iph) + sizeof(*tcp) > data_end)
64 //         return 0;
65 //     if (eth->h_proto != ETH_P_IP)
66 //         return 0;
67 //     if (iph->protocol != IPPROTO_TCP)
68 //         return 0;
69 //     if (tcp->source == BLOCKED_TCP_PORT || tcp->dest == BLOCKED_TCP_PORT)
70 //         return -1;
71 //     return 0;
72 // }
73 // char _license[] SEC(".license") = "GPL";
74 // ```
75 //
76 // This program, once compiled, can be injected into Linux kernel, with tc for instance. Sadly, we
77 // need to bring some modifications to the generated bytecode in order to run it: the three
78 // instructions with opcode 0x61 load data from a packet area as 4-byte words, where we need to
79 // load it as 8-bytes double words (0x79). The kernel does the same kind of translation before
80 // running the program, but rbpf does not implement this.
81 //
82 // In addition, the offset at which the pointer to the packet data is stored must be changed: since
83 // we use 8 bytes instead of 4 for the start and end addresses of the data packet, we cannot use
84 // the offsets produced by clang (0x4c and 0x50), the addresses would overlap. Instead we can use,
85 // for example, 0x40 and 0x50. See comments on the bytecode below to see the modifications.
86 //
87 // Once the bytecode has been (manually, in our case) edited, we can load the bytecode directly
88 // from the ELF object file. This is easy to do, but requires the addition of two crates in the
89 // Cargo.toml file (see comments above), so here we use just the hardcoded bytecode instructions
90 // instead.
91 
92 #[test]
93 #[cfg(feature = "std")]
94 fn test_vm_block_port() {
95     // To load the bytecode from an object file instead of using the hardcoded instructions,
96     // use the additional crates commented at the beginning of this file (and also add them to your
97     // Cargo.toml). See comments above.
98     //
99     // ---
100     // let filename = "my_ebpf_object_file.o";
101     //
102     // let path = PathBuf::from(filename);
103     // let file = match elf::File::open_path(&path) {
104     //     Ok(f) => f,
105     //     Err(e) => panic!("Error: {:?}", e),
106     // };
107     //
108     // let text_scn = match file.get_section(".classifier") {
109     //     Some(s) => s,
110     //     None => panic!("Failed to look up .classifier section"),
111     // };
112     //
113     // let prog = &text_scn.data;
114     // ---
115 
116     let prog = &[
117         0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x12, 0x50, 0x00, 0x00, 0x00, 0x00,
118         0x00, // 0x79 instead of 0x61
119         0x79, 0x11, 0x40, 0x00, 0x00, 0x00, 0x00,
120         0x00, // 0x79 instead of 0x61, 0x40 i.o. 0x4c
121         0xbf, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00, 0x36, 0x00, 0x00,
122         0x00, 0x2d, 0x23, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x12, 0x0c, 0x00, 0x00, 0x00,
123         0x00, 0x00, 0x55, 0x02, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, 0x71, 0x12, 0x17, 0x00, 0x00,
124         0x00, 0x00, 0x00, 0x55, 0x02, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
125         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x11, 0x22,
126         0x00, 0x00, 0x00, 0x00, 0x00, // 0x79 instead of 0x61
127         0xbf, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x02, 0x00, 0x00, 0xff, 0xff, 0x00,
128         0x00, 0x15, 0x02, 0x08, 0x00, 0x99, 0x99, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00, 0x00, 0x00,
129         0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x21, 0x00, 0x00, 0x00,
130         0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x18, 0x02, 0x00, 0x00,
131         0x00, 0x00, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x21, 0x01,
132         0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00,
133         0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134     ];
135 
136     let packet = &mut [
137         0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x08,
138         0x00, // ethertype
139         0x45, 0x00, 0x00, 0x3b, // start ip_hdr
140         0xa6, 0xab, 0x40, 0x00, 0x40, 0x06, 0x96, 0x0f, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00,
141         0x01,
142         // Program matches the next two bytes: 0x9999 returns 0xffffffff, else return 0.
143         0x99, 0x99, 0xc6, 0xcc, // start tcp_hdr
144         0xd1, 0xe5, 0xc4, 0x9d, 0xd4, 0x30, 0xb5, 0xd2, 0x80, 0x18, 0x01, 0x56, 0xfe, 0x2f, 0x00,
145         0x00, 0x01, 0x01, 0x08, 0x0a, // start data
146         0x00, 0x23, 0x75, 0x89, 0x00, 0x23, 0x63, 0x2d, 0x71, 0x64, 0x66, 0x73, 0x64, 0x66, 0x0au8,
147     ];
148 
149     let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
150     vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, helpers::bpf_trace_printf)
151         .unwrap();
152 
153     let res = vm.execute_program(packet).unwrap();
154     println!("Program returned: {res:?} ({res:#x})");
155     assert_eq!(res, 0xffffffff);
156 }
157 
158 #[test]
159 #[cfg(all(not(windows), feature = "std"))]
160 fn test_jit_block_port() {
161     // To load the bytecode from an object file instead of using the hardcoded instructions,
162     // use the additional crates commented at the beginning of this file (and also add them to your
163     // Cargo.toml). See comments above.
164     //
165     // ---
166     // let filename = "my_ebpf_object_file.o";
167     //
168     // let path = PathBuf::from(filename);
169     // let file = match elf::File::open_path(&path) {
170     //     Ok(f) => f,
171     //     Err(e) => panic!("Error: {:?}", e),
172     // };
173     //
174     // let text_scn = match file.get_section(".classifier") {
175     //     Some(s) => s,
176     //     None => panic!("Failed to look up .classifier section"),
177     // };
178     //
179     // let prog = &text_scn.data;
180     // ---
181 
182     let prog = &[
183         0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x12, 0x50, 0x00, 0x00, 0x00, 0x00,
184         0x00, // 0x79 instead of 0x61
185         0x79, 0x11, 0x40, 0x00, 0x00, 0x00, 0x00,
186         0x00, // 0x79 instead of 0x61, 0x40 i.o. 0x4c
187         0xbf, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00, 0x36, 0x00, 0x00,
188         0x00, 0x2d, 0x23, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x12, 0x0c, 0x00, 0x00, 0x00,
189         0x00, 0x00, 0x55, 0x02, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, 0x71, 0x12, 0x17, 0x00, 0x00,
190         0x00, 0x00, 0x00, 0x55, 0x02, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
191         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x11, 0x22,
192         0x00, 0x00, 0x00, 0x00, 0x00, // 0x79 instead of 0x61
193         0xbf, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x02, 0x00, 0x00, 0xff, 0xff, 0x00,
194         0x00, 0x15, 0x02, 0x08, 0x00, 0x99, 0x99, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00, 0x00, 0x00,
195         0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x21, 0x00, 0x00, 0x00,
196         0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x18, 0x02, 0x00, 0x00,
197         0x00, 0x00, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x21, 0x01,
198         0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00,
199         0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
200     ];
201 
202     let packet = &mut [
203         0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x08,
204         0x00, // ethertype
205         0x45, 0x00, 0x00, 0x3b, // start ip_hdr
206         0xa6, 0xab, 0x40, 0x00, 0x40, 0x06, 0x96, 0x0f, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00,
207         0x01,
208         // Program matches the next two bytes: 0x9999 returns 0xffffffff, else return 0.
209         0x99, 0x99, 0xc6, 0xcc, // start tcp_hdr
210         0xd1, 0xe5, 0xc4, 0x9d, 0xd4, 0x30, 0xb5, 0xd2, 0x80, 0x18, 0x01, 0x56, 0xfe, 0x2f, 0x00,
211         0x00, 0x01, 0x01, 0x08, 0x0a, // start data
212         0x00, 0x23, 0x75, 0x89, 0x00, 0x23, 0x63, 0x2d, 0x71, 0x64, 0x66, 0x73, 0x64, 0x66, 0x0au8,
213     ];
214 
215     let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
216     vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, helpers::bpf_trace_printf)
217         .unwrap();
218     vm.jit_compile().unwrap();
219 
220     unsafe {
221         let res = vm.execute_program_jit(packet).unwrap();
222         println!("Program returned: {res:?} ({res:#x})");
223         assert_eq!(res, 0xffffffff);
224     }
225 }
226 
227 // Program and memory come from uBPF test ldxh.
228 #[test]
229 fn test_vm_mbuff() {
230     let prog = &[
231         // Load mem from mbuff into R1
232         0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
233         0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
234         0x00,
235     ];
236     let mem = &[0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd];
237 
238     let mbuff = [0u8; 32];
239     unsafe {
240         let mut data = mbuff.as_ptr().offset(8) as *mut u64;
241         let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
242         data.write_unaligned(mem.as_ptr() as u64);
243         data_end.write_unaligned(mem.as_ptr() as u64 + mem.len() as u64);
244     }
245 
246     let vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
247     assert_eq!(vm.execute_program(mem, &mbuff).unwrap(), 0x2211);
248 }
249 
250 // Program and memory come from uBPF test ldxh.
251 #[test]
252 fn test_vm_mbuff_with_rust_api() {
253     use rbpf::insn_builder::*;
254 
255     let mut program = BpfCode::new();
256     program
257         .load_x(MemSize::DoubleWord)
258         .set_dst(0x01)
259         .set_src(0x01)
260         .set_off(0x00_08)
261         .push()
262         .load_x(MemSize::HalfWord)
263         .set_dst(0x00)
264         .set_src(0x01)
265         .set_off(0x00_02)
266         .push()
267         .exit()
268         .push();
269 
270     let mem = &[0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd];
271 
272     let mbuff = [0u8; 32];
273     unsafe {
274         let mut data = mbuff.as_ptr().offset(8) as *mut u64;
275         let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
276         *data = mem.as_ptr() as u64;
277         *data_end = mem.as_ptr() as u64 + mem.len() as u64;
278     }
279 
280     let vm = rbpf::EbpfVmMbuff::new(Some(program.into_bytes())).unwrap();
281     assert_eq!(vm.execute_program(mem, &mbuff).unwrap(), 0x2211);
282 }
283 
284 // Program and memory come from uBPF test ldxh.
285 #[test]
286 #[cfg(all(not(windows), feature = "std"))]
287 fn test_jit_mbuff() {
288     let prog = &[
289         // Load mem from mbuff into R1
290         0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
291         0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292         0x00,
293     ];
294     let mem = &mut [0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd];
295 
296     let mut mbuff = [0u8; 32];
297     unsafe {
298         let mut data = mbuff.as_ptr().offset(8) as *mut u64;
299         let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
300         *data = mem.as_ptr() as u64;
301         *data_end = mem.as_ptr() as u64 + mem.len() as u64;
302     }
303 
304     unsafe {
305         let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
306         vm.jit_compile().unwrap();
307         assert_eq!(vm.execute_program_jit(mem, &mut mbuff).unwrap(), 0x2211);
308     }
309 }
310 
311 #[cfg(all(not(windows), feature = "std"))]
312 #[test]
313 fn test_vm_jit_ldabsb() {
314     let prog = &[
315         0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316         0x00,
317     ];
318     let mem = &mut [
319         0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
320         0xff,
321     ];
322     let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
323     assert_eq!(vm.execute_program(mem).unwrap(), 0x33);
324 
325     vm.jit_compile().unwrap();
326     unsafe {
327         assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x33);
328     };
329 }
330 
331 #[cfg(all(not(windows), feature = "std"))]
332 #[test]
333 fn test_vm_jit_ldabsh() {
334     let prog = &[
335         0x28, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
336         0x00,
337     ];
338     let mem = &mut [
339         0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
340         0xff,
341     ];
342     let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
343     assert_eq!(vm.execute_program(mem).unwrap(), 0x4433);
344 
345     vm.jit_compile().unwrap();
346     unsafe {
347         assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x4433);
348     };
349 }
350 
351 #[cfg(all(not(windows), feature = "std"))]
352 #[test]
353 fn test_vm_jit_ldabsw() {
354     let prog = &[
355         0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
356         0x00,
357     ];
358     let mem = &mut [
359         0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
360         0xff,
361     ];
362     let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
363     assert_eq!(vm.execute_program(mem).unwrap(), 0x66554433);
364     vm.jit_compile().unwrap();
365 
366     unsafe {
367         assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x66554433);
368     };
369 }
370 
371 #[cfg(all(not(windows), feature = "std"))]
372 #[test]
373 fn test_vm_jit_ldabsdw() {
374     let prog = &[
375         0x38, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
376         0x00,
377     ];
378     let mem = &mut [
379         0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
380         0xff,
381     ];
382     let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
383     assert_eq!(vm.execute_program(mem).unwrap(), 0xaa99887766554433);
384     vm.jit_compile().unwrap();
385 
386     unsafe {
387         assert_eq!(vm.execute_program_jit(mem).unwrap(), 0xaa99887766554433);
388     };
389 }
390 
391 #[test]
392 #[should_panic(expected = "Error: out of bounds memory load (insn #1),")]
393 fn test_vm_err_ldabsb_oob() {
394     let prog = &[
395         0x38, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
396         0x00,
397     ];
398     let mem = &mut [
399         0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
400         0xff,
401     ];
402     let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
403     vm.execute_program(mem).unwrap();
404 
405     // Memory check not implemented for JIT yet.
406 }
407 
408 #[test]
409 #[should_panic(expected = "Error: out of bounds memory load (insn #1),")]
410 fn test_vm_err_ldabsb_nomem() {
411     let prog = &[
412         0x38, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
413         0x00,
414     ];
415     let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
416     vm.execute_program().unwrap();
417 
418     // Memory check not implemented for JIT yet.
419 }
420 
421 #[cfg(all(not(windows), feature = "std"))]
422 #[test]
423 fn test_vm_jit_ldindb() {
424     let prog = &[
425         0xb7, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x50, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00,
426         0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
427     ];
428     let mem = &mut [
429         0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
430         0xff,
431     ];
432     let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
433     assert_eq!(vm.execute_program(mem).unwrap(), 0x88);
434 
435     vm.jit_compile().unwrap();
436     unsafe {
437         assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x88);
438     };
439 }
440 
441 #[cfg(all(not(windows), feature = "std"))]
442 #[test]
443 fn test_vm_jit_ldindh() {
444     let prog = &[
445         0xb7, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00,
446         0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
447     ];
448     let mem = &mut [
449         0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
450         0xff,
451     ];
452     let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
453     assert_eq!(vm.execute_program(mem).unwrap(), 0x9988);
454 
455     vm.jit_compile().unwrap();
456     unsafe {
457         assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x9988);
458     };
459 }
460 
461 #[cfg(all(not(windows), feature = "std"))]
462 #[test]
463 fn test_vm_jit_ldindw() {
464     let prog = &[
465         0xb7, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00,
466         0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
467     ];
468     let mem = &mut [
469         0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
470         0xff,
471     ];
472     let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
473     assert_eq!(vm.execute_program(mem).unwrap(), 0x88776655);
474     vm.jit_compile().unwrap();
475 
476     unsafe {
477         assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x88776655);
478     };
479 }
480 
481 #[cfg(all(not(windows), feature = "std"))]
482 #[test]
483 fn test_vm_jit_ldinddw() {
484     let prog = &[
485         0xb7, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x58, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00,
486         0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
487     ];
488     let mem = &mut [
489         0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
490         0xff,
491     ];
492     let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
493     assert_eq!(vm.execute_program(mem).unwrap(), 0xccbbaa9988776655);
494     vm.jit_compile().unwrap();
495 
496     unsafe {
497         assert_eq!(vm.execute_program_jit(mem).unwrap(), 0xccbbaa9988776655);
498     };
499 }
500 
501 #[test]
502 #[should_panic(expected = "Error: out of bounds memory load (insn #2),")]
503 fn test_vm_err_ldindb_oob() {
504     let prog = &[
505         0xb7, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x38, 0x10, 0x00, 0x00, 0x33, 0x00, 0x00,
506         0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
507     ];
508     let mem = &mut [
509         0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
510         0xff,
511     ];
512     let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
513     vm.execute_program(mem).unwrap();
514 
515     // Memory check not implemented for JIT yet.
516 }
517 
518 #[test]
519 #[should_panic(expected = "Error: out of bounds memory load (insn #2),")]
520 fn test_vm_err_ldindb_nomem() {
521     let prog = &[
522         0xb7, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x38, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00,
523         0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
524     ];
525     let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
526     vm.execute_program().unwrap();
527 
528     // Memory check not implemented for JIT yet.
529 }
530 
531 #[test]
532 #[should_panic(expected = "Error: No program set, call prog_set() to load one")]
533 fn test_vm_exec_no_program() {
534     let vm = rbpf::EbpfVmNoData::new(None).unwrap();
535     assert_eq!(vm.execute_program().unwrap(), 0xBEE);
536 }
537 
538 fn verifier_success(_prog: &[u8]) -> Result<(), Error> {
539     Ok(())
540 }
541 
542 fn verifier_fail(_prog: &[u8]) -> Result<(), Error> {
543     Err(Error::new(ErrorKind::Other, "Gaggablaghblagh!"))
544 }
545 
546 #[test]
547 fn test_verifier_success() {
548     let prog = assemble(
549         "mov32 r0, 0xBEE
550          exit",
551     )
552     .unwrap();
553     let mut vm = rbpf::EbpfVmNoData::new(None).unwrap();
554     vm.set_verifier(verifier_success).unwrap();
555     vm.set_program(&prog).unwrap();
556     assert_eq!(vm.execute_program().unwrap(), 0xBEE);
557 }
558 
559 #[test]
560 #[should_panic(expected = "Gaggablaghblagh!")]
561 fn test_verifier_fail() {
562     let prog = assemble(
563         "mov32 r0, 0xBEE
564          exit",
565     )
566     .unwrap();
567     let mut vm = rbpf::EbpfVmNoData::new(None).unwrap();
568     vm.set_verifier(verifier_fail).unwrap();
569     vm.set_program(&prog).unwrap();
570     assert_eq!(vm.execute_program().unwrap(), 0xBEE);
571 }
572