Skip to content

Commit e591bb9

Browse files
committed
fix: add executable memory using set_jit_exec_memory
Signed-off-by: Godones <[email protected]>
1 parent 7e7b1cd commit e591bb9

File tree

1 file changed

+161
-88
lines changed

1 file changed

+161
-88
lines changed

src/lib.rs

Lines changed: 161 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,9 @@ pub mod lib {
9999
// BTree-based implementations of Maps and Sets. The cranelift module uses
100100
// BTrees by default, hence we need to expose it twice here.
101101
#[cfg(not(feature = "std"))]
102-
pub use alloc::collections::{BTreeMap};
102+
pub use alloc::collections::BTreeMap;
103103
#[cfg(feature = "std")]
104-
pub use std::collections::{BTreeMap};
104+
pub use std::collections::BTreeMap;
105105

106106
/// In no_std we use a custom implementation of the error which acts as a
107107
/// replacement for the io Error.
@@ -179,6 +179,8 @@ pub struct EbpfVmMbuff<'a> {
179179
verifier: Verifier,
180180
#[cfg(not(windows))]
181181
jit: Option<jit::JitMemory<'a>>,
182+
#[cfg(all(not(windows), not(feature = "std")))]
183+
custom_exec_memory: Option<&'a mut [u8]>,
182184
#[cfg(feature = "cranelift")]
183185
cranelift_prog: Option<cranelift::CraneliftProgram>,
184186
helpers: HashMap<u32, ebpf::Helper>,
@@ -217,6 +219,8 @@ impl<'a> EbpfVmMbuff<'a> {
217219
verifier: verifier::check,
218220
#[cfg(not(windows))]
219221
jit: None,
222+
#[cfg(all(not(windows), not(feature = "std")))]
223+
custom_exec_memory: None,
220224
#[cfg(feature = "cranelift")]
221225
cranelift_prog: None,
222226
helpers: HashMap::new(),
@@ -332,6 +336,27 @@ impl<'a> EbpfVmMbuff<'a> {
332336
Ok(())
333337
}
334338

339+
/// Set a custom executable memory for the JIT-compiled program.
340+
/// We need this for no_std because we cannot use the default memory allocator.
341+
///
342+
/// # Examples
343+
///
344+
/// ```
345+
/// let prog = &[
346+
/// 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
347+
/// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
348+
/// ];
349+
/// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
350+
/// let mut memory = [0u8; 1024];
351+
/// // Use mmap or other means to modify the permissions of the memory to be executable.
352+
/// vm.set_jit_exec_memory(&mut memory);
353+
/// ```
354+
#[cfg(all(not(windows), not(feature = "std")))]
355+
pub fn set_jit_exec_memory(&mut self, memory: &'a mut [u8]) -> Result<(), Error> {
356+
self.custom_exec_memory = Some(memory);
357+
Ok(())
358+
}
359+
335360
/// Register a built-in or user-defined helper function in order to use it later from within
336361
/// the eBPF program. The helper is registered into a hashmap, so the `key` can be any `u32`.
337362
///
@@ -476,7 +501,7 @@ impl<'a> EbpfVmMbuff<'a> {
476501
///
477502
/// vm.jit_compile();
478503
/// ```
479-
#[cfg(all(not(windows), feature = "std"))]
504+
#[cfg(not(windows))]
480505
pub fn jit_compile(&mut self) -> Result<(), Error> {
481506
let prog = match self.prog {
482507
Some(prog) => prog,
@@ -485,29 +510,27 @@ impl<'a> EbpfVmMbuff<'a> {
485510
"Error: No program set, call prog_set() to load one",
486511
))?,
487512
};
488-
self.jit = Some(jit::JitMemory::new(prog, &self.helpers, true, false)?);
489-
Ok(())
490-
}
491-
492-
/// JIT-compile the loaded program. The user has to provide a mutable slice of memory that
493-
/// will be used for the JIT-compiled code. For more information, see the [EbpfVmMbuff::jit_compile]
494-
/// function.
495-
#[cfg(all(not(windows), not(feature = "std")))]
496-
pub fn jit_compile(&mut self, executable_memory: &'a mut [u8]) -> Result<(), Error> {
497-
let prog = match self.prog {
498-
Some(prog) => prog,
499-
None => Err(Error::new(
500-
ErrorKind::Other,
501-
"Error: No program set, call prog_set() to load one",
502-
))?,
503-
};
504-
self.jit = Some(jit::JitMemory::new(
505-
prog,
506-
executable_memory,
507-
&self.helpers,
508-
true,
509-
false,
510-
)?);
513+
#[cfg(feature = "std")]
514+
{
515+
self.jit = Some(jit::JitMemory::new(prog, &self.helpers, true, false)?);
516+
}
517+
#[cfg(not(feature = "std"))]
518+
{
519+
let exec_memory = match self.custom_exec_memory.take() {
520+
Some(memory) => memory,
521+
None => return Err(Error::new(
522+
ErrorKind::Other,
523+
"Error: No custom executable memory set, call set_jit_exec_memory() to set one",
524+
))?,
525+
};
526+
self.jit = Some(jit::JitMemory::new(
527+
prog,
528+
exec_memory,
529+
&self.helpers,
530+
true,
531+
false,
532+
)?);
533+
}
511534
Ok(())
512535
}
513536

@@ -929,6 +952,27 @@ impl<'a> EbpfVmFixedMbuff<'a> {
929952
self.parent.set_stack_usage_calculator(calculator, data)
930953
}
931954

955+
/// Set a custom executable memory for the JIT-compiled program.
956+
/// We need this for no_std because we cannot use the default memory allocator.
957+
///
958+
/// # Examples
959+
///
960+
/// ```
961+
/// let prog = &[
962+
/// 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
963+
/// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
964+
/// ];
965+
/// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
966+
/// let mut memory = [0u8; 1024];
967+
/// // Use mmap or other means to modify the permissions of the memory to be executable.
968+
/// vm.set_jit_exec_memory(&mut memory);
969+
/// ```
970+
#[cfg(all(not(windows), not(feature = "std")))]
971+
pub fn set_jit_exec_memory(&mut self, memory: &'a mut [u8]) -> Result<(), Error> {
972+
self.parent.custom_exec_memory = Some(memory);
973+
Ok(())
974+
}
975+
932976
/// Register a built-in or user-defined helper function in order to use it later from within
933977
/// the eBPF program. The helper is registered into a hashmap, so the `key` can be any `u32`.
934978
///
@@ -1088,7 +1132,7 @@ impl<'a> EbpfVmFixedMbuff<'a> {
10881132
///
10891133
/// vm.jit_compile();
10901134
/// ```
1091-
#[cfg(all(not(windows), feature = "std"))]
1135+
#[cfg(not(windows))]
10921136
pub fn jit_compile(&mut self) -> Result<(), Error> {
10931137
let prog = match self.parent.prog {
10941138
Some(prog) => prog,
@@ -1097,29 +1141,27 @@ impl<'a> EbpfVmFixedMbuff<'a> {
10971141
"Error: No program set, call prog_set() to load one",
10981142
))?,
10991143
};
1100-
self.parent.jit = Some(jit::JitMemory::new(prog, &self.parent.helpers, true, true)?);
1101-
Ok(())
1102-
}
1103-
1104-
/// JIT-compile the loaded program. The user has to provide a mutable slice of memory that
1105-
/// will be used for the JIT-compiled code. For more information, see the [EbpfVmFixedMbuff::jit_compile]
1106-
/// function.
1107-
#[cfg(all(not(windows), not(feature = "std")))]
1108-
pub fn jit_compile(&mut self, executable_memory: &'a mut [u8]) -> Result<(), Error> {
1109-
let prog = match self.parent.prog {
1110-
Some(prog) => prog,
1111-
None => Err(Error::new(
1112-
ErrorKind::Other,
1113-
"Error: No program set, call prog_set() to load one",
1114-
))?,
1115-
};
1116-
self.parent.jit = Some(jit::JitMemory::new(
1117-
prog,
1118-
executable_memory,
1119-
&self.parent.helpers,
1120-
true,
1121-
true,
1122-
)?);
1144+
#[cfg(feature = "std")]
1145+
{
1146+
self.parent.jit = Some(jit::JitMemory::new(prog, &self.parent.helpers, true, true)?);
1147+
}
1148+
#[cfg(not(feature = "std"))]
1149+
{
1150+
let exec_memory = match self.parent.custom_exec_memory.take() {
1151+
Some(memory) => memory,
1152+
None => return Err(Error::new(
1153+
ErrorKind::Other,
1154+
"Error: No custom executable memory set, call set_jit_exec_memory() to set one",
1155+
))?,
1156+
};
1157+
self.parent.jit = Some(jit::JitMemory::new(
1158+
prog,
1159+
exec_memory,
1160+
&self.parent.helpers,
1161+
true,
1162+
true,
1163+
)?);
1164+
}
11231165
Ok(())
11241166
}
11251167

@@ -1464,6 +1506,27 @@ impl<'a> EbpfVmRaw<'a> {
14641506
self.parent.set_stack_usage_calculator(calculator, data)
14651507
}
14661508

1509+
/// Set a custom executable memory for the JIT-compiled program.
1510+
/// We need this for no_std because we cannot use the default memory allocator.
1511+
///
1512+
/// # Examples
1513+
///
1514+
/// ```
1515+
/// let prog = &[
1516+
/// 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
1517+
/// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
1518+
/// ];
1519+
/// let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
1520+
/// let mut memory = [0u8; 1024];
1521+
/// // Use mmap or other means to modify the permissions of the memory to be executable.
1522+
/// vm.set_jit_exec_memory(&mut memory);
1523+
/// ```
1524+
#[cfg(all(not(windows), not(feature = "std")))]
1525+
pub fn set_jit_exec_memory(&mut self, memory: &'a mut [u8]) -> Result<(), Error> {
1526+
self.parent.custom_exec_memory = Some(memory);
1527+
Ok(())
1528+
}
1529+
14671530
/// Register a built-in or user-defined helper function in order to use it later from within
14681531
/// the eBPF program. The helper is registered into a hashmap, so the `key` can be any `u32`.
14691532
///
@@ -1589,7 +1652,7 @@ impl<'a> EbpfVmRaw<'a> {
15891652
///
15901653
/// vm.jit_compile();
15911654
/// ```
1592-
#[cfg(all(not(windows), feature = "std"))]
1655+
#[cfg(not(windows))]
15931656
pub fn jit_compile(&mut self) -> Result<(), Error> {
15941657
let prog = match self.parent.prog {
15951658
Some(prog) => prog,
@@ -1598,34 +1661,32 @@ impl<'a> EbpfVmRaw<'a> {
15981661
"Error: No program set, call prog_set() to load one",
15991662
))?,
16001663
};
1601-
self.parent.jit = Some(jit::JitMemory::new(
1602-
prog,
1603-
&self.parent.helpers,
1604-
false,
1605-
false,
1606-
)?);
1607-
Ok(())
1608-
}
1609-
1610-
/// JIT-compile the loaded program. The user has to provide a mutable slice of memory that
1611-
/// will be used for the JIT-compiled code. For more information, see the [EbpfVmRaw::jit_compile]
1612-
/// function.
1613-
#[cfg(all(not(windows), not(feature = "std")))]
1614-
pub fn jit_compile(&mut self, executable_memory: &'a mut [u8]) -> Result<(), Error> {
1615-
let prog = match self.parent.prog {
1616-
Some(prog) => prog,
1617-
None => Err(Error::new(
1618-
ErrorKind::Other,
1619-
"Error: No program set, call prog_set() to load one",
1620-
))?,
1621-
};
1622-
self.parent.jit = Some(jit::JitMemory::new(
1623-
prog,
1624-
executable_memory,
1625-
&self.parent.helpers,
1626-
false,
1627-
false,
1628-
)?);
1664+
#[cfg(feature = "std")]
1665+
{
1666+
self.parent.jit = Some(jit::JitMemory::new(
1667+
prog,
1668+
&self.parent.helpers,
1669+
false,
1670+
false,
1671+
)?);
1672+
}
1673+
#[cfg(not(feature = "std"))]
1674+
{
1675+
let exec_memory = match self.parent.custom_exec_memory.take() {
1676+
Some(memory) => memory,
1677+
None => return Err(Error::new(
1678+
ErrorKind::Other,
1679+
"Error: No custom executable memory set, call set_jit_exec_memory() to set one",
1680+
))?,
1681+
};
1682+
self.parent.jit = Some(jit::JitMemory::new(
1683+
prog,
1684+
exec_memory,
1685+
&self.parent.helpers,
1686+
false,
1687+
false,
1688+
)?);
1689+
}
16291690
Ok(())
16301691
}
16311692

@@ -1905,6 +1966,26 @@ impl<'a> EbpfVmNoData<'a> {
19051966
self.parent.set_stack_usage_calculator(calculator, data)
19061967
}
19071968

1969+
/// Set a custom executable memory for the JIT-compiled program.
1970+
/// We need this for no_std because we cannot use the default memory allocator.
1971+
///
1972+
/// # Examples
1973+
///
1974+
/// ```
1975+
/// let prog = &[
1976+
/// 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
1977+
/// 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit
1978+
/// ];
1979+
/// let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
1980+
/// let mut memory = [0u8; 1024];
1981+
/// // Use mmap or other means to modify the permissions of the memory to be executable.
1982+
/// vm.set_jit_exec_memory(&mut memory);
1983+
/// ```
1984+
#[cfg(all(not(windows), not(feature = "std")))]
1985+
pub fn set_jit_exec_memory(&mut self, memory: &'a mut [u8]) -> Result<(), Error> {
1986+
self.parent.set_jit_exec_memory(memory)
1987+
}
1988+
19081989
/// Register a built-in or user-defined helper function in order to use it later from within
19091990
/// the eBPF program. The helper is registered into a hashmap, so the `key` can be any `u32`.
19101991
///
@@ -1999,19 +2080,11 @@ impl<'a> EbpfVmNoData<'a> {
19992080
///
20002081
/// vm.jit_compile();
20012082
/// ```
2002-
#[cfg(all(not(windows), feature = "std"))]
2083+
#[cfg(not(windows))]
20032084
pub fn jit_compile(&mut self) -> Result<(), Error> {
20042085
self.parent.jit_compile()
20052086
}
20062087

2007-
/// JIT-compile the loaded program. The user has to provide a mutable slice of memory that
2008-
/// will be used for the JIT-compiled code. For more information, see the [EbpfVmNoData::jit_compile]
2009-
/// function.
2010-
#[cfg(all(not(windows), not(feature = "std")))]
2011-
pub fn jit_compile(&mut self, executable_memory: &'a mut [u8]) -> Result<(), Error> {
2012-
self.parent.jit_compile(executable_memory)
2013-
}
2014-
20152088
/// Execute the program loaded, without providing pointers to any memory area whatsoever.
20162089
///
20172090
/// # Examples

0 commit comments

Comments
 (0)