Quellcode durchsuchen

src/lib.rs: make prog_exec(_jit) functions take a reference to mbuff

Prior to this commit, when using a struct EbpfVmFixedMbuff, the full
buffer was passed through the stack, since all structs would expect it
as an argument (even if empty) for the exec functions, to add it to an
(mostly useless) internal MetaBuff.

EbpfVmFixedMbuff is the only struct needing this, adapt the function
calls in consequence. This avoids copying the mbuff each time the
program is run.
Quentin Monnet vor 8 Jahren
Ursprung
Commit
3ae3a3f1d8
3 geänderte Dateien mit 35 neuen und 40 gelöschten Zeilen
  1. 2 2
      README.md
  2. 29 34
      src/lib.rs
  3. 4 4
      tests/misc.rs

+ 2 - 2
README.md

@@ -100,7 +100,7 @@ fn main() {
 
     // Just for the example we create our metadata buffer from scratch, and
     // we store the pointers to packet data start and end in it.
-    let mbuff = vec![0u8; 32];
+    let mut mbuff = vec![0u8; 32];
     unsafe {
         let mut data     = mbuff.as_ptr().offset(8)  as *mut u64;
         let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
@@ -116,7 +116,7 @@ fn main() {
 
     // Here we must provide both a reference to the packet data, and to the
     // metadata buffer we use.
-    assert_eq!(vm.prog_exec_jit(&mut mem, mbuff), 0x2211);
+    assert_eq!(vm.prog_exec_jit(&mut mem, &mut mbuff), 0x2211);
 }
 ```
 

+ 29 - 34
src/lib.rs

@@ -62,7 +62,7 @@ impl<'a> EbpfVm<'a> {
         self.helpers.insert(key, function);
     }
 
-    fn prog_exec(&self, mem: &mut std::vec::Vec<u8>, mbuff: &'a mut MetaBuff) -> u64 {
+    fn prog_exec(&self, mem: &mut std::vec::Vec<u8>, mbuff: &'a mut std::vec::Vec<u8>) -> u64 {
         const U32MAX: u64 = u32::MAX as u64;
 
         let stack = vec![0u8;ebpf::STACK_SIZE];
@@ -71,18 +71,18 @@ impl<'a> EbpfVm<'a> {
         let mut reg: [u64;11] = [
             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, stack.as_ptr() as u64 + stack.len() as u64
         ];
-        if mbuff.buffer.len() > 0 {
-            reg[1] = mbuff.buffer.as_ptr() as u64;
+        if mbuff.len() > 0 {
+            reg[1] = mbuff.as_ptr() as u64;
         }
         else if mem.len() > 0 {
             reg[1] = mem.as_ptr() as u64;
         }
 
         let check_mem_load = | addr: u64, len: usize, insn_ptr: usize | {
-            EbpfVm::check_mem(addr, len, "load", insn_ptr, &mbuff.buffer, &mem, &stack);
+            EbpfVm::check_mem(addr, len, "load", insn_ptr, &mbuff, &mem, &stack);
         };
         let check_mem_store = | addr: u64, len: usize, insn_ptr: usize | {
-            EbpfVm::check_mem(addr, len, "store", insn_ptr, &mbuff.buffer, &mem, &stack);
+            EbpfVm::check_mem(addr, len, "store", insn_ptr, &mbuff, &mem, &stack);
         };
 
         // Loop on instructions
@@ -334,7 +334,7 @@ impl<'a> EbpfVm<'a> {
     // fn jit_compile(&mut self) {
     // }
 
-    fn prog_exec_jit(&self, mem: &mut std::vec::Vec<u8>, mbuff: &'a mut MetaBuff) -> u64 {
+    fn prog_exec_jit(&self, mem: &mut std::vec::Vec<u8>, mbuff: &'a mut std::vec::Vec<u8>) -> u64 {
         // If packet data is empty, do not send the address of an empty vector; send a null
         // pointer (zero value) as first argument instead, as this is uBPF's behavior (empty
         // packet should not happen in the kernel; anyway the verifier would prevent the use of
@@ -343,8 +343,10 @@ impl<'a> EbpfVm<'a> {
             0 => 0 as *mut u8,
             _ => mem.as_ptr() as *mut u8
         };
-        (self.jit)(mbuff.buffer.as_ptr() as *mut u8, mbuff.buffer.len(), mem_ptr, mem.len(),
-                   mbuff.data_offset, mbuff.data_end_offset)
+        // The last two arguments are not used in this function. They would be used if there was a
+        // need to indicate to the JIT at which offset in the mbuff mem_ptr and mem_ptr + mem.len()
+        // should be stored; this is what happens with struct EbpfVmFixedMbuff.
+        (self.jit)(mbuff.as_ptr() as *mut u8, mbuff.len(), mem_ptr, mem.len(), 0, 0)
     }
 }
 
@@ -370,26 +372,16 @@ impl<'a> EbpfVmMbuff<'a> {
         self.parent.register_helper(key, function);
     }
 
-    pub fn prog_exec(&self, mem: &'a mut std::vec::Vec<u8>, metadata: std::vec::Vec<u8>) -> u64 {
-        let mut mbuff = MetaBuff {
-            data_offset:     0,
-            data_end_offset: 0,
-            buffer:          metadata,
-        };
-        self.parent.prog_exec(mem, &mut mbuff)
+    pub fn prog_exec(&self, mem: &'a mut std::vec::Vec<u8>, mbuff: &'a mut std::vec::Vec<u8>) -> u64 {
+        self.parent.prog_exec(mem, mbuff)
     }
 
     pub fn jit_compile(&mut self) {
         self.parent.jit = jit::compile(&self.parent.prog, &self.parent.helpers, true, false);
     }
 
-    pub fn prog_exec_jit(&self, mem: &'a mut std::vec::Vec<u8>, metadata: std::vec::Vec<u8>) -> u64 {
-        let mut mbuff = MetaBuff {
-            data_offset:     0,
-            data_end_offset: 0,
-            buffer:          metadata,
-        };
-        self.parent.prog_exec_jit(mem, &mut mbuff)
+    pub fn prog_exec_jit(&self, mem: &'a mut std::vec::Vec<u8>, mbuff: &'a mut std::vec::Vec<u8>) -> u64 {
+        self.parent.prog_exec_jit(mem, mbuff)
     }
 }
 
@@ -437,15 +429,26 @@ impl<'a> EbpfVmFixedMbuff<'a> {
             *data     = mem.as_ptr() as u64;
             *data_end = mem.as_ptr() as u64 + mem.len() as u64;
         }
-        self.parent.prog_exec(mem, &mut self.mbuff)
+        self.parent.prog_exec(mem, &mut self.mbuff.buffer)
     }
 
     pub fn jit_compile(&mut self) {
         self.parent.jit = jit::compile(&self.parent.prog, &self.parent.helpers, true, true);
     }
 
+    // This struct redefines the `prog_exec_jit()` function, in order to pass the offsets
+    // associated with the fixed mbuff.
     pub fn prog_exec_jit(&mut self, mem: &'a mut std::vec::Vec<u8>) -> u64 {
-        self.parent.prog_exec_jit(mem, &mut self.mbuff)
+        // If packet data is empty, do not send the address of an empty vector; send a null
+        // pointer (zero value) as first argument instead, as this is uBPF's behavior (empty
+        // packet should not happen in the kernel; anyway the verifier would prevent the use of
+        // uninitialized registers). See `mul_loop` test.
+        let mem_ptr = match mem.len() {
+            0 => 0 as *mut u8,
+            _ => mem.as_ptr() as *mut u8
+        };
+        (self.parent.jit)(self.mbuff.buffer.as_ptr() as *mut u8, self.mbuff.buffer.len(),
+                          mem_ptr, mem.len(), self.mbuff.data_offset, self.mbuff.data_end_offset)
     }
 }
 
@@ -472,11 +475,7 @@ impl<'a> EbpfVmRaw<'a> {
     }
 
     pub fn prog_exec(&self, mem: &'a mut std::vec::Vec<u8>) -> u64 {
-        let mut mbuff = MetaBuff {
-            data_offset:     0,
-            data_end_offset: 0,
-            buffer:          vec![]
-        };
+        let mut mbuff = vec![];
         self.parent.prog_exec(mem, &mut mbuff)
     }
 
@@ -485,11 +484,7 @@ impl<'a> EbpfVmRaw<'a> {
     }
 
     pub fn prog_exec_jit(&self, mem: &'a mut std::vec::Vec<u8>) -> u64 {
-        let mut mbuff = MetaBuff {
-            data_offset:     0,
-            data_end_offset: 0,
-            buffer:          vec![]
-        };
+        let mut mbuff = vec![];
         //println!("{:?}", &mbuff.buffer);
         //println!("{:?}", &mem);
         //println!("{:?}", mem.as_ptr() as *const u64);

+ 4 - 4
tests/misc.rs

@@ -265,7 +265,7 @@ fn test_vm_mbuff() {
         0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
     ];
 
-    let mbuff = vec![0u8; 32];
+    let mut mbuff = vec![0u8; 32];
     unsafe {
         let mut data     = mbuff.as_ptr().offset(8)  as *mut u64;
         let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
@@ -274,7 +274,7 @@ fn test_vm_mbuff() {
     }
 
     let vm = rbpf::EbpfVmMbuff::new(&prog);
-    assert_eq!(vm.prog_exec(&mut mem, mbuff), 0x2211);
+    assert_eq!(vm.prog_exec(&mut mem, &mut mbuff), 0x2211);
 }
 
 // Program and memory come from uBPF test ldxh.
@@ -291,7 +291,7 @@ fn test_jit_mbuff() {
         0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
     ];
 
-    let mbuff = vec![0u8; 32];
+    let mut mbuff = vec![0u8; 32];
     unsafe {
         let mut data     = mbuff.as_ptr().offset(8)  as *mut u64;
         let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
@@ -301,5 +301,5 @@ fn test_jit_mbuff() {
 
     let mut vm = rbpf::EbpfVmMbuff::new(&prog);
     vm.jit_compile();
-    assert_eq!(vm.prog_exec_jit(&mut mem, mbuff), 0x2211);
+    assert_eq!(vm.prog_exec_jit(&mut mem, &mut mbuff), 0x2211);
 }