4
0

bpf_probe_read.rs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. use aya::{maps::Array, programs::UProbe, Ebpf};
  2. use test_log::test;
  3. const RESULT_BUF_LEN: usize = 1024;
  4. #[derive(Copy, Clone)]
  5. #[repr(C)]
  6. struct TestResult {
  7. buf: [u8; RESULT_BUF_LEN],
  8. len: Option<Result<usize, i64>>,
  9. }
  10. unsafe impl aya::Pod for TestResult {}
  11. #[test]
  12. fn bpf_probe_read_user_str_bytes() {
  13. let bpf = set_user_buffer(b"foo\0", RESULT_BUF_LEN);
  14. assert_eq!(result_bytes(&bpf), b"foo");
  15. }
  16. #[test]
  17. fn bpf_probe_read_user_str_bytes_truncate() {
  18. let s = vec![b'a'; RESULT_BUF_LEN];
  19. let bpf = set_user_buffer(&s, RESULT_BUF_LEN);
  20. // The kernel truncates the string and the last byte is the null terminator
  21. assert_eq!(result_bytes(&bpf), &s[..RESULT_BUF_LEN - 1]);
  22. }
  23. #[test]
  24. fn bpf_probe_read_user_str_bytes_empty_string() {
  25. let bpf = set_user_buffer(b"\0", RESULT_BUF_LEN);
  26. assert_eq!(result_bytes(&bpf), b"");
  27. }
  28. #[test]
  29. fn bpf_probe_read_user_str_bytes_empty_dest() {
  30. let bpf = set_user_buffer(b"foo\0", 0);
  31. assert_eq!(result_bytes(&bpf), b"");
  32. }
  33. #[test]
  34. fn bpf_probe_read_kernel_str_bytes() {
  35. let bpf = set_kernel_buffer(b"foo\0", RESULT_BUF_LEN);
  36. assert_eq!(result_bytes(&bpf), b"foo");
  37. }
  38. #[test]
  39. fn bpf_probe_read_kernel_str_bytes_truncate() {
  40. let s = vec![b'a'; RESULT_BUF_LEN];
  41. let bpf = set_kernel_buffer(&s, RESULT_BUF_LEN);
  42. // The kernel truncates the string and the last byte is the null terminator
  43. assert_eq!(result_bytes(&bpf), &s[..RESULT_BUF_LEN - 1]);
  44. }
  45. #[test]
  46. fn bpf_probe_read_kernel_str_bytes_empty_string() {
  47. let bpf = set_kernel_buffer(b"\0", RESULT_BUF_LEN);
  48. assert_eq!(result_bytes(&bpf), b"");
  49. }
  50. #[test]
  51. fn bpf_probe_read_kernel_str_bytes_empty_dest() {
  52. let bpf = set_kernel_buffer(b"foo\0", 0);
  53. assert_eq!(result_bytes(&bpf), b"");
  54. }
  55. fn set_user_buffer(bytes: &[u8], dest_len: usize) -> Ebpf {
  56. let bpf = load_and_attach_uprobe(
  57. "test_bpf_probe_read_user_str_bytes",
  58. "trigger_bpf_probe_read_user",
  59. crate::BPF_PROBE_READ,
  60. );
  61. trigger_bpf_probe_read_user(bytes.as_ptr(), dest_len);
  62. bpf
  63. }
  64. fn set_kernel_buffer(bytes: &[u8], dest_len: usize) -> Ebpf {
  65. let mut bpf = load_and_attach_uprobe(
  66. "test_bpf_probe_read_kernel_str_bytes",
  67. "trigger_bpf_probe_read_kernel",
  68. crate::BPF_PROBE_READ,
  69. );
  70. set_kernel_buffer_element(&mut bpf, bytes);
  71. trigger_bpf_probe_read_kernel(dest_len);
  72. bpf
  73. }
  74. fn set_kernel_buffer_element(bpf: &mut Ebpf, bytes: &[u8]) {
  75. let mut bytes = bytes.to_vec();
  76. bytes.resize(1024, 0xFF);
  77. let bytes: [u8; 1024] = bytes.try_into().unwrap();
  78. let mut m = Array::<_, [u8; 1024]>::try_from(bpf.map_mut("KERNEL_BUFFER").unwrap()).unwrap();
  79. m.set(0, bytes, 0).unwrap();
  80. }
  81. #[track_caller]
  82. fn result_bytes(bpf: &Ebpf) -> Vec<u8> {
  83. let m = Array::<_, TestResult>::try_from(bpf.map("RESULT").unwrap()).unwrap();
  84. let TestResult { buf, len } = m.get(&0, 0).unwrap();
  85. let len = len.unwrap();
  86. let len = len.unwrap();
  87. // assert that the buffer is always null terminated
  88. assert_eq!(buf[len], 0);
  89. buf[..len].to_vec()
  90. }
  91. fn load_and_attach_uprobe(prog_name: &str, func_name: &str, bytes: &[u8]) -> Ebpf {
  92. let mut bpf = Ebpf::load(bytes).unwrap();
  93. let prog: &mut UProbe = bpf.program_mut(prog_name).unwrap().try_into().unwrap();
  94. prog.load().unwrap();
  95. prog.attach(Some(func_name), 0, "/proc/self/exe", None)
  96. .unwrap();
  97. bpf
  98. }
  99. #[no_mangle]
  100. #[inline(never)]
  101. pub extern "C" fn trigger_bpf_probe_read_user(string: *const u8, len: usize) {
  102. core::hint::black_box((string, len));
  103. }
  104. #[no_mangle]
  105. #[inline(never)]
  106. pub extern "C" fn trigger_bpf_probe_read_kernel(len: usize) {
  107. core::hint::black_box(len);
  108. }