bpf_probe_read.rs 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #![no_std]
  2. #![no_main]
  3. use aya_bpf::{
  4. helpers::{bpf_probe_read_kernel_str_bytes, bpf_probe_read_user_str_bytes},
  5. macros::{map, uprobe},
  6. maps::Array,
  7. programs::ProbeContext,
  8. };
  9. const RESULT_BUF_LEN: usize = 1024;
  10. macro_rules! read_str_bytes {
  11. ($fun:ident, $ptr:expr, $len:expr $(,)?) => {
  12. let Some(ptr) = RESULT.get_ptr_mut(0) else {
  13. return;
  14. };
  15. let TestResult {
  16. did_error,
  17. len,
  18. buf,
  19. } = unsafe { &mut *ptr };
  20. // $len comes from ctx.arg(1) so it's dynamic and the verifier
  21. // doesn't see any bounds. We do $len.min(RESULT_BUF_LEN) here to
  22. // ensure that the verifier can see the upper bound, or you get:
  23. //
  24. // 18: (79) r7 = *(u64 *)(r7 +8) ; R7_w=scalar()
  25. // [snip]
  26. // 27: (bf) r2 = r7 ;
  27. // R2_w=scalar(id=2,umax=9223372036854775807,var_off=(0x0; 0x7fffffffffffffff)) [snip]
  28. // 28: (85) call bpf_probe_read_user_str#114
  29. // R2 unbounded memory access, use 'var &= const' or 'if (var < const)'
  30. let Some(buf) = buf.get_mut(..$len) else {
  31. return;
  32. };
  33. match unsafe { $fun($ptr, buf) } {
  34. Ok(s) => {
  35. *len = s.len();
  36. }
  37. Err(_) => {
  38. *did_error = 1;
  39. }
  40. }
  41. };
  42. }
  43. #[repr(C)]
  44. struct TestResult {
  45. did_error: u64,
  46. len: usize,
  47. buf: [u8; RESULT_BUF_LEN],
  48. }
  49. #[map]
  50. static RESULT: Array<TestResult> = Array::with_max_entries(1, 0);
  51. #[map]
  52. static KERNEL_BUFFER: Array<[u8; RESULT_BUF_LEN]> = Array::with_max_entries(1, 0);
  53. #[uprobe]
  54. pub fn test_bpf_probe_read_user_str_bytes(ctx: ProbeContext) {
  55. read_str_bytes!(
  56. bpf_probe_read_user_str_bytes,
  57. match ctx.arg::<*const u8>(0) {
  58. Some(p) => p,
  59. _ => return,
  60. },
  61. match ctx.arg::<usize>(1) {
  62. Some(p) => p,
  63. _ => return,
  64. },
  65. );
  66. }
  67. #[uprobe]
  68. pub fn test_bpf_probe_read_kernel_str_bytes(ctx: ProbeContext) {
  69. read_str_bytes!(
  70. bpf_probe_read_kernel_str_bytes,
  71. match KERNEL_BUFFER.get_ptr(0) {
  72. Some(p) => p as *const u8,
  73. _ => return,
  74. },
  75. match ctx.arg::<usize>(0) {
  76. Some(p) => p,
  77. _ => return,
  78. },
  79. );
  80. }
  81. #[cfg(not(test))]
  82. #[panic_handler]
  83. fn panic(_info: &core::panic::PanicInfo) -> ! {
  84. loop {}
  85. }