bpf_probe_read.rs 3.9 KB

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