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