bpf_probe_read.rs 4.0 KB

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