4
0

lib.rs 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443
  1. // Derived from uBPF <https://github.com/iovisor/ubpf>
  2. // Copyright 2015 Big Switch Networks, Inc
  3. // (uBPF: VM architecture, parts of the interpreter, originally in C)
  4. // Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
  5. // (Translation to Rust, MetaBuff/multiple classes addition, hashmaps for helpers)
  6. //
  7. // Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
  8. // the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
  9. // copied, modified, or distributed except according to those terms.
  10. //! Virtual machine and JIT compiler for eBPF programs.
  11. #![doc(html_logo_url = "https://raw.githubusercontent.com/qmonnet/rbpf/master/misc/rbpf.png",
  12. html_favicon_url = "https://raw.githubusercontent.com/qmonnet/rbpf/master/misc/rbpf.ico")]
  13. #![warn(missing_docs)]
  14. #![cfg_attr(feature = "cargo-clippy", allow(doc_markdown, match_same_arms))]
  15. use std::u32;
  16. use std::collections::HashMap;
  17. extern crate libc;
  18. extern crate combine;
  19. extern crate time;
  20. pub mod assembler;
  21. pub mod disassembler;
  22. pub mod ebpf;
  23. pub mod helpers;
  24. pub mod insn_builder;
  25. mod asm_parser;
  26. mod jit;
  27. mod verifier;
  28. // A metadata buffer with two offset indications. It can be used in one kind of eBPF VM to simulate
  29. // the use of a metadata buffer each time the program is executed, without the user having to
  30. // actually handle it. The offsets are used to tell the VM where in the buffer the pointers to
  31. // packet data start and end should be stored each time the program is run on a new packet.
  32. struct MetaBuff {
  33. data_offset: usize,
  34. data_end_offset: usize,
  35. buffer: Vec<u8>,
  36. }
  37. /// A virtual machine to run eBPF program. This kind of VM is used for programs expecting to work
  38. /// on a metadata buffer containing pointers to packet data.
  39. ///
  40. /// # Examples
  41. ///
  42. /// ```
  43. /// let prog = &[
  44. /// 0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff at offset 8 into R1.
  45. /// 0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
  46. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  47. /// ];
  48. /// let mem = &mut [
  49. /// 0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
  50. /// ];
  51. ///
  52. /// // Just for the example we create our metadata buffer from scratch, and we store the pointers
  53. /// // to packet data start and end in it.
  54. /// let mut mbuff = [0u8; 32];
  55. /// unsafe {
  56. /// let mut data = mbuff.as_ptr().offset(8) as *mut u64;
  57. /// let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
  58. /// *data = mem.as_ptr() as u64;
  59. /// *data_end = mem.as_ptr() as u64 + mem.len() as u64;
  60. /// }
  61. ///
  62. /// // Instantiate a VM.
  63. /// let mut vm = rbpf::EbpfVmMbuff::new(prog);
  64. ///
  65. /// // Provide both a reference to the packet data, and to the metadata buffer.
  66. /// let res = vm.prog_exec(mem, &mut mbuff);
  67. /// assert_eq!(res, 0x2211);
  68. /// ```
  69. pub struct EbpfVmMbuff<'a> {
  70. prog: &'a [u8],
  71. jit: (unsafe fn (*mut u8, usize, *mut u8, usize, usize, usize) -> u64),
  72. helpers: HashMap<u32, ebpf::Helper>,
  73. }
  74. impl<'a> EbpfVmMbuff<'a> {
  75. /// Create a new virtual machine instance, and load an eBPF program into that instance.
  76. /// When attempting to load the program, it passes through a simple verifier.
  77. ///
  78. /// # Panics
  79. ///
  80. /// The simple verifier may panic if it finds errors in the eBPF program at load time.
  81. ///
  82. /// # Examples
  83. ///
  84. /// ```
  85. /// let prog = &[
  86. /// 0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into R1.
  87. /// 0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
  88. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  89. /// ];
  90. ///
  91. /// // Instantiate a VM.
  92. /// let mut vm = rbpf::EbpfVmMbuff::new(prog);
  93. /// ```
  94. pub fn new(prog: &'a [u8]) -> EbpfVmMbuff<'a> {
  95. verifier::check(prog);
  96. fn no_jit(_mbuff: *mut u8, _len: usize, _mem: *mut u8, _mem_len: usize,
  97. _nodata_offset: usize, _nodata_end_offset: usize) -> u64 {
  98. panic!("Error: program has not been JIT-compiled");
  99. }
  100. EbpfVmMbuff {
  101. prog: prog,
  102. jit: no_jit,
  103. helpers: HashMap::new(),
  104. }
  105. }
  106. /// Load a new eBPF program into the virtual machine instance.
  107. ///
  108. /// # Panics
  109. ///
  110. /// The simple verifier may panic if it finds errors in the eBPF program at load time.
  111. ///
  112. /// # Examples
  113. ///
  114. /// ```
  115. /// let prog1 = &[
  116. /// 0xb7, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
  117. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  118. /// ];
  119. /// let prog2 = &[
  120. /// 0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into R1.
  121. /// 0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
  122. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  123. /// ];
  124. ///
  125. /// // Instantiate a VM.
  126. /// let mut vm = rbpf::EbpfVmMbuff::new(prog1);
  127. /// vm.set_prog(prog2);
  128. /// ```
  129. pub fn set_prog(&mut self, prog: &'a [u8]) {
  130. verifier::check(prog);
  131. self.prog = prog;
  132. }
  133. /// Register a built-in or user-defined helper function in order to use it later from within
  134. /// the eBPF program. The helper is registered into a hashmap, so the `key` can be any `u32`.
  135. ///
  136. /// If using JIT-compiled eBPF programs, be sure to register all helpers before compiling the
  137. /// program. You should be able to change registered helpers after compiling, but not to add
  138. /// new ones (i.e. with new keys).
  139. ///
  140. /// # Examples
  141. ///
  142. /// ```
  143. /// use rbpf::helpers;
  144. ///
  145. /// // This program was compiled with clang, from a C program containing the following single
  146. /// // instruction: `return bpf_trace_printk("foo %c %c %c\n", 10, 1, 2, 3);`
  147. /// let prog = &[
  148. /// 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load 0 as u64 into r1 (That would be
  149. /// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // replaced by tc by the address of
  150. /// // the format string, in the .map
  151. /// // section of the ELF file).
  152. /// 0xb7, 0x02, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, // mov r2, 10
  153. /// 0xb7, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // mov r3, 1
  154. /// 0xb7, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // mov r4, 2
  155. /// 0xb7, 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // mov r5, 3
  156. /// 0x85, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, // call helper with key 6
  157. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  158. /// ];
  159. ///
  160. /// // Instantiate a VM.
  161. /// let mut vm = rbpf::EbpfVmMbuff::new(prog);
  162. ///
  163. /// // Register a helper.
  164. /// // On running the program this helper will print the content of registers r3, r4 and r5 to
  165. /// // standard output.
  166. /// vm.register_helper(6, helpers::bpf_trace_printf);
  167. /// ```
  168. pub fn register_helper(&mut self, key: u32, function: fn (u64, u64, u64, u64, u64) -> u64) {
  169. self.helpers.insert(key, function);
  170. }
  171. /// Execute the program loaded, with the given packet data and metadata buffer.
  172. ///
  173. /// If the program is made to be compatible with Linux kernel, it is expected to load the
  174. /// address of the beginning and of the end of the memory area used for packet data from the
  175. /// metadata buffer, at some appointed offsets. It is up to the user to ensure that these
  176. /// pointers are correctly stored in the buffer.
  177. ///
  178. /// # Panics
  179. ///
  180. /// This function is currently expected to panic if it encounters any error during the program
  181. /// execution, such as out of bounds accesses or division by zero attempts. This may be changed
  182. /// in the future (we could raise errors instead).
  183. ///
  184. /// # Examples
  185. ///
  186. /// ```
  187. /// let prog = &[
  188. /// 0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into R1.
  189. /// 0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
  190. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  191. /// ];
  192. /// let mem = &mut [
  193. /// 0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
  194. /// ];
  195. ///
  196. /// // Just for the example we create our metadata buffer from scratch, and we store the
  197. /// // pointers to packet data start and end in it.
  198. /// let mut mbuff = [0u8; 32];
  199. /// unsafe {
  200. /// let mut data = mbuff.as_ptr().offset(8) as *mut u64;
  201. /// let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
  202. /// *data = mem.as_ptr() as u64;
  203. /// *data_end = mem.as_ptr() as u64 + mem.len() as u64;
  204. /// }
  205. ///
  206. /// // Instantiate a VM.
  207. /// let mut vm = rbpf::EbpfVmMbuff::new(prog);
  208. ///
  209. /// // Provide both a reference to the packet data, and to the metadata buffer.
  210. /// let res = vm.prog_exec(mem, &mut mbuff);
  211. /// assert_eq!(res, 0x2211);
  212. /// ```
  213. #[allow(unknown_lints)]
  214. #[allow(cyclomatic_complexity)]
  215. pub fn prog_exec(&self, mem: &[u8], mbuff: &[u8]) -> u64 {
  216. const U32MAX: u64 = u32::MAX as u64;
  217. let stack = vec![0u8;ebpf::STACK_SIZE];
  218. // R1 points to beginning of memory area, R10 to stack
  219. let mut reg: [u64;11] = [
  220. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, stack.as_ptr() as u64 + stack.len() as u64
  221. ];
  222. if mbuff.len() > 0 {
  223. reg[1] = mbuff.as_ptr() as u64;
  224. }
  225. else if mem.len() > 0 {
  226. reg[1] = mem.as_ptr() as u64;
  227. }
  228. let check_mem_load = | addr: u64, len: usize, insn_ptr: usize | {
  229. EbpfVmMbuff::check_mem(addr, len, "load", insn_ptr, mbuff, mem, &stack);
  230. };
  231. let check_mem_store = | addr: u64, len: usize, insn_ptr: usize | {
  232. EbpfVmMbuff::check_mem(addr, len, "store", insn_ptr, mbuff, mem, &stack);
  233. };
  234. // Loop on instructions
  235. let mut insn_ptr:usize = 0;
  236. while insn_ptr * ebpf::INSN_SIZE < self.prog.len() {
  237. let insn = ebpf::get_insn(self.prog, insn_ptr);
  238. insn_ptr += 1;
  239. let _dst = insn.dst as usize;
  240. let _src = insn.src as usize;
  241. match insn.opc {
  242. // BPF_LD class
  243. // LD_ABS_* and LD_IND_* are supposed to load pointer to data from metadata buffer.
  244. // Since this pointer is constant, and since we already know it (mem), do not
  245. // bother re-fetching it, just use mem already.
  246. ebpf::LD_ABS_B => reg[0] = unsafe {
  247. let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u8;
  248. check_mem_load(x as u64, 8, insn_ptr);
  249. *x as u64
  250. },
  251. ebpf::LD_ABS_H => reg[0] = unsafe {
  252. let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u16;
  253. check_mem_load(x as u64, 8, insn_ptr);
  254. *x as u64
  255. },
  256. ebpf::LD_ABS_W => reg[0] = unsafe {
  257. let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u32;
  258. check_mem_load(x as u64, 8, insn_ptr);
  259. *x as u64
  260. },
  261. ebpf::LD_ABS_DW => reg[0] = unsafe {
  262. let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u64;
  263. check_mem_load(x as u64, 8, insn_ptr);
  264. *x as u64
  265. },
  266. ebpf::LD_IND_B => reg[0] = unsafe {
  267. let x = (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u8;
  268. check_mem_load(x as u64, 8, insn_ptr);
  269. *x as u64
  270. },
  271. ebpf::LD_IND_H => reg[0] = unsafe {
  272. let x = (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u16;
  273. check_mem_load(x as u64, 8, insn_ptr);
  274. *x as u64
  275. },
  276. ebpf::LD_IND_W => reg[0] = unsafe {
  277. let x = (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u32;
  278. check_mem_load(x as u64, 8, insn_ptr);
  279. *x as u64
  280. },
  281. ebpf::LD_IND_DW => reg[0] = unsafe {
  282. let x = (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u64;
  283. check_mem_load(x as u64, 8, insn_ptr);
  284. *x as u64
  285. },
  286. ebpf::LD_DW_IMM => {
  287. let next_insn = ebpf::get_insn(self.prog, insn_ptr);
  288. insn_ptr += 1;
  289. reg[_dst] = ((insn.imm as u32) as u64) + ((next_insn.imm as u64) << 32);
  290. },
  291. // BPF_LDX class
  292. ebpf::LD_B_REG => reg[_dst] = unsafe {
  293. let x = (reg[_src] as *const u8).offset(insn.off as isize) as *const u8;
  294. check_mem_load(x as u64, 1, insn_ptr);
  295. *x as u64
  296. },
  297. ebpf::LD_H_REG => reg[_dst] = unsafe {
  298. let x = (reg[_src] as *const u8).offset(insn.off as isize) as *const u16;
  299. check_mem_load(x as u64, 2, insn_ptr);
  300. *x as u64
  301. },
  302. ebpf::LD_W_REG => reg[_dst] = unsafe {
  303. let x = (reg[_src] as *const u8).offset(insn.off as isize) as *const u32;
  304. check_mem_load(x as u64, 4, insn_ptr);
  305. *x as u64
  306. },
  307. ebpf::LD_DW_REG => reg[_dst] = unsafe {
  308. let x = (reg[_src] as *const u8).offset(insn.off as isize) as *const u64;
  309. check_mem_load(x as u64, 8, insn_ptr);
  310. *x as u64
  311. },
  312. // BPF_ST class
  313. ebpf::ST_B_IMM => unsafe {
  314. let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u8;
  315. check_mem_store(x as u64, 1, insn_ptr);
  316. *x = insn.imm as u8;
  317. },
  318. ebpf::ST_H_IMM => unsafe {
  319. let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u16;
  320. check_mem_store(x as u64, 2, insn_ptr);
  321. *x = insn.imm as u16;
  322. },
  323. ebpf::ST_W_IMM => unsafe {
  324. let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u32;
  325. check_mem_store(x as u64, 4, insn_ptr);
  326. *x = insn.imm as u32;
  327. },
  328. ebpf::ST_DW_IMM => unsafe {
  329. let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u64;
  330. check_mem_store(x as u64, 8, insn_ptr);
  331. *x = insn.imm as u64;
  332. },
  333. // BPF_STX class
  334. ebpf::ST_B_REG => unsafe {
  335. let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u8;
  336. check_mem_store(x as u64, 1, insn_ptr);
  337. *x = reg[_src] as u8;
  338. },
  339. ebpf::ST_H_REG => unsafe {
  340. let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u16;
  341. check_mem_store(x as u64, 2, insn_ptr);
  342. *x = reg[_src] as u16;
  343. },
  344. ebpf::ST_W_REG => unsafe {
  345. let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u32;
  346. check_mem_store(x as u64, 4, insn_ptr);
  347. *x = reg[_src] as u32;
  348. },
  349. ebpf::ST_DW_REG => unsafe {
  350. let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u64;
  351. check_mem_store(x as u64, 8, insn_ptr);
  352. *x = reg[_src] as u64;
  353. },
  354. ebpf::ST_W_XADD => unimplemented!(),
  355. ebpf::ST_DW_XADD => unimplemented!(),
  356. // BPF_ALU class
  357. // TODO Check how overflow works in kernel. Should we &= U32MAX all src register value
  358. // before we do the operation?
  359. // Cf ((0x11 << 32) - (0x1 << 32)) as u32 VS ((0x11 << 32) as u32 - (0x1 << 32) as u32
  360. ebpf::ADD32_IMM => reg[_dst] = (reg[_dst] as i32).wrapping_add(insn.imm) as u64, //((reg[_dst] & U32MAX) + insn.imm as u64) & U32MAX,
  361. ebpf::ADD32_REG => reg[_dst] = (reg[_dst] as i32).wrapping_add(reg[_src] as i32) as u64, //((reg[_dst] & U32MAX) + (reg[_src] & U32MAX)) & U32MAX,
  362. ebpf::SUB32_IMM => reg[_dst] = (reg[_dst] as i32).wrapping_sub(insn.imm) as u64,
  363. ebpf::SUB32_REG => reg[_dst] = (reg[_dst] as i32).wrapping_sub(reg[_src] as i32) as u64,
  364. ebpf::MUL32_IMM => reg[_dst] = (reg[_dst] as i32).wrapping_mul(insn.imm) as u64,
  365. ebpf::MUL32_REG => reg[_dst] = (reg[_dst] as i32).wrapping_mul(reg[_src] as i32) as u64,
  366. ebpf::DIV32_IMM => reg[_dst] = (reg[_dst] as u32 / insn.imm as u32) as u64,
  367. ebpf::DIV32_REG => {
  368. if reg[_src] == 0 {
  369. panic!("Error: division by 0");
  370. }
  371. reg[_dst] = (reg[_dst] as u32 / reg[_src] as u32) as u64;
  372. },
  373. ebpf::OR32_IMM => reg[_dst] = (reg[_dst] as u32 | insn.imm as u32) as u64,
  374. ebpf::OR32_REG => reg[_dst] = (reg[_dst] as u32 | reg[_src] as u32) as u64,
  375. ebpf::AND32_IMM => reg[_dst] = (reg[_dst] as u32 & insn.imm as u32) as u64,
  376. ebpf::AND32_REG => reg[_dst] = (reg[_dst] as u32 & reg[_src] as u32) as u64,
  377. ebpf::LSH32_IMM => reg[_dst] = (reg[_dst] as u32).wrapping_shl(insn.imm as u32) as u64,
  378. ebpf::LSH32_REG => reg[_dst] = (reg[_dst] as u32).wrapping_shl(reg[_src] as u32) as u64,
  379. ebpf::RSH32_IMM => reg[_dst] = (reg[_dst] as u32).wrapping_shr(insn.imm as u32) as u64,
  380. ebpf::RSH32_REG => reg[_dst] = (reg[_dst] as u32).wrapping_shr(reg[_src] as u32) as u64,
  381. ebpf::NEG32 => { reg[_dst] = (reg[_dst] as i32).wrapping_neg() as u64; reg[_dst] &= U32MAX; },
  382. ebpf::MOD32_IMM => reg[_dst] = (reg[_dst] as u32 % insn.imm as u32) as u64,
  383. ebpf::MOD32_REG => {
  384. if reg[_src] == 0 {
  385. panic!("Error: division by 0");
  386. }
  387. reg[_dst] = (reg[_dst] as u32 % reg[_src] as u32) as u64;
  388. },
  389. ebpf::XOR32_IMM => reg[_dst] = (reg[_dst] as u32 ^ insn.imm as u32) as u64,
  390. ebpf::XOR32_REG => reg[_dst] = (reg[_dst] as u32 ^ reg[_src] as u32) as u64,
  391. ebpf::MOV32_IMM => reg[_dst] = insn.imm as u64,
  392. ebpf::MOV32_REG => reg[_dst] = (reg[_src] as u32) as u64,
  393. ebpf::ARSH32_IMM => { reg[_dst] = (reg[_dst] as i32).wrapping_shr(insn.imm as u32) as u64; reg[_dst] &= U32MAX; },
  394. ebpf::ARSH32_REG => { reg[_dst] = (reg[_dst] as i32).wrapping_shr(reg[_src] as u32) as u64; reg[_dst] &= U32MAX; },
  395. ebpf::LE => {
  396. reg[_dst] = match insn.imm {
  397. 16 => (reg[_dst] as u16).to_le() as u64,
  398. 32 => (reg[_dst] as u32).to_le() as u64,
  399. 64 => reg[_dst].to_le(),
  400. _ => unreachable!(),
  401. };
  402. },
  403. ebpf::BE => {
  404. reg[_dst] = match insn.imm {
  405. 16 => (reg[_dst] as u16).to_be() as u64,
  406. 32 => (reg[_dst] as u32).to_be() as u64,
  407. 64 => reg[_dst].to_be(),
  408. _ => unreachable!(),
  409. };
  410. },
  411. // BPF_ALU64 class
  412. ebpf::ADD64_IMM => reg[_dst] = reg[_dst].wrapping_add(insn.imm as u64),
  413. ebpf::ADD64_REG => reg[_dst] = reg[_dst].wrapping_add(reg[_src]),
  414. ebpf::SUB64_IMM => reg[_dst] = reg[_dst].wrapping_sub(insn.imm as u64),
  415. ebpf::SUB64_REG => reg[_dst] = reg[_dst].wrapping_sub(reg[_src]),
  416. ebpf::MUL64_IMM => reg[_dst] = reg[_dst].wrapping_mul(insn.imm as u64),
  417. ebpf::MUL64_REG => reg[_dst] = reg[_dst].wrapping_mul(reg[_src]),
  418. ebpf::DIV64_IMM => reg[_dst] /= insn.imm as u64,
  419. ebpf::DIV64_REG => {
  420. if reg[_src] == 0 {
  421. panic!("Error: division by 0");
  422. }
  423. reg[_dst] /= reg[_src];
  424. },
  425. ebpf::OR64_IMM => reg[_dst] |= insn.imm as u64,
  426. ebpf::OR64_REG => reg[_dst] |= reg[_src],
  427. ebpf::AND64_IMM => reg[_dst] &= insn.imm as u64,
  428. ebpf::AND64_REG => reg[_dst] &= reg[_src],
  429. ebpf::LSH64_IMM => reg[_dst] <<= insn.imm as u64,
  430. ebpf::LSH64_REG => reg[_dst] <<= reg[_src],
  431. ebpf::RSH64_IMM => reg[_dst] >>= insn.imm as u64,
  432. ebpf::RSH64_REG => reg[_dst] >>= reg[_src],
  433. ebpf::NEG64 => reg[_dst] = -(reg[_dst] as i64) as u64,
  434. ebpf::MOD64_IMM => reg[_dst] %= insn.imm as u64,
  435. ebpf::MOD64_REG => {
  436. if reg[_src] == 0 {
  437. panic!("Error: division by 0");
  438. }
  439. reg[_dst] %= reg[_src];
  440. },
  441. ebpf::XOR64_IMM => reg[_dst] ^= insn.imm as u64,
  442. ebpf::XOR64_REG => reg[_dst] ^= reg[_src],
  443. ebpf::MOV64_IMM => reg[_dst] = insn.imm as u64,
  444. ebpf::MOV64_REG => reg[_dst] = reg[_src],
  445. ebpf::ARSH64_IMM => reg[_dst] = (reg[_dst] as i64 >> insn.imm) as u64,
  446. ebpf::ARSH64_REG => reg[_dst] = (reg[_dst] as i64 >> reg[_src]) as u64,
  447. // BPF_JMP class
  448. // TODO: check this actually works as expected for signed / unsigned ops
  449. ebpf::JA => insn_ptr = (insn_ptr as i16 + insn.off) as usize,
  450. ebpf::JEQ_IMM => if reg[_dst] == insn.imm as u64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
  451. ebpf::JEQ_REG => if reg[_dst] == reg[_src] { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
  452. ebpf::JGT_IMM => if reg[_dst] > insn.imm as u64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
  453. ebpf::JGT_REG => if reg[_dst] > reg[_src] { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
  454. ebpf::JGE_IMM => if reg[_dst] >= insn.imm as u64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
  455. ebpf::JGE_REG => if reg[_dst] >= reg[_src] { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
  456. ebpf::JSET_IMM => if reg[_dst] & insn.imm as u64 != 0 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
  457. ebpf::JSET_REG => if reg[_dst] & reg[_src] != 0 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
  458. ebpf::JNE_IMM => if reg[_dst] != insn.imm as u64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
  459. ebpf::JNE_REG => if reg[_dst] != reg[_src] { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
  460. ebpf::JSGT_IMM => if reg[_dst] as i64 > insn.imm as i64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
  461. ebpf::JSGT_REG => if reg[_dst] as i64 > reg[_src] as i64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
  462. ebpf::JSGE_IMM => if reg[_dst] as i64 >= insn.imm as i64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
  463. ebpf::JSGE_REG => if reg[_dst] as i64 >= reg[_src] as i64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
  464. // Do not delegate the check to the verifier, since registered functions can be
  465. // changed after the program has been verified.
  466. ebpf::CALL => if let Some(function) = self.helpers.get(&(insn.imm as u32)) {
  467. reg[0] = function(reg[1], reg[2], reg[3], reg[4], reg[5]);
  468. } else {
  469. panic!("Error: unknown helper function (id: {:#x})", insn.imm as u32);
  470. },
  471. ebpf::TAIL_CALL => unimplemented!(),
  472. ebpf::EXIT => return reg[0],
  473. _ => unreachable!()
  474. }
  475. }
  476. unreachable!()
  477. }
  478. fn check_mem(addr: u64, len: usize, access_type: &str, insn_ptr: usize,
  479. mbuff: &[u8], mem: &[u8], stack: &[u8]) {
  480. if mbuff.as_ptr() as u64 <= addr && addr + len as u64 <= mbuff.as_ptr() as u64 + mbuff.len() as u64 {
  481. return
  482. }
  483. if mem.as_ptr() as u64 <= addr && addr + len as u64 <= mem.as_ptr() as u64 + mem.len() as u64 {
  484. return
  485. }
  486. if stack.as_ptr() as u64 <= addr && addr + len as u64 <= stack.as_ptr() as u64 + stack.len() as u64 {
  487. return
  488. }
  489. panic!(
  490. "Error: out of bounds memory {} (insn #{:?}), addr {:#x}, size {:?}\nmbuff: {:#x}/{:#x}, mem: {:#x}/{:#x}, stack: {:#x}/{:#x}",
  491. access_type, insn_ptr, addr, len,
  492. mbuff.as_ptr() as u64, mbuff.len(),
  493. mem.as_ptr() as u64, mem.len(),
  494. stack.as_ptr() as u64, stack.len()
  495. );
  496. }
  497. /// JIT-compile the loaded program. No argument required for this.
  498. ///
  499. /// If using helper functions, be sure to register them into the VM before calling this
  500. /// function.
  501. ///
  502. /// # Panics
  503. ///
  504. /// This function panics if an error occurs during JIT-compiling, such as the occurrence of an
  505. /// unknown eBPF operation code.
  506. ///
  507. /// # Examples
  508. ///
  509. /// ```
  510. /// let prog = &[
  511. /// 0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into R1.
  512. /// 0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
  513. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  514. /// ];
  515. ///
  516. /// // Instantiate a VM.
  517. /// let mut vm = rbpf::EbpfVmMbuff::new(prog);
  518. ///
  519. /// vm.jit_compile();
  520. /// ```
  521. pub fn jit_compile(&mut self) {
  522. self.jit = jit::compile(self.prog, &self.helpers, true, false);
  523. }
  524. /// Execute the previously JIT-compiled program, with the given packet data and metadata
  525. /// buffer, in a manner very similar to `prog_exec()`.
  526. ///
  527. /// If the program is made to be compatible with Linux kernel, it is expected to load the
  528. /// address of the beginning and of the end of the memory area used for packet data from the
  529. /// metadata buffer, at some appointed offsets. It is up to the user to ensure that these
  530. /// pointers are correctly stored in the buffer.
  531. ///
  532. /// # Panics
  533. ///
  534. /// This function panics if an error occurs during the execution of the program.
  535. ///
  536. /// # Safety
  537. ///
  538. /// **WARNING:** JIT-compiled assembly code is not safe, in particular there is no runtime
  539. /// check for memory access; so if the eBPF program attempts erroneous accesses, this may end
  540. /// very bad (program may segfault). It may be wise to check that the program works with the
  541. /// interpreter before running the JIT-compiled version of it.
  542. ///
  543. /// For this reason the function should be called from within an `unsafe` bloc.
  544. ///
  545. /// # Examples
  546. ///
  547. /// ```
  548. /// let prog = &[
  549. /// 0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into r1.
  550. /// 0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
  551. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  552. /// ];
  553. /// let mem = &mut [
  554. /// 0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
  555. /// ];
  556. ///
  557. /// // Just for the example we create our metadata buffer from scratch, and we store the
  558. /// // pointers to packet data start and end in it.
  559. /// let mut mbuff = [0u8; 32];
  560. /// unsafe {
  561. /// let mut data = mbuff.as_ptr().offset(8) as *mut u64;
  562. /// let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
  563. /// *data = mem.as_ptr() as u64;
  564. /// *data_end = mem.as_ptr() as u64 + mem.len() as u64;
  565. /// }
  566. ///
  567. /// // Instantiate a VM.
  568. /// let mut vm = rbpf::EbpfVmMbuff::new(prog);
  569. ///
  570. /// vm.jit_compile();
  571. ///
  572. /// // Provide both a reference to the packet data, and to the metadata buffer.
  573. /// unsafe {
  574. /// let res = vm.prog_exec_jit(mem, &mut mbuff);
  575. /// assert_eq!(res, 0x2211);
  576. /// }
  577. /// ```
  578. pub unsafe fn prog_exec_jit(&self, mem: &mut [u8], mbuff: &'a mut [u8]) -> u64 {
  579. // If packet data is empty, do not send the address of an empty slice; send a null pointer
  580. // as first argument instead, as this is uBPF's behavior (empty packet should not happen
  581. // in the kernel; anyway the verifier would prevent the use of uninitialized registers).
  582. // See `mul_loop` test.
  583. let mem_ptr = match mem.len() {
  584. 0 => std::ptr::null_mut(),
  585. _ => mem.as_ptr() as *mut u8
  586. };
  587. // The last two arguments are not used in this function. They would be used if there was a
  588. // need to indicate to the JIT at which offset in the mbuff mem_ptr and mem_ptr + mem.len()
  589. // should be stored; this is what happens with struct EbpfVmFixedMbuff.
  590. (self.jit)(mbuff.as_ptr() as *mut u8, mbuff.len(), mem_ptr, mem.len(), 0, 0)
  591. }
  592. }
  593. /// A virtual machine to run eBPF program. This kind of VM is used for programs expecting to work
  594. /// on a metadata buffer containing pointers to packet data, but it internally handles the buffer
  595. /// so as to save the effort to manually handle the metadata buffer for the user.
  596. ///
  597. /// This struct implements a static internal buffer that is passed to the program. The user has to
  598. /// indicate the offset values at which the eBPF program expects to find the start and the end of
  599. /// packet data in the buffer. On calling the `prog_exec()` or `prog_exec_jit()` functions, the
  600. /// struct automatically updates the addresses in this static buffer, at the appointed offsets, for
  601. /// the start and the end of the packet data the program is called upon.
  602. ///
  603. /// # Examples
  604. ///
  605. /// This was compiled with clang from the following program, in C:
  606. ///
  607. /// ```c
  608. /// #include <linux/bpf.h>
  609. /// #include "path/to/linux/samples/bpf/bpf_helpers.h"
  610. ///
  611. /// SEC(".classifier")
  612. /// int classifier(struct __sk_buff *skb)
  613. /// {
  614. /// void *data = (void *)(long)skb->data;
  615. /// void *data_end = (void *)(long)skb->data_end;
  616. ///
  617. /// // Check program is long enough.
  618. /// if (data + 5 > data_end)
  619. /// return 0;
  620. ///
  621. /// return *((char *)data + 5);
  622. /// }
  623. /// ```
  624. ///
  625. /// Some small modifications have been brought to have it work, see comments.
  626. ///
  627. /// ```
  628. /// let prog = &[
  629. /// 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
  630. /// // Here opcode 0x61 had to be replace by 0x79 so as to load a 8-bytes long address.
  631. /// // Also, offset 0x4c had to be replace with e.g. 0x40 so as to prevent the two pointers
  632. /// // from overlapping in the buffer.
  633. /// 0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load pointer to mem from r1[0x40] to r2
  634. /// 0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
  635. /// // Here opcode 0x61 had to be replace by 0x79 so as to load a 8-bytes long address.
  636. /// 0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load ptr to mem_end from r1[0x50] to r1
  637. /// 0x2d, 0x12, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
  638. /// 0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
  639. /// 0x67, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, // r0 >>= 56
  640. /// 0xc7, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, // r0 <<= 56 (arsh) extend byte sign to u64
  641. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  642. /// ];
  643. /// let mem1 = &mut [
  644. /// 0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
  645. /// ];
  646. /// let mem2 = &mut [
  647. /// 0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x27
  648. /// ];
  649. ///
  650. /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
  651. /// let mut vm = rbpf::EbpfVmFixedMbuff::new(prog, 0x40, 0x50);
  652. ///
  653. /// // Provide only a reference to the packet data. We do not manage the metadata buffer.
  654. /// let res = vm.prog_exec(mem1);
  655. /// assert_eq!(res, 0xffffffffffffffdd);
  656. ///
  657. /// let res = vm.prog_exec(mem2);
  658. /// assert_eq!(res, 0x27);
  659. /// ```
  660. pub struct EbpfVmFixedMbuff<'a> {
  661. parent: EbpfVmMbuff<'a>,
  662. mbuff: MetaBuff,
  663. }
  664. impl<'a> EbpfVmFixedMbuff<'a> {
  665. /// Create a new virtual machine instance, and load an eBPF program into that instance.
  666. /// When attempting to load the program, it passes through a simple verifier.
  667. ///
  668. /// # Panics
  669. ///
  670. /// The simple verifier may panic if it finds errors in the eBPF program at load time.
  671. ///
  672. /// # Examples
  673. ///
  674. /// ```
  675. /// let prog = &[
  676. /// 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
  677. /// 0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
  678. /// 0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
  679. /// 0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
  680. /// 0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
  681. /// 0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
  682. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  683. /// ];
  684. ///
  685. /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
  686. /// let mut vm = rbpf::EbpfVmFixedMbuff::new(prog, 0x40, 0x50);
  687. /// ```
  688. pub fn new(prog: &'a [u8], data_offset: usize, data_end_offset: usize) -> EbpfVmFixedMbuff<'a> {
  689. let parent = EbpfVmMbuff::new(prog);
  690. let get_buff_len = | x: usize, y: usize | if x >= y { x + 8 } else { y + 8 };
  691. let buffer = vec![0u8; get_buff_len(data_offset, data_end_offset)];
  692. let mbuff = MetaBuff {
  693. data_offset: data_offset,
  694. data_end_offset: data_end_offset,
  695. buffer: buffer,
  696. };
  697. EbpfVmFixedMbuff {
  698. parent: parent,
  699. mbuff: mbuff,
  700. }
  701. }
  702. /// Load a new eBPF program into the virtual machine instance.
  703. ///
  704. /// At the same time, load new offsets for storing pointers to start and end of packet data in
  705. /// the internal metadata buffer.
  706. ///
  707. /// # Panics
  708. ///
  709. /// The simple verifier may panic if it finds errors in the eBPF program at load time.
  710. ///
  711. /// # Examples
  712. ///
  713. /// ```
  714. /// let prog1 = &[
  715. /// 0xb7, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
  716. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  717. /// ];
  718. /// let prog2 = &[
  719. /// 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
  720. /// 0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
  721. /// 0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
  722. /// 0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
  723. /// 0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
  724. /// 0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
  725. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  726. /// ];
  727. ///
  728. /// let mem = &mut [
  729. /// 0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x27,
  730. /// ];
  731. ///
  732. /// let mut vm = rbpf::EbpfVmFixedMbuff::new(prog1, 0, 0);
  733. /// vm.set_prog(prog2, 0x40, 0x50);
  734. ///
  735. /// let res = vm.prog_exec(mem);
  736. /// assert_eq!(res, 0x27);
  737. /// ```
  738. pub fn set_prog(&mut self, prog: &'a [u8], data_offset: usize, data_end_offset: usize) {
  739. let get_buff_len = | x: usize, y: usize | if x >= y { x + 8 } else { y + 8 };
  740. let buffer = vec![0u8; get_buff_len(data_offset, data_end_offset)];
  741. self.mbuff.buffer = buffer;
  742. self.mbuff.data_offset = data_offset;
  743. self.mbuff.data_end_offset = data_end_offset;
  744. self.parent.set_prog(prog)
  745. }
  746. /// Register a built-in or user-defined helper function in order to use it later from within
  747. /// the eBPF program. The helper is registered into a hashmap, so the `key` can be any `u32`.
  748. ///
  749. /// If using JIT-compiled eBPF programs, be sure to register all helpers before compiling the
  750. /// program. You should be able to change registered helpers after compiling, but not to add
  751. /// new ones (i.e. with new keys).
  752. ///
  753. /// # Examples
  754. ///
  755. /// ```
  756. /// use rbpf::helpers;
  757. ///
  758. /// // This program was compiled with clang, from a C program containing the following single
  759. /// // instruction: `return bpf_trace_printk("foo %c %c %c\n", 10, 1, 2, 3);`
  760. /// let prog = &[
  761. /// 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
  762. /// 0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
  763. /// 0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
  764. /// 0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
  765. /// 0x2d, 0x12, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 6 instructions
  766. /// 0x71, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r1
  767. /// 0xb7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r2, 0
  768. /// 0xb7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r3, 0
  769. /// 0xb7, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r4, 0
  770. /// 0xb7, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r5, 0
  771. /// 0x85, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // call helper with key 1
  772. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  773. /// ];
  774. ///
  775. /// let mem = &mut [
  776. /// 0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x09,
  777. /// ];
  778. ///
  779. /// // Instantiate a VM.
  780. /// let mut vm = rbpf::EbpfVmFixedMbuff::new(prog, 0x40, 0x50);
  781. ///
  782. /// // Register a helper. This helper will store the result of the square root of r1 into r0.
  783. /// vm.register_helper(1, helpers::sqrti);
  784. ///
  785. /// let res = vm.prog_exec(mem);
  786. /// assert_eq!(res, 3);
  787. /// ```
  788. pub fn register_helper(&mut self, key: u32, function: fn (u64, u64, u64, u64, u64) -> u64) {
  789. self.parent.register_helper(key, function);
  790. }
  791. /// Execute the program loaded, with the given packet data.
  792. ///
  793. /// If the program is made to be compatible with Linux kernel, it is expected to load the
  794. /// address of the beginning and of the end of the memory area used for packet data from some
  795. /// metadata buffer, which in the case of this VM is handled internally. The offsets at which
  796. /// the addresses should be placed should have be set at the creation of the VM.
  797. ///
  798. /// # Panics
  799. ///
  800. /// This function is currently expected to panic if it encounters any error during the program
  801. /// execution, such as out of bounds accesses or division by zero attempts. This may be changed
  802. /// in the future (we could raise errors instead).
  803. ///
  804. /// # Examples
  805. ///
  806. /// ```
  807. /// let prog = &[
  808. /// 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
  809. /// 0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
  810. /// 0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
  811. /// 0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
  812. /// 0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
  813. /// 0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
  814. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  815. /// ];
  816. /// let mem = &mut [
  817. /// 0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
  818. /// ];
  819. ///
  820. /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
  821. /// let mut vm = rbpf::EbpfVmFixedMbuff::new(prog, 0x40, 0x50);
  822. ///
  823. /// // Provide only a reference to the packet data. We do not manage the metadata buffer.
  824. /// let res = vm.prog_exec(mem);
  825. /// assert_eq!(res, 0xdd);
  826. /// ```
  827. pub fn prog_exec(&mut self, mem: &'a mut [u8]) -> u64 {
  828. let l = self.mbuff.buffer.len();
  829. // Can this ever happen? Probably not, should be ensured at mbuff creation.
  830. if self.mbuff.data_offset + 8 > l || self.mbuff.data_end_offset + 8 > l {
  831. panic!("Error: buffer too small ({:?}), cannot use data_offset {:?} and data_end_offset {:?}",
  832. l, self.mbuff.data_offset, self.mbuff.data_end_offset);
  833. }
  834. unsafe {
  835. let mut data = self.mbuff.buffer.as_ptr().offset(self.mbuff.data_offset as isize) as *mut u64;
  836. let mut data_end = self.mbuff.buffer.as_ptr().offset(self.mbuff.data_end_offset as isize) as *mut u64;
  837. *data = mem.as_ptr() as u64;
  838. *data_end = mem.as_ptr() as u64 + mem.len() as u64;
  839. }
  840. self.parent.prog_exec(mem, &self.mbuff.buffer)
  841. }
  842. /// JIT-compile the loaded program. No argument required for this.
  843. ///
  844. /// If using helper functions, be sure to register them into the VM before calling this
  845. /// function.
  846. ///
  847. /// # Panics
  848. ///
  849. /// This function panics if an error occurs during JIT-compiling, such as the occurrence of an
  850. /// unknown eBPF operation code.
  851. ///
  852. /// # Examples
  853. ///
  854. /// ```
  855. /// let prog = &[
  856. /// 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
  857. /// 0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
  858. /// 0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
  859. /// 0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
  860. /// 0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
  861. /// 0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
  862. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  863. /// ];
  864. ///
  865. /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
  866. /// let mut vm = rbpf::EbpfVmFixedMbuff::new(prog, 0x40, 0x50);
  867. ///
  868. /// vm.jit_compile();
  869. /// ```
  870. pub fn jit_compile(&mut self) {
  871. self.parent.jit = jit::compile(self.parent.prog, &self.parent.helpers, true, true);
  872. }
  873. /// Execute the previously JIT-compiled program, with the given packet data, in a manner very
  874. /// similar to `prog_exec()`.
  875. ///
  876. /// If the program is made to be compatible with Linux kernel, it is expected to load the
  877. /// address of the beginning and of the end of the memory area used for packet data from some
  878. /// metadata buffer, which in the case of this VM is handled internally. The offsets at which
  879. /// the addresses should be placed should have be set at the creation of the VM.
  880. ///
  881. /// # Panics
  882. ///
  883. /// This function panics if an error occurs during the execution of the program.
  884. ///
  885. /// # Safety
  886. ///
  887. /// **WARNING:** JIT-compiled assembly code is not safe, in particular there is no runtime
  888. /// check for memory access; so if the eBPF program attempts erroneous accesses, this may end
  889. /// very bad (program may segfault). It may be wise to check that the program works with the
  890. /// interpreter before running the JIT-compiled version of it.
  891. ///
  892. /// For this reason the function should be called from within an `unsafe` bloc.
  893. ///
  894. /// # Examples
  895. ///
  896. /// ```
  897. /// let prog = &[
  898. /// 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
  899. /// 0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
  900. /// 0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
  901. /// 0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
  902. /// 0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
  903. /// 0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
  904. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  905. /// ];
  906. /// let mem = &mut [
  907. /// 0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
  908. /// ];
  909. ///
  910. /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
  911. /// let mut vm = rbpf::EbpfVmFixedMbuff::new(prog, 0x40, 0x50);
  912. ///
  913. /// vm.jit_compile();
  914. ///
  915. /// // Provide only a reference to the packet data. We do not manage the metadata buffer.
  916. /// unsafe {
  917. /// let res = vm.prog_exec_jit(mem);
  918. /// assert_eq!(res, 0xdd);
  919. /// }
  920. /// ```
  921. // This struct redefines the `prog_exec_jit()` function, in order to pass the offsets
  922. // associated with the fixed mbuff.
  923. pub unsafe fn prog_exec_jit(&mut self, mem: &'a mut [u8]) -> u64 {
  924. // If packet data is empty, do not send the address of an empty slice; send a null pointer
  925. // as first argument instead, as this is uBPF's behavior (empty packet should not happen
  926. // in the kernel; anyway the verifier would prevent the use of uninitialized registers).
  927. // See `mul_loop` test.
  928. let mem_ptr = match mem.len() {
  929. 0 => std::ptr::null_mut(),
  930. _ => mem.as_ptr() as *mut u8
  931. };
  932. (self.parent.jit)(self.mbuff.buffer.as_ptr() as *mut u8, self.mbuff.buffer.len(),
  933. mem_ptr, mem.len(), self.mbuff.data_offset, self.mbuff.data_end_offset)
  934. }
  935. }
  936. /// A virtual machine to run eBPF program. This kind of VM is used for programs expecting to work
  937. /// directly on the memory area representing packet data.
  938. ///
  939. /// # Examples
  940. ///
  941. /// ```
  942. /// let prog = &[
  943. /// 0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
  944. /// 0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
  945. /// 0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
  946. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  947. /// ];
  948. /// let mem = &mut [
  949. /// 0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
  950. /// ];
  951. ///
  952. /// // Instantiate a VM.
  953. /// let vm = rbpf::EbpfVmRaw::new(prog);
  954. ///
  955. /// // Provide only a reference to the packet data.
  956. /// let res = vm.prog_exec(mem);
  957. /// assert_eq!(res, 0x22cc);
  958. /// ```
  959. pub struct EbpfVmRaw<'a> {
  960. parent: EbpfVmMbuff<'a>,
  961. }
  962. impl<'a> EbpfVmRaw<'a> {
  963. /// Create a new virtual machine instance, and load an eBPF program into that instance.
  964. /// When attempting to load the program, it passes through a simple verifier.
  965. ///
  966. /// # Panics
  967. ///
  968. /// The simple verifier may panic if it finds errors in the eBPF program at load time.
  969. ///
  970. /// # Examples
  971. ///
  972. /// ```
  973. /// let prog = &[
  974. /// 0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
  975. /// 0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
  976. /// 0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
  977. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  978. /// ];
  979. ///
  980. /// // Instantiate a VM.
  981. /// let vm = rbpf::EbpfVmRaw::new(prog);
  982. /// ```
  983. pub fn new(prog: &'a [u8]) -> EbpfVmRaw<'a> {
  984. let parent = EbpfVmMbuff::new(prog);
  985. EbpfVmRaw {
  986. parent: parent,
  987. }
  988. }
  989. /// Load a new eBPF program into the virtual machine instance.
  990. ///
  991. /// # Panics
  992. ///
  993. /// The simple verifier may panic if it finds errors in the eBPF program at load time.
  994. ///
  995. /// # Examples
  996. ///
  997. /// ```
  998. /// let prog1 = &[
  999. /// 0xb7, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
  1000. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  1001. /// ];
  1002. /// let prog2 = &[
  1003. /// 0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
  1004. /// 0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
  1005. /// 0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
  1006. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  1007. /// ];
  1008. ///
  1009. /// let mem = &mut [
  1010. /// 0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x27,
  1011. /// ];
  1012. ///
  1013. /// let mut vm = rbpf::EbpfVmRaw::new(prog1);
  1014. /// vm.set_prog(prog2);
  1015. ///
  1016. /// let res = vm.prog_exec(mem);
  1017. /// assert_eq!(res, 0x22cc);
  1018. /// ```
  1019. pub fn set_prog(&mut self, prog: &'a [u8]) {
  1020. self.parent.set_prog(prog)
  1021. }
  1022. /// Register a built-in or user-defined helper function in order to use it later from within
  1023. /// the eBPF program. The helper is registered into a hashmap, so the `key` can be any `u32`.
  1024. ///
  1025. /// If using JIT-compiled eBPF programs, be sure to register all helpers before compiling the
  1026. /// program. You should be able to change registered helpers after compiling, but not to add
  1027. /// new ones (i.e. with new keys).
  1028. ///
  1029. /// # Examples
  1030. ///
  1031. /// ```
  1032. /// use rbpf::helpers;
  1033. ///
  1034. /// let prog = &[
  1035. /// 0x79, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxdw r1, r1[0x00]
  1036. /// 0xb7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r2, 0
  1037. /// 0xb7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r3, 0
  1038. /// 0xb7, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r4, 0
  1039. /// 0xb7, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r5, 0
  1040. /// 0x85, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // call helper with key 1
  1041. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  1042. /// ];
  1043. ///
  1044. /// let mem = &mut [
  1045. /// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
  1046. /// ];
  1047. ///
  1048. /// // Instantiate a VM.
  1049. /// let mut vm = rbpf::EbpfVmRaw::new(prog);
  1050. ///
  1051. /// // Register a helper. This helper will store the result of the square root of r1 into r0.
  1052. /// vm.register_helper(1, helpers::sqrti);
  1053. ///
  1054. /// let res = vm.prog_exec(mem);
  1055. /// assert_eq!(res, 0x10000000);
  1056. /// ```
  1057. pub fn register_helper(&mut self, key: u32, function: fn (u64, u64, u64, u64, u64) -> u64) {
  1058. self.parent.register_helper(key, function);
  1059. }
  1060. /// Execute the program loaded, with the given packet data.
  1061. ///
  1062. /// # Panics
  1063. ///
  1064. /// This function is currently expected to panic if it encounters any error during the program
  1065. /// execution, such as out of bounds accesses or division by zero attempts. This may be changed
  1066. /// in the future (we could raise errors instead).
  1067. ///
  1068. /// # Examples
  1069. ///
  1070. /// ```
  1071. /// let prog = &[
  1072. /// 0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
  1073. /// 0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
  1074. /// 0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
  1075. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  1076. /// ];
  1077. ///
  1078. /// let mem = &mut [
  1079. /// 0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x27
  1080. /// ];
  1081. ///
  1082. /// let mut vm = rbpf::EbpfVmRaw::new(prog);
  1083. ///
  1084. /// let res = vm.prog_exec(mem);
  1085. /// assert_eq!(res, 0x22cc);
  1086. /// ```
  1087. pub fn prog_exec(&self, mem: &'a mut [u8]) -> u64 {
  1088. self.parent.prog_exec(mem, &[])
  1089. }
  1090. /// JIT-compile the loaded program. No argument required for this.
  1091. ///
  1092. /// If using helper functions, be sure to register them into the VM before calling this
  1093. /// function.
  1094. ///
  1095. /// # Panics
  1096. ///
  1097. /// This function panics if an error occurs during JIT-compiling, such as the occurrence of an
  1098. /// unknown eBPF operation code.
  1099. ///
  1100. /// # Examples
  1101. ///
  1102. /// ```
  1103. /// let prog = &[
  1104. /// 0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
  1105. /// 0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
  1106. /// 0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
  1107. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  1108. /// ];
  1109. ///
  1110. /// let mut vm = rbpf::EbpfVmRaw::new(prog);
  1111. ///
  1112. /// vm.jit_compile();
  1113. /// ```
  1114. pub fn jit_compile(&mut self) {
  1115. self.parent.jit = jit::compile(self.parent.prog, &self.parent.helpers, false, false);
  1116. }
  1117. /// Execute the previously JIT-compiled program, with the given packet data, in a manner very
  1118. /// similar to `prog_exec()`.
  1119. ///
  1120. /// # Panics
  1121. ///
  1122. /// This function panics if an error occurs during the execution of the program.
  1123. ///
  1124. /// # Safety
  1125. ///
  1126. /// **WARNING:** JIT-compiled assembly code is not safe, in particular there is no runtime
  1127. /// check for memory access; so if the eBPF program attempts erroneous accesses, this may end
  1128. /// very bad (program may segfault). It may be wise to check that the program works with the
  1129. /// interpreter before running the JIT-compiled version of it.
  1130. ///
  1131. /// For this reason the function should be called from within an `unsafe` bloc.
  1132. ///
  1133. /// # Examples
  1134. ///
  1135. /// ```
  1136. /// let prog = &[
  1137. /// 0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
  1138. /// 0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
  1139. /// 0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
  1140. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  1141. /// ];
  1142. ///
  1143. /// let mem = &mut [
  1144. /// 0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x27
  1145. /// ];
  1146. ///
  1147. /// let mut vm = rbpf::EbpfVmRaw::new(prog);
  1148. ///
  1149. /// vm.jit_compile();
  1150. ///
  1151. /// unsafe {
  1152. /// let res = vm.prog_exec_jit(mem);
  1153. /// assert_eq!(res, 0x22cc);
  1154. /// }
  1155. /// ```
  1156. pub unsafe fn prog_exec_jit(&self, mem: &'a mut [u8]) -> u64 {
  1157. let mut mbuff = vec![];
  1158. self.parent.prog_exec_jit(mem, &mut mbuff)
  1159. }
  1160. }
  1161. /// A virtual machine to run eBPF program. This kind of VM is used for programs that do not work
  1162. /// with any memory area—no metadata buffer, no packet data either.
  1163. ///
  1164. /// # Examples
  1165. ///
  1166. /// ```
  1167. /// let prog = &[
  1168. /// 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
  1169. /// 0xb7, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // mov r1, 1
  1170. /// 0xb7, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // mov r2, 2
  1171. /// 0xb7, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // mov r3, 3
  1172. /// 0xb7, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, // mov r4, 4
  1173. /// 0xb7, 0x05, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // mov r5, 5
  1174. /// 0xb7, 0x06, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, // mov r6, 6
  1175. /// 0xb7, 0x07, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, // mov r7, 7
  1176. /// 0xb7, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, // mov r8, 8
  1177. /// 0x4f, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // or r0, r5
  1178. /// 0x47, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, // or r0, 0xa0
  1179. /// 0x57, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, // and r0, 0xa3
  1180. /// 0xb7, 0x09, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, // mov r9, 0x91
  1181. /// 0x5f, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // and r0, r9
  1182. /// 0x67, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, // lsh r0, 32
  1183. /// 0x67, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, // lsh r0, 22
  1184. /// 0x6f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // lsh r0, r8
  1185. /// 0x77, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, // rsh r0, 32
  1186. /// 0x77, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, // rsh r0, 19
  1187. /// 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // rsh r0, r7
  1188. /// 0xa7, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // xor r0, 0x03
  1189. /// 0xaf, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // xor r0, r2
  1190. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  1191. /// ];
  1192. ///
  1193. /// // Instantiate a VM.
  1194. /// let vm = rbpf::EbpfVmNoData::new(prog);
  1195. ///
  1196. /// // Provide only a reference to the packet data.
  1197. /// let res = vm.prog_exec();
  1198. /// assert_eq!(res, 0x11);
  1199. /// ```
  1200. pub struct EbpfVmNoData<'a> {
  1201. parent: EbpfVmRaw<'a>,
  1202. }
  1203. impl<'a> EbpfVmNoData<'a> {
  1204. /// Create a new virtual machine instance, and load an eBPF program into that instance.
  1205. /// When attempting to load the program, it passes through a simple verifier.
  1206. ///
  1207. /// # Panics
  1208. ///
  1209. /// The simple verifier may panic if it finds errors in the eBPF program at load time.
  1210. ///
  1211. /// # Examples
  1212. ///
  1213. /// ```
  1214. /// let prog = &[
  1215. /// 0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
  1216. /// 0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
  1217. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  1218. /// ];
  1219. ///
  1220. /// // Instantiate a VM.
  1221. /// let vm = rbpf::EbpfVmNoData::new(prog);
  1222. /// ```
  1223. pub fn new(prog: &'a [u8]) -> EbpfVmNoData<'a> {
  1224. let parent = EbpfVmRaw::new(prog);
  1225. EbpfVmNoData {
  1226. parent: parent,
  1227. }
  1228. }
  1229. /// Load a new eBPF program into the virtual machine instance.
  1230. ///
  1231. /// # Panics
  1232. ///
  1233. /// The simple verifier may panic if it finds errors in the eBPF program at load time.
  1234. ///
  1235. /// # Examples
  1236. ///
  1237. /// ```
  1238. /// let prog1 = &[
  1239. /// 0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
  1240. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  1241. /// ];
  1242. /// let prog2 = &[
  1243. /// 0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
  1244. /// 0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
  1245. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  1246. /// ];
  1247. ///
  1248. /// let mut vm = rbpf::EbpfVmNoData::new(prog1);
  1249. ///
  1250. /// let res = vm.prog_exec();
  1251. /// assert_eq!(res, 0x2211);
  1252. ///
  1253. /// vm.set_prog(prog2);
  1254. ///
  1255. /// let res = vm.prog_exec();
  1256. /// assert_eq!(res, 0x1122);
  1257. /// ```
  1258. pub fn set_prog(&mut self, prog: &'a [u8]) {
  1259. self.parent.set_prog(prog)
  1260. }
  1261. /// Register a built-in or user-defined helper function in order to use it later from within
  1262. /// the eBPF program. The helper is registered into a hashmap, so the `key` can be any `u32`.
  1263. ///
  1264. /// If using JIT-compiled eBPF programs, be sure to register all helpers before compiling the
  1265. /// program. You should be able to change registered helpers after compiling, but not to add
  1266. /// new ones (i.e. with new keys).
  1267. ///
  1268. /// # Examples
  1269. ///
  1270. /// ```
  1271. /// use rbpf::helpers;
  1272. ///
  1273. /// let prog = &[
  1274. /// 0xb7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // mov r1, 0x010000000
  1275. /// 0xb7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r2, 0
  1276. /// 0xb7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r3, 0
  1277. /// 0xb7, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r4, 0
  1278. /// 0xb7, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r5, 0
  1279. /// 0x85, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // call helper with key 1
  1280. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  1281. /// ];
  1282. ///
  1283. /// let mut vm = rbpf::EbpfVmNoData::new(prog);
  1284. ///
  1285. /// // Register a helper. This helper will store the result of the square root of r1 into r0.
  1286. /// vm.register_helper(1, helpers::sqrti);
  1287. ///
  1288. /// let res = vm.prog_exec();
  1289. /// assert_eq!(res, 0x1000);
  1290. /// ```
  1291. pub fn register_helper(&mut self, key: u32, function: fn (u64, u64, u64, u64, u64) -> u64) {
  1292. self.parent.register_helper(key, function);
  1293. }
  1294. /// JIT-compile the loaded program. No argument required for this.
  1295. ///
  1296. /// If using helper functions, be sure to register them into the VM before calling this
  1297. /// function.
  1298. ///
  1299. /// # Panics
  1300. ///
  1301. /// This function panics if an error occurs during JIT-compiling, such as the occurrence of an
  1302. /// unknown eBPF operation code.
  1303. ///
  1304. /// # Examples
  1305. ///
  1306. /// ```
  1307. /// let prog = &[
  1308. /// 0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
  1309. /// 0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
  1310. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  1311. /// ];
  1312. ///
  1313. /// let mut vm = rbpf::EbpfVmNoData::new(prog);
  1314. ///
  1315. ///
  1316. /// vm.jit_compile();
  1317. /// ```
  1318. pub fn jit_compile(&mut self) {
  1319. self.parent.jit_compile();
  1320. }
  1321. /// Execute the program loaded, without providing pointers to any memory area whatsoever.
  1322. ///
  1323. /// # Panics
  1324. ///
  1325. /// This function is currently expected to panic if it encounters any error during the program
  1326. /// execution, such as memory accesses or division by zero attempts. This may be changed in the
  1327. /// future (we could raise errors instead).
  1328. ///
  1329. /// # Examples
  1330. ///
  1331. /// ```
  1332. /// let prog = &[
  1333. /// 0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
  1334. /// 0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
  1335. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  1336. /// ];
  1337. ///
  1338. /// let vm = rbpf::EbpfVmNoData::new(prog);
  1339. ///
  1340. /// // For this kind of VM, the `prog_exec()` function needs no argument.
  1341. /// let res = vm.prog_exec();
  1342. /// assert_eq!(res, 0x1122);
  1343. /// ```
  1344. pub fn prog_exec(&self) -> u64 {
  1345. self.parent.prog_exec(&mut [])
  1346. }
  1347. /// Execute the previously JIT-compiled program, without providing pointers to any memory area
  1348. /// whatsoever, in a manner very similar to `prog_exec()`.
  1349. ///
  1350. /// # Panics
  1351. ///
  1352. /// This function panics if an error occurs during the execution of the program.
  1353. ///
  1354. /// # Safety
  1355. ///
  1356. /// **WARNING:** JIT-compiled assembly code is not safe, in particular there is no runtime
  1357. /// check for memory access; so if the eBPF program attempts erroneous accesses, this may end
  1358. /// very bad (program may segfault). It may be wise to check that the program works with the
  1359. /// interpreter before running the JIT-compiled version of it.
  1360. ///
  1361. /// For this reason the function should be called from within an `unsafe` bloc.
  1362. ///
  1363. /// # Examples
  1364. ///
  1365. /// ```
  1366. /// let prog = &[
  1367. /// 0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
  1368. /// 0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
  1369. /// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
  1370. /// ];
  1371. ///
  1372. /// let mut vm = rbpf::EbpfVmNoData::new(prog);
  1373. ///
  1374. /// vm.jit_compile();
  1375. ///
  1376. /// unsafe {
  1377. /// let res = vm.prog_exec_jit();
  1378. /// assert_eq!(res, 0x1122);
  1379. /// }
  1380. /// ```
  1381. pub unsafe fn prog_exec_jit(&self) -> u64 {
  1382. self.parent.prog_exec_jit(&mut [])
  1383. }
  1384. }