1use crate::{
4 aligned_memory::Pod,
5 ebpf,
6 error::{EbpfError, ProgramResult, StableResult},
7 program::SBPFVersion,
8 vm::Config,
9};
10use std::fmt::Formatter;
11use std::{array, cell::UnsafeCell, fmt, mem, ops::Range, ptr};
12
13pub type AccessViolationHandler = Box<dyn Fn(&mut MemoryRegion, u64, AccessType, u64, u64)>;
32#[allow(clippy::result_unit_err)]
34pub fn default_access_violation_handler(
35 _region: &mut MemoryRegion,
36 _region_max_len: u64,
37 _access_type: AccessType,
38 _vm_addr: u64,
39 _len: u64,
40) {
41}
42
43pub unsafe trait HostMemoryObject {
50 fn host(self) -> HostBuffer;
54}
55
56pub trait VmExposable {}
61
62pub unsafe trait VmExposableMut {}
72
73unsafe impl VmExposableMut for u8 {}
74impl<T: VmExposableMut> VmExposable for T {}
75
76unsafe impl<T: VmExposable> HostMemoryObject for *const T {
77 fn host(self) -> HostBuffer {
78 HostBuffer::Immutable(ptr::slice_from_raw_parts(
79 self.cast(),
80 std::mem::size_of::<T>(),
81 ))
82 }
83}
84
85unsafe impl<T: VmExposableMut> HostMemoryObject for *mut T {
86 fn host(self) -> HostBuffer {
87 HostBuffer::Mutable(ptr::slice_from_raw_parts_mut(
88 self.cast(),
89 std::mem::size_of::<T>(),
90 ))
91 }
92}
93
94unsafe impl<T: VmExposable> HostMemoryObject for *const [T] {
95 fn host(self) -> HostBuffer {
96 HostBuffer::Immutable(ptr::slice_from_raw_parts(
97 self.cast(),
98 self.len().checked_mul(core::mem::size_of::<T>()).unwrap(),
99 ))
100 }
101}
102
103unsafe impl<T: VmExposableMut> HostMemoryObject for *mut [T] {
104 fn host(self) -> HostBuffer {
105 HostBuffer::Mutable(ptr::slice_from_raw_parts_mut(
106 self.cast(),
107 self.len().checked_mul(core::mem::size_of::<T>()).unwrap(),
108 ))
109 }
110}
111
112unsafe impl<T: VmExposable, const N: usize> HostMemoryObject for *const [T; N] {
113 fn host(self) -> HostBuffer {
114 HostBuffer::Immutable(ptr::slice_from_raw_parts(
115 self.cast(),
116 N.checked_mul(core::mem::size_of::<T>()).unwrap(),
117 ))
118 }
119}
120
121unsafe impl<T: VmExposableMut, const N: usize> HostMemoryObject for *mut [T; N] {
122 fn host(self) -> HostBuffer {
123 HostBuffer::Mutable(ptr::slice_from_raw_parts_mut(
124 self.cast(),
125 N.checked_mul(core::mem::size_of::<T>()).unwrap(),
126 ))
127 }
128}
129
130#[derive(PartialEq, Eq, Copy, Clone, Debug)]
132pub enum HostBuffer {
133 Immutable(*const [u8]),
135 Mutable(*mut [u8]),
137}
138
139impl HostBuffer {
140 pub fn len(&self) -> usize {
142 match self {
143 HostBuffer::Immutable(p) => p.len(),
144 HostBuffer::Mutable(p) => p.len(),
145 }
146 }
147
148 pub fn is_empty(&self) -> bool {
150 match self {
151 HostBuffer::Immutable(p) => p.is_empty(),
152 HostBuffer::Mutable(p) => p.is_empty(),
153 }
154 }
155
156 pub fn is_mutable(&self) -> bool {
158 matches!(self, HostBuffer::Mutable(_))
159 }
160
161 pub unsafe fn mutable(self) -> Self {
167 match self {
168 HostBuffer::Immutable(p) => HostBuffer::Mutable(p.cast_mut()),
169 HostBuffer::Mutable(_) => self,
170 }
171 }
172
173 pub fn immutable(self) -> Self {
175 match self {
176 HostBuffer::Immutable(_) => self,
177 HostBuffer::Mutable(p) => Self::Immutable(p.cast_const()),
178 }
179 }
180
181 #[inline]
183 pub fn get(self, range: std::ops::Range<usize>) -> Option<Self> {
184 if range.end > self.len() {
185 return None;
186 }
187 let new_len = range.len();
188 unsafe {
189 Some(match self {
208 HostBuffer::Immutable(p) => HostBuffer::Immutable(ptr::slice_from_raw_parts(
209 p.byte_add(range.start).cast(),
210 new_len,
211 )),
212 HostBuffer::Mutable(p) => HostBuffer::Mutable(ptr::slice_from_raw_parts_mut(
213 p.byte_add(range.start).cast(),
214 new_len,
215 )),
216 })
217 }
218 }
219
220 #[inline(always)]
222 pub fn ptr(self) -> *const [u8] {
223 match self {
224 HostBuffer::Immutable(p) => p,
225 HostBuffer::Mutable(p) => p,
226 }
227 }
228
229 #[inline(always)]
231 pub fn ptr_mut(self) -> *mut [u8] {
232 match self {
233 HostBuffer::Immutable(p) => {
234 debug_assert!(false, "ptr_mut, but buffer is immutable");
235 p.cast_mut()
236 }
237 HostBuffer::Mutable(p) => p,
238 }
239 }
240}
241
242unsafe impl HostMemoryObject for HostBuffer {
243 fn host(self) -> HostBuffer {
244 self
245 }
246}
247
248#[derive(Eq, PartialEq, Clone)]
250pub struct MemoryRegion {
251 host: HostBuffer,
252 vm_addr: u64,
254 vm_gap_shift: u8,
256 pub access_violation_handler_payload: Option<u16>,
258}
259
260impl MemoryRegion {
261 fn new_internal(host: HostBuffer, vm_addr: u64, vm_gap_size: u64) -> Self {
265 let mut vm_gap_shift = (std::mem::size_of::<u64>() as u8)
266 .saturating_mul(8)
267 .saturating_sub(1);
268 if vm_gap_size > 0 {
269 vm_gap_shift = vm_gap_shift.saturating_sub(vm_gap_size.leading_zeros() as u8);
270 debug_assert_eq!(Some(vm_gap_size), 1_u64.checked_shl(vm_gap_shift as u32));
271 };
272 MemoryRegion {
273 host,
274 vm_addr,
275 vm_gap_shift,
276 access_violation_handler_payload: None,
277 }
278 }
279
280 pub fn new_empty(vm_addr: u64) -> Self {
284 const EMPTY: &[u8] = &[];
285 Self::new_internal((&raw const *EMPTY).host(), vm_addr, 0)
286 }
287
288 pub fn new<HO: HostMemoryObject>(host: HO, vm_addr: u64) -> Self {
292 Self::new_internal(host.host(), vm_addr, 0)
293 }
294
295 pub fn new_gapped<HO: HostMemoryObject>(host: HO, vm_addr: u64, vm_gap_size: u64) -> Self {
299 Self::new_internal(host.host(), vm_addr, vm_gap_size)
300 }
301
302 pub unsafe fn redirect<HO: HostMemoryObject>(&mut self, host: HO) {
312 self.host = host.host();
313 }
314
315 pub fn make_immutable(&mut self) {
317 unsafe {
318 self.redirect(self.host_buffer().immutable());
330 }
331 }
332
333 pub fn vm_addr_range(&self) -> Range<u64> {
335 let bytes = self.len() as u64;
336 if self.vm_gap_shift == 63 {
337 self.vm_addr..self.vm_addr.saturating_add(bytes)
338 } else {
339 self.vm_addr..self.vm_addr.saturating_add(bytes.saturating_mul(2))
340 }
341 }
342
343 pub fn host_buffer(&self) -> HostBuffer {
347 self.host
348 }
349
350 pub fn len(&self) -> usize {
352 self.host.len()
353 }
354
355 pub fn is_empty(&self) -> bool {
357 self.host.is_empty()
358 }
359
360 pub fn gap_size(&self) -> u64 {
362 if self.vm_gap_shift == 63 {
363 0
364 } else {
365 1 << self.vm_gap_shift
366 }
367 }
368
369 #[inline]
374 pub(crate) fn vm_to_host_buffer(&self, vm_addr: u64, len: u64) -> Option<HostBuffer> {
375 if vm_addr < self.vm_addr {
379 return None;
380 }
381
382 let begin_offset = vm_addr.saturating_sub(self.vm_addr);
383 if self.vm_gap_shift == 63 {
384 if let Some(end_offset) = begin_offset.checked_add(len) {
386 return self.host.get(begin_offset as usize..end_offset as usize);
387 }
388 return None;
389 }
390
391 let is_in_gap = (begin_offset
392 .checked_shr(self.vm_gap_shift as u32)
393 .unwrap_or(0)
394 & 1)
395 == 1;
396 let gap_mask = (-1i64).checked_shl(self.vm_gap_shift as u32).unwrap_or(0) as u64;
397 let gapped_offset =
398 (begin_offset & gap_mask).checked_shr(1).unwrap_or(0) | (begin_offset & !gap_mask);
399 if let Some(end_offset) = gapped_offset.checked_add(len) {
400 if !is_in_gap {
401 return self.host.get(gapped_offset as usize..end_offset as usize);
402 }
403 }
404 None
405 }
406}
407
408impl fmt::Debug for MemoryRegion {
409 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
410 let vm_addr = self.vm_addr_range();
411 let (host_addr, len, writable) = match self.host {
412 HostBuffer::Immutable(p) => (p.addr() as u64, p.len() as u64, false),
413 HostBuffer::Mutable(p) => (p.addr() as u64, p.len() as u64, true),
414 };
415 write!(
416 f,
417 "host_addr: {:#x?}-{:#x?}, vm_addr: {:#x?}-{:#x?}, len: {}, writable: {}, payload {:?}",
418 host_addr,
419 host_addr.saturating_add(len),
420 vm_addr.start,
421 vm_addr.end,
422 len,
423 writable,
424 self.access_violation_handler_payload,
425 )
426 }
427}
428
429impl std::cmp::PartialOrd for MemoryRegion {
430 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
431 Some(self.cmp(other))
432 }
433}
434
435impl std::cmp::Ord for MemoryRegion {
436 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
437 self.vm_addr.cmp(&other.vm_addr)
438 }
439}
440
441#[derive(Clone, Copy, PartialEq, Eq, Debug)]
443pub enum AccessType {
444 Load,
446 Store,
448}
449
450impl std::fmt::Display for AccessType {
451 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
452 f.write_str(match self {
453 Self::Load => "reading",
454 Self::Store => "writing",
455 })
456 }
457}
458
459pub struct UnalignedMemoryMapping {
461 regions: Box<[MemoryRegion]>,
463 region_addresses: Box<[u64]>,
465 region_index_lookup: Box<[usize]>,
467 cache: UnsafeCell<MappingCache>,
469}
470
471impl fmt::Debug for UnalignedMemoryMapping {
472 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
473 f.debug_struct("UnalignedMemoryMapping")
474 .field("regions", &self.regions)
475 .field("cache", &self.cache)
476 .finish()
477 }
478}
479
480impl UnalignedMemoryMapping {
481 fn construct_eytzinger_order(&mut self, mut in_index: usize, out_index: usize) -> usize {
482 if out_index >= self.regions.len() {
483 return in_index;
484 }
485 in_index =
486 self.construct_eytzinger_order(in_index, out_index.saturating_mul(2).saturating_add(1));
487 self.region_addresses[out_index] = self.regions[in_index].vm_addr;
488 self.region_index_lookup[out_index] = in_index;
489 self.construct_eytzinger_order(
490 in_index.saturating_add(1),
491 out_index.saturating_mul(2).saturating_add(2),
492 )
493 }
494
495 pub unsafe fn new_uninitialized(regions: Vec<MemoryRegion>) -> Self {
501 let number_of_regions = regions.len();
502 Self {
503 regions: regions.into_boxed_slice(),
504 region_addresses: vec![0; number_of_regions].into_boxed_slice(),
505 region_index_lookup: vec![0; number_of_regions].into_boxed_slice(),
506 cache: UnsafeCell::new(MappingCache::new()),
507 }
508 }
509
510 pub unsafe fn new(regions: Vec<MemoryRegion>) -> Result<Self, EbpfError> {
516 let mut mapping = Self::new_uninitialized(regions);
517 mapping.initialize()?;
518 Ok(mapping)
519 }
520
521 pub fn initialize(&mut self) -> Result<(), EbpfError> {
523 self.regions.sort();
524 let number_of_regions = self.regions.len();
525 for index in 1..number_of_regions {
526 let first = &self.regions[index.saturating_sub(1)];
527 let second = &self.regions[index];
528 if first.vm_addr_range().end > second.vm_addr {
529 return Err(EbpfError::InvalidMemoryRegion(index));
530 }
531 }
532
533 self.construct_eytzinger_order(0, 0);
534 Ok(())
535 }
536
537 #[allow(clippy::arithmetic_side_effects)]
539 #[inline(always)]
540 pub fn find_region(&self, vm_addr: u64) -> Option<(usize, &MemoryRegion)> {
541 let cache = unsafe { &mut *self.cache.get() };
546 if let Some(index) = cache.find(vm_addr) {
547 Some((index, unsafe { self.regions.get_unchecked(index) }))
551 } else {
552 let mut index = 1;
553 while index <= self.region_addresses.len() {
554 index = (index << 1)
558 + unsafe { *self.region_addresses.get_unchecked(index - 1) <= vm_addr }
559 as usize;
560 }
561 index >>= index.trailing_zeros() + 1;
562 if index == 0 {
563 return None;
564 }
565 index = unsafe { *self.region_index_lookup.get_unchecked(index - 1) };
569 let region = unsafe { self.regions.get_unchecked(index) };
570 cache.insert(region.vm_addr_range(), index);
571 Some((index, region))
572 }
573 }
574
575 #[inline(always)]
581 pub unsafe fn replace_region(
582 &mut self,
583 index: usize,
584 region: MemoryRegion,
585 ) -> Result<(), EbpfError> {
586 self.regions[index] = region;
587 self.cache.get_mut().flush();
588 Ok(())
589 }
590}
591
592#[derive(Debug)]
595pub struct AlignedMemoryMapping {
596 regions: Vec<MemoryRegion>,
597}
598
599impl AlignedMemoryMapping {
600 pub unsafe fn new(regions: Vec<MemoryRegion>) -> Result<Self, EbpfError> {
606 let mut mapping = Self::new_uninitialized(regions);
607 mapping.initialize()?;
608 Ok(mapping)
609 }
610
611 pub unsafe fn new_uninitialized(regions: Vec<MemoryRegion>) -> Self {
617 Self { regions }
618 }
619
620 pub fn initialize(&mut self) -> Result<(), EbpfError> {
622 static EMPTY_SLICE: &[u8] = &[];
623 self.regions.sort();
624 let mut expected_region_index = 0;
625 while expected_region_index < self.regions.len() {
626 let actual_region_index = self
627 .regions
628 .get(expected_region_index)
629 .unwrap()
630 .vm_addr
631 .checked_shr(ebpf::VIRTUAL_ADDRESS_BITS as u32)
632 .unwrap_or(0) as usize;
633 if actual_region_index > expected_region_index {
634 self.regions.insert(
635 expected_region_index,
636 MemoryRegion::new(
637 &raw const *EMPTY_SLICE,
638 (expected_region_index as u64).saturating_mul(ebpf::MM_REGION_SIZE),
639 ),
640 );
641 } else if actual_region_index < expected_region_index {
642 return Err(EbpfError::InvalidMemoryRegion(actual_region_index));
643 }
644 expected_region_index = expected_region_index.saturating_add(1);
645 }
646
647 Ok(())
648 }
649
650 #[inline(always)]
652 pub fn find_region(&self, vm_addr: u64) -> Option<(usize, &MemoryRegion)> {
653 let index = vm_addr.wrapping_shr(ebpf::VIRTUAL_ADDRESS_BITS as u32) as usize;
654 if index < self.regions.len() {
655 let region = unsafe { self.regions.get_unchecked(index) };
657 return Some((index, region));
658 }
659 None
660 }
661
662 #[inline(always)]
668 pub unsafe fn replace_region(
669 &mut self,
670 index: usize,
671 region: MemoryRegion,
672 ) -> Result<(), EbpfError> {
673 let begin_index = region
674 .vm_addr
675 .checked_shr(ebpf::VIRTUAL_ADDRESS_BITS as u32)
676 .unwrap_or(0) as usize;
677 let end_index = region
678 .vm_addr
679 .saturating_add((region.len() as u64).saturating_sub(1))
680 .checked_shr(ebpf::VIRTUAL_ADDRESS_BITS as u32)
681 .unwrap_or(0) as usize;
682 if begin_index != index || end_index != index {
683 return Err(EbpfError::InvalidMemoryRegion(index));
684 }
685 self.regions[index] = region;
686 Ok(())
687 }
688}
689
690pub struct MemoryMapping {
692 access_violation_handler: AccessViolationHandler,
694 max_call_depth: i64,
695 stack_frame_size: i64,
696 disable_address_translation: bool,
697 sbpf_version: SBPFVersion,
699 initialized: bool,
700 ty: MemoryMappingType,
701}
702
703impl fmt::Debug for MemoryMapping {
704 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
705 f.debug_struct("MemoryMapping")
706 .field("max_call_depth", &self.max_call_depth)
707 .field("stack_frame_size", &self.stack_frame_size)
708 .field("sbpf_version", &self.sbpf_version)
709 .field("ty", &self.ty)
710 .finish()
711 }
712}
713
714#[derive(Debug)]
716pub enum MemoryMappingType {
717 Aligned(AlignedMemoryMapping),
720 Unaligned(UnalignedMemoryMapping),
722}
723
724impl MemoryMapping {
725 pub unsafe fn new_with_access_violation_handler(
737 regions: Vec<MemoryRegion>,
738 config: &Config,
739 sbpf_version: SBPFVersion,
740 access_violation_handler: AccessViolationHandler,
741 ) -> Result<Self, EbpfError> {
742 let mut mapping =
743 Self::new_uninitialized(regions, config, sbpf_version, access_violation_handler);
744 mapping.initialize()?;
745 Ok(mapping)
746 }
747
748 pub unsafe fn new_uninitialized(
759 regions: Vec<MemoryRegion>,
760 config: &Config,
761 sbpf_version: SBPFVersion,
762 access_violation_handler: AccessViolationHandler,
763 ) -> Self {
764 let ty = if sbpf_version >= SBPFVersion::V4 || config.aligned_memory_mapping {
765 MemoryMappingType::Aligned(AlignedMemoryMapping::new_uninitialized(regions))
766 } else {
767 debug_assert!(
768 sbpf_version <= SBPFVersion::V3,
769 "SBPFv4 and later versions do not support unaligned memory"
770 );
771 MemoryMappingType::Unaligned(UnalignedMemoryMapping::new_uninitialized(regions))
772 };
773
774 Self {
775 access_violation_handler: Box::new(access_violation_handler),
776 max_call_depth: config.max_call_depth as i64,
777 stack_frame_size: config.stack_frame_size as i64,
778 disable_address_translation: !config.enable_address_translation,
779 sbpf_version,
780 initialized: false,
781 ty,
782 }
783 }
784
785 pub unsafe fn new(
793 regions: Vec<MemoryRegion>,
794 config: &Config,
795 sbpf_version: SBPFVersion,
796 ) -> Result<Self, EbpfError> {
797 Self::new_with_access_violation_handler(
798 regions,
799 config,
800 sbpf_version,
801 Box::new(default_access_violation_handler),
802 )
803 }
804
805 pub fn map(
807 &self,
808 access_type: AccessType,
809 vm_addr: u64,
810 len: u64,
811 ) -> StableResult<HostBuffer, EbpfError> {
812 debug_assert!(self.initialized);
813 if self.disable_address_translation {
814 let ptr = ptr::with_exposed_provenance_mut(vm_addr as usize);
820 let buffer = HostBuffer::Mutable(ptr::slice_from_raw_parts_mut(ptr, len as usize));
821 return StableResult::Ok(buffer);
822 }
823 if let Some((_index, region)) = self.find_region(vm_addr) {
824 if region.host_buffer().is_mutable() || access_type != AccessType::Store {
825 if let Some(host_buffer) = region.vm_to_host_buffer(vm_addr, len) {
826 return StableResult::Ok(host_buffer);
827 }
828 }
829 }
830 StableResult::Err(self.generate_access_violation(access_type, vm_addr, len))
831 }
832
833 #[inline(always)]
838 pub fn map_with_access_violation_handler(
839 &mut self,
840 access_type: AccessType,
841 vm_addr: u64,
842 len: u64,
843 ) -> StableResult<HostBuffer, EbpfError> {
844 debug_assert!(self.initialized);
845 if self.disable_address_translation {
846 let ptr = ptr::with_exposed_provenance_mut(vm_addr as usize);
852 let buffer = HostBuffer::Mutable(ptr::slice_from_raw_parts_mut(ptr, len as usize));
853 return StableResult::Ok(buffer);
854 }
855
856 let index = match self.find_region(vm_addr) {
857 Some((index, region)) => {
858 if region.host_buffer().is_mutable() || access_type != AccessType::Store {
859 if let Some(host_buffer) = region.vm_to_host_buffer(vm_addr, len) {
860 return StableResult::Ok(host_buffer);
861 }
862 }
863 index
864 }
865 None => usize::MAX,
866 };
867 self.map_with_access_violation_handler_slow(index, access_type, vm_addr, len)
872 }
873
874 #[cold]
878 #[inline(never)]
879 fn map_with_access_violation_handler_slow(
880 &mut self,
881 region_index: usize,
882 access_type: AccessType,
883 vm_addr: u64,
884 len: u64,
885 ) -> StableResult<HostBuffer, EbpfError> {
886 let regions = self.get_regions();
887 let Some(region) = regions.get(region_index) else {
888 debug_assert!(self.find_region(vm_addr).is_none());
889 return StableResult::Err(self.generate_access_violation_for(
890 None,
891 access_type,
892 vm_addr,
893 len,
894 ));
895 };
896 let mut region = region.clone();
897 let max_len = regions
898 .get(region_index.saturating_add(1))
899 .map_or(u64::MAX, |next_region| next_region.vm_addr)
900 .saturating_sub(region.vm_addr);
901 (self.access_violation_handler)(&mut region, max_len, access_type, vm_addr, len);
902 if region.host_buffer().is_mutable() || access_type != AccessType::Store {
903 if let Some(host_buffer) = region.vm_to_host_buffer(vm_addr, len) {
904 if let Err(err) = unsafe { self.replace_region(region_index, region) } {
905 return StableResult::Err(err);
906 }
907 return StableResult::Ok(host_buffer);
908 }
909 }
910 let region = self.get_regions().get(region_index);
912 StableResult::Err(self.generate_access_violation_for(region, access_type, vm_addr, len))
913 }
914
915 #[inline]
917 pub fn load<T: Pod + Into<u64>>(&mut self, vm_addr: u64) -> ProgramResult {
918 let len = mem::size_of::<T>() as u64;
919 debug_assert!(len <= mem::size_of::<u64>() as u64);
920 debug_assert!(self.initialized);
921 let ptr = match self.map_with_access_violation_handler(AccessType::Load, vm_addr, len) {
922 StableResult::Err(e) => return ProgramResult::Err(e),
923 StableResult::Ok(buf) => buf.ptr(),
924 };
925 ProgramResult::Ok(unsafe {
926 ptr::read_unaligned::<T>(ptr.cast()).into()
935 })
936 }
937
938 #[inline]
940 pub fn store<T: Pod>(&mut self, value: T, vm_addr: u64) -> ProgramResult {
941 let len = mem::size_of::<T>() as u64;
942 debug_assert!(len <= mem::size_of::<u64>() as u64);
943 debug_assert!(self.initialized);
944 let ptr = match self.map_with_access_violation_handler(AccessType::Store, vm_addr, len) {
945 StableResult::Err(e) => return ProgramResult::Err(e),
946 StableResult::Ok(buf) => buf.ptr_mut(),
947 };
948 StableResult::Ok(unsafe {
949 ptr::write_unaligned::<T>(ptr.cast(), value);
958 0
959 })
960 }
961
962 #[inline(always)]
964 pub fn find_region(&self, vm_addr: u64) -> Option<(usize, &MemoryRegion)> {
965 debug_assert!(self.initialized);
966 match &self.ty {
967 MemoryMappingType::Aligned(inner) => inner.find_region(vm_addr),
968 MemoryMappingType::Unaligned(inner) => inner.find_region(vm_addr),
969 }
970 }
971
972 #[inline(always)]
974 pub fn get_regions(&self) -> &[MemoryRegion] {
975 match &self.ty {
976 MemoryMappingType::Aligned(inner) => &inner.regions,
977 MemoryMappingType::Unaligned(inner) => &inner.regions,
978 }
979 }
980
981 pub fn get_regions_mut(&mut self) -> &mut [MemoryRegion] {
987 self.initialized = false;
988
989 let regions = match &mut self.ty {
990 MemoryMappingType::Aligned(inner) => inner.regions.as_mut_slice(),
991 MemoryMappingType::Unaligned(inner) => &mut inner.regions,
992 };
993
994 regions
995 }
996
997 #[inline(always)]
1003 pub unsafe fn replace_region(
1004 &mut self,
1005 index: usize,
1006 region: MemoryRegion,
1007 ) -> Result<(), EbpfError> {
1008 debug_assert!(self.initialized);
1009 let regions = self.get_regions();
1010 let next_region_start = regions
1011 .get(index.saturating_add(1))
1012 .map_or(u64::MAX, |next_region| next_region.vm_addr);
1013 if index >= regions.len()
1014 || regions[index].vm_addr != region.vm_addr
1015 || region.vm_addr_range().end > next_region_start
1016 {
1017 return Err(EbpfError::InvalidMemoryRegion(index));
1018 }
1019 match &mut self.ty {
1020 MemoryMappingType::Aligned(inner) => inner.replace_region(index, region),
1021 MemoryMappingType::Unaligned(inner) => inner.replace_region(index, region),
1022 }
1023 }
1024
1025 pub fn initialize(&mut self) -> Result<(), EbpfError> {
1027 let result = match &mut self.ty {
1028 MemoryMappingType::Aligned(inner) => inner.initialize(),
1029 MemoryMappingType::Unaligned(inner) => inner.initialize(),
1030 };
1031 self.initialized = result.is_ok();
1032 result
1033 }
1034
1035 fn generate_access_violation(
1036 &self,
1037 access_type: AccessType,
1038 vm_addr: u64,
1039 len: u64,
1040 ) -> EbpfError {
1041 self.generate_access_violation_for(
1042 self.find_region(vm_addr).map(|(_, region)| region),
1043 access_type,
1044 vm_addr,
1045 len,
1046 )
1047 }
1048
1049 fn generate_access_violation_for(
1052 &self,
1053 region: Option<&MemoryRegion>,
1054 access_type: AccessType,
1055 vm_addr: u64,
1056 len: u64,
1057 ) -> EbpfError {
1058 let stack_frame = (vm_addr as i64)
1059 .saturating_sub(ebpf::MM_STACK_START as i64)
1060 .checked_div(self.stack_frame_size)
1061 .unwrap_or(0);
1062 if !self.sbpf_version.manual_stack_frame_bump()
1063 && (-1..self.max_call_depth.saturating_add(1)).contains(&stack_frame)
1064 {
1065 EbpfError::StackAccessViolation(access_type, vm_addr, len, stack_frame)
1066 } else {
1067 let region_name = match vm_addr & (!ebpf::MM_BYTECODE_START.saturating_sub(1)) {
1068 _ if region.map(|r| r.vm_addr_range().contains(&vm_addr)) != Some(true) => {
1069 "unallocated"
1070 }
1071 ebpf::MM_BYTECODE_START => "program",
1072 ebpf::MM_STACK_START => "stack",
1073 ebpf::MM_HEAP_START => "heap",
1074 ebpf::MM_INPUT_START => "input",
1075 _ => "allocated",
1076 };
1077 EbpfError::AccessViolation(access_type, vm_addr, len, region_name)
1078 }
1079 }
1080}
1081
1082#[derive(Debug)]
1084struct MappingCache {
1085 entries: [(Range<u64>, usize); MappingCache::SIZE],
1087 head: usize,
1092}
1093
1094impl MappingCache {
1095 const SIZE: usize = 4;
1097
1098 fn new() -> MappingCache {
1099 MappingCache {
1100 entries: array::from_fn(|_| (0..0, 0)),
1101 head: 0,
1102 }
1103 }
1104
1105 #[inline]
1106 fn find(&self, vm_addr: u64) -> Option<usize> {
1107 for i in 0..Self::SIZE {
1108 let index = self.head.wrapping_add(i) % Self::SIZE;
1109 let (vm_range, region_index) = unsafe { self.entries.get_unchecked(index) };
1112 if vm_range.contains(&vm_addr) {
1113 return Some(*region_index);
1114 }
1115 }
1116
1117 None
1118 }
1119
1120 #[inline]
1121 fn insert(&mut self, vm_range: Range<u64>, region_index: usize) {
1122 self.head = self.head.wrapping_sub(1) % Self::SIZE;
1123 unsafe { *self.entries.get_unchecked_mut(self.head) = (vm_range, region_index) };
1126 }
1127
1128 #[inline]
1129 fn flush(&mut self) {
1130 self.entries = array::from_fn(|_| (0..0, 0));
1131 self.head = 0;
1132 }
1133}
1134
1135#[cfg(test)]
1136mod test {
1137 use std::{cell::RefCell, rc::Rc};
1138 use test_utils::assert_error;
1139
1140 use super::*;
1141
1142 #[test]
1143 fn test_mapping_cache() {
1144 let mut cache = MappingCache::new();
1145 assert_eq!(cache.find(0), None);
1146
1147 let mut ranges = vec![10u64..20, 20..30, 30..40, 40..50];
1148 for (region, range) in ranges.iter().cloned().enumerate() {
1149 cache.insert(range, region);
1150 }
1151 for (region, range) in ranges.iter().enumerate() {
1152 if region > 0 {
1153 assert_eq!(cache.find(range.start - 1), Some(region - 1));
1154 } else {
1155 assert_eq!(cache.find(range.start - 1), None);
1156 }
1157 assert_eq!(cache.find(range.start), Some(region));
1158 assert_eq!(cache.find(range.start + 1), Some(region));
1159 assert_eq!(cache.find(range.end - 1), Some(region));
1160 if region < 3 {
1161 assert_eq!(cache.find(range.end), Some(region + 1));
1162 } else {
1163 assert_eq!(cache.find(range.end), None);
1164 }
1165 }
1166
1167 cache.insert(50..60, 4);
1168 ranges.push(50..60);
1169 for (region, range) in ranges.iter().enumerate() {
1170 if region == 0 {
1171 assert_eq!(cache.find(range.start), None);
1172 continue;
1173 }
1174 if region > 1 {
1175 assert_eq!(cache.find(range.start - 1), Some(region - 1));
1176 } else {
1177 assert_eq!(cache.find(range.start - 1), None);
1178 }
1179 assert_eq!(cache.find(range.start), Some(region));
1180 assert_eq!(cache.find(range.start + 1), Some(region));
1181 assert_eq!(cache.find(range.end - 1), Some(region));
1182 if region < 4 {
1183 assert_eq!(cache.find(range.end), Some(region + 1));
1184 } else {
1185 assert_eq!(cache.find(range.end), None);
1186 }
1187 }
1188 }
1189
1190 #[test]
1191 fn test_mapping_cache_flush() {
1192 let mut cache = MappingCache::new();
1193 assert_eq!(cache.find(0), None);
1194 cache.insert(0..10, 0);
1195 assert_eq!(cache.find(0), Some(0));
1196 cache.flush();
1197 assert_eq!(cache.find(0), None);
1198 }
1199
1200 #[test]
1201 fn test_map_empty() {
1202 for aligned_memory_mapping in [false, true] {
1203 let config = Config {
1204 aligned_memory_mapping,
1205 ..Config::default()
1206 };
1207 let m = unsafe { MemoryMapping::new(vec![], &config, SBPFVersion::V3) }.unwrap();
1208 assert_error!(
1209 m.map(AccessType::Load, ebpf::MM_REGION_SIZE, 8),
1210 "AccessViolation"
1211 );
1212 }
1213 }
1214
1215 #[test]
1216 fn test_gapped_map() {
1217 for aligned_memory_mapping in [false, true] {
1218 let config = Config {
1219 aligned_memory_mapping,
1220 ..Config::default()
1221 };
1222 let mut mem1 = [0xff; 8];
1223 let mem2 = [0; 8];
1224 let mut m = unsafe {
1225 MemoryMapping::new(
1226 vec![
1227 MemoryRegion::new(&raw const mem2[..], ebpf::MM_REGION_SIZE),
1228 MemoryRegion::new_gapped(&raw mut mem1[..], ebpf::MM_REGION_SIZE * 2, 2),
1229 ],
1230 &config,
1231 SBPFVersion::V3,
1232 )
1233 .unwrap()
1234 };
1235 for frame in 0..4 {
1236 let address = ebpf::MM_STACK_START + frame * 4;
1237 assert!(m.find_region(address).is_some());
1238 assert!(m.map(AccessType::Load, address, 2).is_ok());
1239 assert_error!(m.map(AccessType::Load, address + 2, 2), "AccessViolation");
1240 assert_eq!(m.load::<u16>(address).unwrap(), 0xFFFF);
1241 assert_error!(m.load::<u16>(address + 2), "AccessViolation");
1242 assert!(m.store::<u16>(0xFFFF, address).is_ok());
1243 assert_error!(m.store::<u16>(0xFFFF, address + 2), "AccessViolation");
1244 }
1245 }
1246 }
1247
1248 #[test]
1249 fn test_unaligned_map_overlap() {
1250 let config = Config {
1251 aligned_memory_mapping: false,
1252 ..Config::default()
1253 };
1254 let mem1 = [1, 2, 3, 4];
1255 let mem2 = [5, 6];
1256 assert_error!(
1257 unsafe {
1258 MemoryMapping::new(
1259 vec![
1260 MemoryRegion::new(&raw const mem1, ebpf::MM_REGION_SIZE),
1261 MemoryRegion::new(
1262 &raw const mem2,
1263 ebpf::MM_REGION_SIZE + mem1.len() as u64 - 1,
1264 ),
1265 ],
1266 &config,
1267 SBPFVersion::V3,
1268 )
1269 },
1270 "InvalidMemoryRegion(1)"
1271 );
1272 assert!(unsafe {
1273 MemoryMapping::new(
1274 vec![
1275 MemoryRegion::new(&raw const mem1, ebpf::MM_REGION_SIZE),
1276 MemoryRegion::new(&raw const mem2, ebpf::MM_REGION_SIZE + mem1.len() as u64),
1277 ],
1278 &config,
1279 SBPFVersion::V3,
1280 )
1281 }
1282 .is_ok());
1283 }
1284
1285 #[test]
1286 fn test_unaligned_map() {
1287 let config = Config {
1288 aligned_memory_mapping: false,
1289 ..Config::default()
1290 };
1291 let mut mem1 = [11];
1292 let mem2 = [22, 22];
1293 let mem3 = [33];
1294 let mem4 = [44, 44];
1295 let m = unsafe {
1296 MemoryMapping::new(
1297 vec![
1298 MemoryRegion::new(&raw mut mem1, ebpf::MM_REGION_SIZE),
1299 MemoryRegion::new(&raw const mem2, ebpf::MM_REGION_SIZE + mem1.len() as u64),
1300 MemoryRegion::new(
1301 &raw const mem3,
1302 ebpf::MM_REGION_SIZE + (mem1.len() + mem2.len()) as u64,
1303 ),
1304 MemoryRegion::new(
1305 &raw const mem4,
1306 ebpf::MM_REGION_SIZE + (mem1.len() + mem2.len() + mem3.len()) as u64,
1307 ),
1308 ],
1309 &config,
1310 SBPFVersion::V3,
1311 )
1312 .unwrap()
1313 };
1314
1315 assert_eq!(
1316 m.map(AccessType::Load, ebpf::MM_REGION_SIZE, 1)
1317 .unwrap()
1318 .ptr()
1319 .addr(),
1320 mem1.as_ptr().addr()
1321 );
1322
1323 assert_eq!(
1324 m.map(AccessType::Store, ebpf::MM_REGION_SIZE, 1)
1325 .unwrap()
1326 .ptr()
1327 .addr(),
1328 mem1.as_ptr().addr()
1329 );
1330
1331 assert_error!(
1332 m.map(AccessType::Load, ebpf::MM_REGION_SIZE, 2),
1333 "AccessViolation"
1334 );
1335
1336 assert_eq!(
1337 m.map(
1338 AccessType::Load,
1339 ebpf::MM_REGION_SIZE + mem1.len() as u64,
1340 1,
1341 )
1342 .unwrap()
1343 .ptr()
1344 .addr(),
1345 mem2.as_ptr().addr()
1346 );
1347
1348 assert_eq!(
1349 m.map(
1350 AccessType::Load,
1351 ebpf::MM_REGION_SIZE + (mem1.len() + mem2.len()) as u64,
1352 1,
1353 )
1354 .unwrap()
1355 .ptr()
1356 .addr(),
1357 mem3.as_ptr().addr()
1358 );
1359
1360 assert_eq!(
1361 m.map(
1362 AccessType::Load,
1363 ebpf::MM_REGION_SIZE + (mem1.len() + mem2.len() + mem3.len()) as u64,
1364 1,
1365 )
1366 .unwrap()
1367 .ptr()
1368 .addr(),
1369 mem4.as_ptr().addr()
1370 );
1371
1372 assert_error!(
1373 m.map(
1374 AccessType::Load,
1375 ebpf::MM_REGION_SIZE + (mem1.len() + mem2.len() + mem3.len() + mem4.len()) as u64,
1376 1,
1377 ),
1378 "AccessViolation"
1379 );
1380 }
1381
1382 #[test]
1383 fn test_unaligned_region() {
1384 let config = Config {
1385 aligned_memory_mapping: false,
1386 ..Config::default()
1387 };
1388
1389 let mut mem1 = [0xFF; 4];
1390 let mem2 = [0xDD; 4];
1391 let m = unsafe {
1392 MemoryMapping::new(
1393 vec![
1394 MemoryRegion::new(&raw mut mem1, ebpf::MM_REGION_SIZE),
1395 MemoryRegion::new(&raw const mem2, ebpf::MM_REGION_SIZE + 4),
1396 ],
1397 &config,
1398 SBPFVersion::V3,
1399 )
1400 .unwrap()
1401 };
1402 assert!(m.find_region(ebpf::MM_REGION_SIZE - 1).is_none());
1403 assert_eq!(
1404 HostBuffer::Mutable(&raw mut mem1[..]),
1405 m.find_region(ebpf::MM_REGION_SIZE).unwrap().1.host,
1406 );
1407 assert_eq!(
1408 HostBuffer::Mutable(&raw mut mem1[..]),
1409 m.find_region(ebpf::MM_REGION_SIZE + 3).unwrap().1.host,
1410 );
1411 assert_eq!(
1412 HostBuffer::Immutable(&raw const mem2[..]),
1413 m.find_region(ebpf::MM_REGION_SIZE + 4).unwrap().1.host,
1414 );
1415 assert_eq!(
1416 HostBuffer::Immutable(&raw const mem2[..]),
1417 m.find_region(ebpf::MM_REGION_SIZE + 7).unwrap().1.host,
1418 );
1419 assert!(m.find_region(ebpf::MM_REGION_SIZE + 8).is_some());
1420 }
1421
1422 #[test]
1423 fn test_aligned_region() {
1424 let config = Config {
1425 aligned_memory_mapping: true,
1426 ..Config::default()
1427 };
1428
1429 let mut mem1 = [0xFF; 4];
1430 let mem2 = [0xDD; 4];
1431 let m = unsafe {
1432 MemoryMapping::new(
1433 vec![
1434 MemoryRegion::new(&raw mut mem1, ebpf::MM_REGION_SIZE),
1435 MemoryRegion::new(&raw const mem2, ebpf::MM_REGION_SIZE * 2),
1436 ],
1437 &config,
1438 SBPFVersion::V4,
1439 )
1440 .unwrap()
1441 };
1442 assert_eq!(m.find_region(ebpf::MM_REGION_SIZE - 1).unwrap().1.len(), 0);
1443 assert_eq!(
1444 HostBuffer::Mutable(&raw mut mem1[..]),
1445 m.find_region(ebpf::MM_REGION_SIZE).unwrap().1.host,
1446 );
1447 assert_eq!(
1448 HostBuffer::Mutable(&raw mut mem1[..]),
1449 m.find_region(ebpf::MM_REGION_SIZE + 3).unwrap().1.host,
1450 );
1451 assert!(m.find_region(ebpf::MM_REGION_SIZE + 4).is_some());
1452 assert_eq!(
1453 HostBuffer::Immutable(&raw const mem2[..]),
1454 m.find_region(ebpf::MM_REGION_SIZE * 2).unwrap().1.host,
1455 );
1456 assert_eq!(
1457 HostBuffer::Immutable(&raw const mem2[..]),
1458 m.find_region(ebpf::MM_REGION_SIZE * 2 + 3).unwrap().1.host,
1459 );
1460 assert!(m.find_region(ebpf::MM_REGION_SIZE * 3 + 4).is_none());
1461 }
1462
1463 #[test]
1464 fn test_unaligned_map_load() {
1465 let config = Config {
1466 aligned_memory_mapping: false,
1467 ..Config::default()
1468 };
1469 let mem1 = [0x11, 0x22];
1470 let mem2 = [0x33];
1471 let mut m = unsafe {
1472 MemoryMapping::new(
1473 vec![
1474 MemoryRegion::new(&raw const mem1, ebpf::MM_REGION_SIZE),
1475 MemoryRegion::new(&raw const mem2, ebpf::MM_REGION_SIZE + mem1.len() as u64),
1476 ],
1477 &config,
1478 SBPFVersion::V3,
1479 )
1480 .unwrap()
1481 };
1482
1483 assert_eq!(m.load::<u16>(ebpf::MM_REGION_SIZE).unwrap(), 0x2211);
1484 assert_error!(m.load::<u32>(ebpf::MM_REGION_SIZE), "AccessViolation");
1485 assert_error!(m.load::<u32>(ebpf::MM_REGION_SIZE + 4), "AccessViolation");
1486 }
1487
1488 #[test]
1489 fn test_unaligned_map_store() {
1490 let config = Config {
1491 aligned_memory_mapping: false,
1492 ..Config::default()
1493 };
1494 let mut mem1 = [0xff, 0xff];
1495 let mut mem2 = [0xff];
1496 let mut m = unsafe {
1497 MemoryMapping::new(
1498 vec![
1499 MemoryRegion::new(&raw mut mem1, ebpf::MM_REGION_SIZE),
1500 MemoryRegion::new(&raw mut mem2, ebpf::MM_REGION_SIZE + mem1.len() as u64),
1501 ],
1502 &config,
1503 SBPFVersion::V3,
1504 )
1505 .unwrap()
1506 };
1507
1508 m.store(0x1122u16, ebpf::MM_REGION_SIZE).unwrap();
1509 assert_eq!(m.load::<u16>(ebpf::MM_REGION_SIZE).unwrap(), 0x1122);
1510
1511 assert_error!(
1512 m.store(0x33445566u32, ebpf::MM_REGION_SIZE),
1513 "AccessViolation"
1514 );
1515 }
1516
1517 #[test]
1518 fn test_unaligned_map_store_out_of_bounds() {
1519 let config = Config {
1520 aligned_memory_mapping: false,
1521 ..Config::default()
1522 };
1523
1524 let mut mem1 = [0xFF];
1525 let mut m = unsafe {
1526 MemoryMapping::new(
1527 vec![MemoryRegion::new(&raw mut mem1, ebpf::MM_REGION_SIZE)],
1528 &config,
1529 SBPFVersion::V3,
1530 )
1531 .unwrap()
1532 };
1533 m.store(0x11u8, ebpf::MM_REGION_SIZE).unwrap();
1534 assert_error!(m.store(0x11u8, ebpf::MM_REGION_SIZE - 1), "AccessViolation");
1535 assert_error!(m.store(0x11u8, ebpf::MM_REGION_SIZE + 1), "AccessViolation");
1536 assert_error!(m.store(0x11u8, ebpf::MM_REGION_SIZE + 2), "AccessViolation");
1539
1540 let mut mem1 = [0xFF; 4];
1541 let mut mem2 = [0xDD; 4];
1542 let mut m = unsafe {
1543 MemoryMapping::new(
1544 vec![
1545 MemoryRegion::new(&raw mut mem1, ebpf::MM_REGION_SIZE),
1546 MemoryRegion::new(&raw mut mem2, ebpf::MM_REGION_SIZE + 4),
1547 ],
1548 &config,
1549 SBPFVersion::V3,
1550 )
1551 .unwrap()
1552 };
1553 assert_error!(
1554 m.store(0x1122334455667788u64, ebpf::MM_REGION_SIZE),
1555 "AccessViolation"
1556 );
1557 }
1558
1559 #[test]
1560 fn test_unaligned_map_load_out_of_bounds() {
1561 let config = Config {
1562 aligned_memory_mapping: false,
1563 ..Config::default()
1564 };
1565
1566 let mem1 = [0xff];
1567 let mut m = unsafe {
1568 MemoryMapping::new(
1569 vec![MemoryRegion::new(&raw const mem1, ebpf::MM_REGION_SIZE)],
1570 &config,
1571 SBPFVersion::V3,
1572 )
1573 .unwrap()
1574 };
1575 assert_eq!(m.load::<u8>(ebpf::MM_REGION_SIZE).unwrap(), 0xff);
1576 assert_error!(m.load::<u8>(ebpf::MM_REGION_SIZE - 1), "AccessViolation");
1577 assert_error!(m.load::<u8>(ebpf::MM_REGION_SIZE + 1), "AccessViolation");
1578 assert_error!(m.load::<u8>(ebpf::MM_REGION_SIZE + 2), "AccessViolation");
1579
1580 let mem1 = [0xFF; 4];
1581 let mem2 = [0xDD; 4];
1582 let mut m = unsafe {
1583 MemoryMapping::new(
1584 vec![
1585 MemoryRegion::new(&raw const mem1, ebpf::MM_REGION_SIZE),
1586 MemoryRegion::new(&raw const mem2, ebpf::MM_REGION_SIZE + 4),
1587 ],
1588 &config,
1589 SBPFVersion::V3,
1590 )
1591 .unwrap()
1592 };
1593 assert_error!(m.load::<u64>(ebpf::MM_REGION_SIZE), "AccessViolation");
1594 }
1595
1596 #[test]
1597 #[should_panic(expected = "AccessViolation")]
1598 fn test_store_readonly() {
1599 let config = Config {
1600 aligned_memory_mapping: false,
1601 ..Config::default()
1602 };
1603 let mut mem1 = [0xff, 0xff];
1604 let mem2 = [0xff, 0xff];
1605 let mut m = unsafe {
1606 MemoryMapping::new(
1607 vec![
1608 MemoryRegion::new(&raw mut mem1, ebpf::MM_REGION_SIZE),
1609 MemoryRegion::new(&raw const mem2, ebpf::MM_REGION_SIZE + mem1.len() as u64),
1610 ],
1611 &config,
1612 SBPFVersion::V3,
1613 )
1614 .unwrap()
1615 };
1616 m.store(0x11223344, ebpf::MM_REGION_SIZE).unwrap();
1617 }
1618
1619 #[test]
1620 fn test_unaligned_map_replace_region() {
1621 let config = Config {
1622 aligned_memory_mapping: false,
1623 ..Config::default()
1624 };
1625 let mem1 = [11];
1626 let mem2 = [22, 22];
1627 let mem3 = [33];
1628 let mut m = unsafe {
1629 MemoryMapping::new(
1630 vec![
1631 MemoryRegion::new(&raw const mem1, ebpf::MM_REGION_SIZE),
1632 MemoryRegion::new(&raw const mem2, ebpf::MM_REGION_SIZE + mem1.len() as u64),
1633 ],
1634 &config,
1635 SBPFVersion::V3,
1636 )
1637 .unwrap()
1638 };
1639
1640 assert_eq!(
1641 m.map(AccessType::Load, ebpf::MM_REGION_SIZE, 1)
1642 .unwrap()
1643 .ptr()
1644 .addr(),
1645 mem1.as_ptr().addr()
1646 );
1647
1648 assert_eq!(
1649 m.map(
1650 AccessType::Load,
1651 ebpf::MM_REGION_SIZE + mem1.len() as u64,
1652 1,
1653 )
1654 .unwrap()
1655 .ptr()
1656 .addr(),
1657 mem2.as_ptr().addr()
1658 );
1659
1660 assert_error!(
1661 unsafe {
1662 m.replace_region(
1663 2,
1664 MemoryRegion::new(&raw const mem3, ebpf::MM_REGION_SIZE + mem1.len() as u64),
1665 )
1666 },
1667 "InvalidMemoryRegion(2)"
1668 );
1669
1670 let region_index = m
1671 .get_regions()
1672 .iter()
1673 .position(|mem| mem.vm_addr == ebpf::MM_REGION_SIZE + mem1.len() as u64)
1674 .unwrap();
1675
1676 assert_error!(
1678 unsafe {
1679 m.replace_region(
1680 region_index,
1681 MemoryRegion::new(
1682 &raw const mem3,
1683 ebpf::MM_REGION_SIZE + mem1.len() as u64 + 1,
1684 ),
1685 )
1686 },
1687 "InvalidMemoryRegion({})",
1688 region_index
1689 );
1690
1691 unsafe {
1692 m.replace_region(
1693 region_index,
1694 MemoryRegion::new(&raw const mem3, ebpf::MM_REGION_SIZE + mem1.len() as u64),
1695 )
1696 .unwrap()
1697 };
1698
1699 assert_eq!(
1700 m.map(
1701 AccessType::Load,
1702 ebpf::MM_REGION_SIZE + mem1.len() as u64,
1703 1,
1704 )
1705 .unwrap()
1706 .ptr()
1707 .addr(),
1708 mem3.as_ptr().addr()
1709 );
1710 }
1711
1712 #[test]
1713 fn test_aligned_map_replace_region() {
1714 let config = Config {
1715 aligned_memory_mapping: true,
1716 ..Config::default()
1717 };
1718 let mem1 = [11];
1719 let mem2 = [22, 22];
1720 let mem3 = [33, 33];
1721 let mut m = unsafe {
1722 MemoryMapping::new(
1723 vec![
1724 MemoryRegion::new(&raw const mem1, ebpf::MM_REGION_SIZE),
1725 MemoryRegion::new(&raw const mem2, ebpf::MM_REGION_SIZE * 2),
1726 ],
1727 &config,
1728 SBPFVersion::V4,
1729 )
1730 .unwrap()
1731 };
1732
1733 assert_eq!(
1734 m.map(AccessType::Load, ebpf::MM_REGION_SIZE * 2, 1)
1735 .unwrap()
1736 .ptr()
1737 .addr(),
1738 mem2.as_ptr().addr()
1739 );
1740
1741 assert_error!(
1743 unsafe {
1744 m.replace_region(
1745 3,
1746 MemoryRegion::new(&raw const mem3, ebpf::MM_REGION_SIZE * 2),
1747 )
1748 },
1749 "InvalidMemoryRegion(3)"
1750 );
1751
1752 assert_error!(
1754 unsafe {
1755 m.replace_region(
1756 2,
1757 MemoryRegion::new(&raw const mem3, ebpf::MM_REGION_SIZE * 3),
1758 )
1759 },
1760 "InvalidMemoryRegion(2)"
1761 );
1762
1763 assert_error!(
1765 unsafe {
1766 m.replace_region(
1767 2,
1768 MemoryRegion::new(&raw const mem3, ebpf::MM_REGION_SIZE * 3 - 1),
1769 )
1770 },
1771 "InvalidMemoryRegion(2)"
1772 );
1773
1774 unsafe {
1775 m.replace_region(
1776 2,
1777 MemoryRegion::new(&raw const mem3, ebpf::MM_REGION_SIZE * 2),
1778 )
1779 .unwrap()
1780 };
1781
1782 assert_eq!(
1783 m.map(AccessType::Load, ebpf::MM_REGION_SIZE * 2, 1)
1784 .unwrap()
1785 .ptr()
1786 .addr(),
1787 mem3.as_ptr().addr()
1788 );
1789 }
1790
1791 #[test]
1792 fn test_access_violation_handler_map() {
1793 for aligned_memory_mapping in [true, false] {
1794 let config = Config {
1795 aligned_memory_mapping,
1796 ..Config::default()
1797 };
1798 let original = [11, 22];
1799 let copied = Rc::new(RefCell::new(Vec::new()));
1800 let mut regions = vec![MemoryRegion::new(&raw const original, ebpf::MM_REGION_SIZE)];
1801 regions[0].access_violation_handler_payload = Some(0);
1802
1803 let c = Rc::clone(&copied);
1804 let mut m = unsafe {
1805 MemoryMapping::new_with_access_violation_handler(
1806 regions,
1807 &config,
1808 SBPFVersion::V3,
1809 Box::new(move |region, _, _, _, _| {
1810 let mut vec = c.borrow_mut();
1811 vec.extend_from_slice(&original);
1812 region.redirect(&raw mut vec[..]);
1813 }),
1814 )
1815 .unwrap()
1816 };
1817
1818 assert_eq!(
1819 m.map_with_access_violation_handler(AccessType::Load, ebpf::MM_REGION_SIZE, 1)
1820 .unwrap()
1821 .ptr()
1822 .addr(),
1823 original.as_ptr().addr()
1824 );
1825 assert_eq!(
1826 m.map_with_access_violation_handler(AccessType::Store, ebpf::MM_REGION_SIZE, 1)
1827 .unwrap()
1828 .ptr()
1829 .addr(),
1830 copied.borrow().as_ptr().addr()
1831 );
1832 }
1833 }
1834
1835 #[test]
1836 fn test_access_violation_handler_load_store() {
1837 for aligned_memory_mapping in [true, false] {
1838 let config = Config {
1839 aligned_memory_mapping,
1840 ..Config::default()
1841 };
1842 let original = [11, 22];
1843 let copied = Rc::new(RefCell::new(Vec::new()));
1844 let mut regions = vec![MemoryRegion::new(&raw const original, ebpf::MM_REGION_SIZE)];
1845 regions[0].access_violation_handler_payload = Some(0);
1846
1847 let c = Rc::clone(&copied);
1848 let mut m = unsafe {
1849 MemoryMapping::new_with_access_violation_handler(
1850 regions,
1851 &config,
1852 SBPFVersion::V3,
1853 Box::new(move |region, _, _, _, _| {
1854 let mut vec = c.borrow_mut();
1855 vec.extend_from_slice(&original);
1856 region.redirect(&raw mut vec[..]);
1857 }),
1858 )
1859 .unwrap()
1860 };
1861
1862 assert_eq!(
1863 m.map(AccessType::Load, ebpf::MM_REGION_SIZE, 1)
1864 .unwrap()
1865 .ptr()
1866 .addr(),
1867 original.as_ptr().addr()
1868 );
1869
1870 assert_eq!(m.load::<u8>(ebpf::MM_REGION_SIZE).unwrap(), 11);
1871 assert_eq!(m.load::<u8>(ebpf::MM_REGION_SIZE + 1).unwrap(), 22);
1872 assert!(copied.borrow().is_empty());
1873
1874 m.store(33u8, ebpf::MM_REGION_SIZE).unwrap();
1875 assert_eq!(original[0], 11);
1876 assert_eq!(m.load::<u8>(ebpf::MM_REGION_SIZE).unwrap(), 33);
1877 assert_eq!(m.load::<u8>(ebpf::MM_REGION_SIZE + 1).unwrap(), 22);
1878 }
1879 }
1880
1881 #[test]
1882 fn test_access_violation_handler_region_id() {
1883 for aligned_memory_mapping in [true, false] {
1884 let config = Config {
1885 aligned_memory_mapping,
1886 ..Config::default()
1887 };
1888 let original1 = [11, 22];
1889 let original2 = [33, 44];
1890 let copied = Rc::new(RefCell::new(Vec::new()));
1891
1892 let mut regions = vec![
1893 MemoryRegion::new(&raw const original1, ebpf::MM_REGION_SIZE),
1894 MemoryRegion::new(&raw const original2, ebpf::MM_REGION_SIZE * 2),
1895 ];
1896 regions[0].access_violation_handler_payload = Some(42);
1897
1898 let c = Rc::clone(&copied);
1899 let mut m = unsafe {
1900 MemoryMapping::new_with_access_violation_handler(
1901 regions,
1902 &config,
1903 SBPFVersion::V3,
1904 Box::new(move |region, _, _, _, _| {
1905 assert_eq!(region.access_violation_handler_payload, Some(42));
1908 let mut vec = c.borrow_mut();
1909 vec.extend_from_slice(&original1);
1910 region.redirect(&raw mut vec[..]);
1911 }),
1912 )
1913 .unwrap()
1914 };
1915
1916 m.store(55u8, ebpf::MM_REGION_SIZE).unwrap();
1917 assert_eq!(original1[0], 11);
1918 assert_eq!(m.load::<u8>(ebpf::MM_REGION_SIZE).unwrap(), 55);
1919 }
1920 }
1921
1922 #[test]
1923 #[should_panic(expected = "AccessViolation")]
1924 fn test_map_access_violation_handler_error() {
1925 let config = Config::default();
1926 let original = [11, 22];
1927
1928 let m = unsafe {
1929 MemoryMapping::new_with_access_violation_handler(
1930 vec![MemoryRegion::new(&raw const original, ebpf::MM_REGION_SIZE)],
1931 &config,
1932 SBPFVersion::V4,
1933 Box::new(default_access_violation_handler),
1934 )
1935 .unwrap()
1936 };
1937
1938 m.map(AccessType::Store, ebpf::MM_REGION_SIZE, 1).unwrap();
1939 }
1940
1941 #[test]
1942 #[should_panic(expected = "AccessViolation")]
1943 fn test_store_access_violation_handler_error() {
1944 let config = Config::default();
1945 let original = [11, 22];
1946
1947 let mut m = unsafe {
1948 MemoryMapping::new_with_access_violation_handler(
1949 vec![MemoryRegion::new(&raw const original, ebpf::MM_REGION_SIZE)],
1950 &config,
1951 SBPFVersion::V4,
1952 Box::new(default_access_violation_handler),
1953 )
1954 .unwrap()
1955 };
1956
1957 m.store(33u8, ebpf::MM_REGION_SIZE).unwrap();
1958 }
1959
1960 #[test]
1961 fn test_access_violation_region_identification() {
1962 let config = Config::default();
1963 let original = [11, 22];
1964 let region = 0x10_0000_0000;
1965 let mut m = unsafe {
1966 MemoryMapping::new(
1967 vec![MemoryRegion::new(&raw const original, region)],
1968 &config,
1969 SBPFVersion::V4,
1970 )
1971 .unwrap()
1972 };
1973 let store_err_inbound = m.store(33u8, region).unwrap_err();
1974 assert_eq!(
1975 store_err_inbound.to_string(),
1976 "Access violation writing 1 bytes at address 0x1000000000 (in allocated region)"
1977 );
1978 let store_err_oob = m.load::<u64>(region + 3).unwrap_err();
1979 assert_eq!(
1980 store_err_oob.to_string(),
1981 "Access violation reading 8 bytes at address 0x1000000003 (in unallocated region)"
1982 );
1983 }
1984
1985 #[test]
1986 fn v4_aligned_mapping() {
1987 let config = Config {
1988 aligned_memory_mapping: false,
1989 ..Config::default()
1990 };
1991
1992 let mem = [11, 12];
1993 let mapping = unsafe {
1994 MemoryMapping::new_with_access_violation_handler(
1995 vec![MemoryRegion::new(&raw const mem, ebpf::MM_REGION_SIZE)],
1996 &config,
1997 SBPFVersion::V4,
1998 Box::new(default_access_violation_handler),
1999 )
2000 .unwrap()
2001 };
2002
2003 assert!(matches!(mapping.ty, MemoryMappingType::Aligned(_)));
2004 }
2005}