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")]
test_vm_block_port()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"))]
test_jit_block_port()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]
test_vm_mbuff()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]
test_vm_mbuff_with_rust_api()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"))]
test_jit_mbuff()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]
test_vm_jit_ldabsb()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]
test_vm_jit_ldabsh()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]
test_vm_jit_ldabsw()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]
test_vm_jit_ldabsdw()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),")]
test_vm_err_ldabsb_oob()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),")]
test_vm_err_ldabsb_nomem()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]
test_vm_jit_ldindb()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]
test_vm_jit_ldindh()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]
test_vm_jit_ldindw()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]
test_vm_jit_ldinddw()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),")]
test_vm_err_ldindb_oob()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),")]
test_vm_err_ldindb_nomem()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")]
test_vm_exec_no_program()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
verifier_success(_prog: &[u8]) -> Result<(), Error>538 fn verifier_success(_prog: &[u8]) -> Result<(), Error> {
539 Ok(())
540 }
541
verifier_fail(_prog: &[u8]) -> Result<(), Error>542 fn verifier_fail(_prog: &[u8]) -> Result<(), Error> {
543 Err(Error::new(ErrorKind::Other, "Gaggablaghblagh!"))
544 }
545
546 #[test]
test_verifier_success()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!")]
test_verifier_fail()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