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