From f51ab800758689a67c312742ffdf9116e1e178c0 Mon Sep 17 00:00:00 2001
From: Tamir Duberstein <tamird@gmail.com>
Date: Sun, 2 Mar 2025 08:25:52 -0500
Subject: [PATCH] perf_buffer: attempt to preserve provenance

In tests, provide write provenance.
---
 aya/src/maps/perf/perf_buffer.rs | 216 ++++++++++++++++---------------
 1 file changed, 113 insertions(+), 103 deletions(-)

diff --git a/aya/src/maps/perf/perf_buffer.rs b/aya/src/maps/perf/perf_buffer.rs
index e04e1e2c..3fa4b0dd 100644
--- a/aya/src/maps/perf/perf_buffer.rs
+++ b/aya/src/maps/perf/perf_buffer.rs
@@ -145,28 +145,24 @@ impl PerfBuffer {
             return Err(PerfBufferError::NoBuffers);
         }
         let header = self.buf().as_ptr();
-        let base = header as usize + self.page_size;
+        let base = unsafe { header.byte_add(self.page_size) };
 
         let mut events = Events { read: 0, lost: 0 };
         let mut buf_n = 0;
 
-        let fill_buf = |start_off, base, mmap_size, out_buf: &mut [u8]| {
+        let fill_buf = |start_off, base: *const u8, mmap_size, out_buf: &mut [u8]| {
             let len = out_buf.len();
 
             let end = (start_off + len) % mmap_size;
             let start = start_off % mmap_size;
 
             if start < end {
-                out_buf.copy_from_slice(unsafe {
-                    slice::from_raw_parts((base + start) as *const u8, len)
-                });
+                out_buf.copy_from_slice(unsafe { slice::from_raw_parts(base.add(start), len) });
             } else {
                 let size = mmap_size - start;
                 unsafe {
-                    out_buf[..size]
-                        .copy_from_slice(slice::from_raw_parts((base + start) as *const u8, size));
-                    out_buf[size..]
-                        .copy_from_slice(slice::from_raw_parts(base as *const u8, len - size));
+                    out_buf[..size].copy_from_slice(slice::from_raw_parts(base.add(start), size));
+                    out_buf[size..].copy_from_slice(slice::from_raw_parts(base, len - size));
                 }
             }
         };
@@ -227,11 +223,11 @@ impl PerfBuffer {
             let buf = &mut buffers[buf_n];
 
             let event_start = tail % self.size;
-            let event =
-                unsafe { ptr::read_unaligned((base + event_start) as *const perf_event_header) };
+            let event: perf_event_header =
+                unsafe { ptr::read_unaligned(base.byte_add(event_start).cast()) };
             let event_size = event.size as usize;
 
-            match read_event(event_start, event.type_, base, buf) {
+            match read_event(event_start, event.type_, base.cast(), buf) {
                 Ok(Some((read, lost))) => {
                     if read > 0 {
                         buf_n += 1;
@@ -290,14 +286,15 @@ mod tests {
         data: [u8; PAGE_SIZE * 2],
     }
 
-    fn fake_mmap(buf: &MMappedBuf) {
+    fn fake_mmap(buf: &mut MMappedBuf) {
+        let buf: *mut _ = buf;
         override_syscall(|call| match call {
             Syscall::PerfEventOpen { .. } | Syscall::PerfEventIoctl { .. } => {
                 Ok(crate::MockableFd::mock_signed_fd().into())
             }
             call => panic!("unexpected syscall: {:?}", call),
         });
-        TEST_MMAP_RET.with(|ret| *ret.borrow_mut() = buf as *const _ as *mut _);
+        TEST_MMAP_RET.with(|ret| *ret.borrow_mut() = buf.cast());
     }
 
     #[test]
@@ -318,27 +315,25 @@ mod tests {
 
     #[test]
     fn test_no_out_bufs() {
-        let mmapped_buf = MMappedBuf {
+        let mut mmapped_buf = MMappedBuf {
             data: [0; PAGE_SIZE * 2],
         };
-        fake_mmap(&mmapped_buf);
 
+        fake_mmap(&mut mmapped_buf);
         let mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
+
         assert_matches!(buf.read_events(&mut []), Err(PerfBufferError::NoBuffers))
     }
 
     #[test]
-    #[cfg_attr(
-        miri,
-        ignore = "`unsafe { (*header).data_tail = tail as u64 };` is attempting a write access using using a tag that only grants SharedReadOnly permission"
-    )]
     fn test_no_events() {
-        let mmapped_buf = MMappedBuf {
+        let mut mmapped_buf = MMappedBuf {
             data: [0; PAGE_SIZE * 2],
         };
-        fake_mmap(&mmapped_buf);
 
+        fake_mmap(&mut mmapped_buf);
         let mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
+
         let out_buf = BytesMut::with_capacity(4);
         assert_eq!(
             buf.read_events(&mut [out_buf]).unwrap(),
@@ -346,13 +341,18 @@ mod tests {
         );
     }
 
+    fn write<T: Debug>(mmapped_buf: &mut MMappedBuf, offset: usize, value: T) -> usize {
+        let dst: *mut _ = mmapped_buf;
+        let head = offset + mem::size_of::<T>();
+        unsafe {
+            ptr::write_unaligned(dst.byte_add(PAGE_SIZE + offset).cast(), value);
+            mmapped_buf.mmap_page.data_head = head as u64;
+        }
+        head
+    }
+
     #[test]
     fn test_read_first_lost() {
-        let mut mmapped_buf = MMappedBuf {
-            data: [0; PAGE_SIZE * 2],
-        };
-        fake_mmap(&mmapped_buf);
-
         #[repr(C)]
         #[derive(Debug)]
         struct LostSamples {
@@ -361,18 +361,27 @@ mod tests {
             count: u64,
         }
 
-        let evt = LostSamples {
-            header: perf_event_header {
-                type_: PERF_RECORD_LOST as u32,
-                misc: 0,
-                size: mem::size_of::<LostSamples>() as u16,
-            },
-            id: 1,
-            count: 0xCAFEBABE,
+        let mut mmapped_buf = MMappedBuf {
+            data: [0; PAGE_SIZE * 2],
         };
-        write(&mut mmapped_buf, 0, evt);
 
+        write(
+            &mut mmapped_buf,
+            0,
+            LostSamples {
+                header: perf_event_header {
+                    type_: PERF_RECORD_LOST as u32,
+                    misc: 0,
+                    size: mem::size_of::<LostSamples>() as u16,
+                },
+                id: 1,
+                count: 0xCAFEBABE,
+            },
+        );
+
+        fake_mmap(&mut mmapped_buf);
         let mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
+
         let out_buf = BytesMut::with_capacity(0);
         let events = buf.read_events(&mut [out_buf]).unwrap();
         assert_eq!(events.lost, 0xCAFEBABE);
@@ -385,28 +394,22 @@ mod tests {
         value: T,
     }
 
-    fn write<T: Debug>(mmapped_buf: &mut MMappedBuf, offset: usize, value: T) -> usize {
-        let dst: *mut _ = mmapped_buf;
-        unsafe {
-            ptr::write_unaligned(dst.byte_add(PAGE_SIZE + offset).cast(), value);
-            mmapped_buf.mmap_page.data_head = (offset + mem::size_of::<T>()) as u64;
-            mmapped_buf.mmap_page.data_head as usize
-        }
-    }
-
     fn write_sample<T: Debug>(mmapped_buf: &mut MMappedBuf, offset: usize, value: T) -> usize {
-        let sample = PerfSample {
-            s_hdr: Sample {
-                header: perf_event_header {
-                    type_: PERF_RECORD_SAMPLE as u32,
-                    misc: 0,
-                    size: mem::size_of::<PerfSample<T>>() as u16,
+        write(
+            mmapped_buf,
+            offset,
+            PerfSample {
+                s_hdr: Sample {
+                    header: perf_event_header {
+                        type_: PERF_RECORD_SAMPLE as u32,
+                        misc: 0,
+                        size: mem::size_of::<PerfSample<T>>() as u16,
+                    },
+                    size: mem::size_of::<T>() as u32,
                 },
-                size: mem::size_of::<T>() as u32,
+                value,
             },
-            value,
-        };
-        write(mmapped_buf, offset, sample)
+        )
     }
 
     fn u32_from_buf(buf: &[u8]) -> u32 {
@@ -422,11 +425,12 @@ mod tests {
         let mut mmapped_buf = MMappedBuf {
             data: [0; PAGE_SIZE * 2],
         };
-        fake_mmap(&mmapped_buf);
-        let mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
 
         write_sample(&mut mmapped_buf, 0, 0xCAFEBABEu32);
 
+        fake_mmap(&mut mmapped_buf);
+        let mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
+
         let mut out_bufs = [BytesMut::with_capacity(4)];
 
         let events = buf.read_events(&mut out_bufs).unwrap();
@@ -439,12 +443,13 @@ mod tests {
         let mut mmapped_buf = MMappedBuf {
             data: [0; PAGE_SIZE * 2],
         };
-        fake_mmap(&mmapped_buf);
-        let mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
 
         let next = write_sample(&mut mmapped_buf, 0, 0xCAFEBABEu32);
         write_sample(&mut mmapped_buf, next, 0xBADCAFEu32);
 
+        fake_mmap(&mut mmapped_buf);
+        let mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
+
         let mut out_bufs = [BytesMut::with_capacity(4)];
 
         let events = buf.read_events(&mut out_bufs).unwrap();
@@ -461,12 +466,13 @@ mod tests {
         let mut mmapped_buf = MMappedBuf {
             data: [0; PAGE_SIZE * 2],
         };
-        fake_mmap(&mmapped_buf);
-        let mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
 
         let next = write_sample(&mut mmapped_buf, 0, 0xCAFEBABEu32);
         write_sample(&mut mmapped_buf, next, 0xBADCAFEu32);
 
+        fake_mmap(&mut mmapped_buf);
+        let mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
+
         let mut out_bufs = (0..3)
             .map(|_| BytesMut::with_capacity(4))
             .collect::<Vec<_>>();
@@ -482,12 +488,13 @@ mod tests {
         let mut mmapped_buf = MMappedBuf {
             data: [0; PAGE_SIZE * 2],
         };
-        fake_mmap(&mmapped_buf);
-        let mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
 
         let offset = PAGE_SIZE - mem::size_of::<PerfSample<u32>>();
-        mmapped_buf.mmap_page.data_tail = offset as u64;
         write_sample(&mut mmapped_buf, offset, 0xCAFEBABEu32);
+        mmapped_buf.mmap_page.data_tail = offset as u64;
+
+        fake_mmap(&mut mmapped_buf);
+        let mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
 
         let mut out_bufs = [BytesMut::with_capacity(4)];
 
@@ -501,31 +508,31 @@ mod tests {
         let mut mmapped_buf = MMappedBuf {
             data: [0; PAGE_SIZE * 2],
         };
-        fake_mmap(&mmapped_buf);
-        let mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
-
-        let header = perf_event_header {
-            type_: PERF_RECORD_SAMPLE as u32,
-            misc: 0,
-            size: mem::size_of::<PerfSample<u64>>() as u16,
-        };
 
         let offset = PAGE_SIZE - mem::size_of::<perf_event_header>() - 2;
+        write(
+            &mut mmapped_buf,
+            offset,
+            perf_event_header {
+                type_: PERF_RECORD_SAMPLE as u32,
+                misc: 0,
+                size: mem::size_of::<PerfSample<u64>>() as u16,
+            },
+        );
         mmapped_buf.mmap_page.data_tail = offset as u64;
-        write(&mut mmapped_buf, offset, header);
-        #[cfg(target_endian = "little")]
-        {
-            write(&mut mmapped_buf, PAGE_SIZE - 2, 0x0004u16);
-            write(&mut mmapped_buf, 0, 0x0000u16);
-        }
-        #[cfg(target_endian = "big")]
-        {
-            write(&mut mmapped_buf, PAGE_SIZE - 2, 0x0000u16);
-            write(&mut mmapped_buf, 0, 0x0004u16);
-        }
 
+        let (left, right) = if cfg!(target_endian = "little") {
+            (0x0004u16, 0x0000u16)
+        } else {
+            (0x0000u16, 0x0004u16)
+        };
+        write(&mut mmapped_buf, PAGE_SIZE - 2, left);
+        write(&mut mmapped_buf, 0, right);
         write(&mut mmapped_buf, 2, 0xBAADCAFEu32);
 
+        fake_mmap(&mut mmapped_buf);
+        let mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
+
         let mut out_bufs = [BytesMut::with_capacity(8)];
 
         let events = buf.read_events(&mut out_bufs).unwrap();
@@ -538,31 +545,34 @@ mod tests {
         let mut mmapped_buf = MMappedBuf {
             data: [0; PAGE_SIZE * 2],
         };
-        fake_mmap(&mmapped_buf);
-        let mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
 
-        let sample = PerfSample {
-            s_hdr: Sample {
-                header: perf_event_header {
-                    type_: PERF_RECORD_SAMPLE as u32,
-                    misc: 0,
-                    size: mem::size_of::<PerfSample<u64>>() as u16,
-                },
-                size: mem::size_of::<u64>() as u32,
-            },
-            #[cfg(target_endian = "little")]
-            value: 0xCAFEBABEu32,
-            #[cfg(target_endian = "big")]
-            value: 0xBAADCAFEu32,
+        let (left, right) = if cfg!(target_endian = "little") {
+            (0xCAFEBABEu32, 0xBAADCAFEu32)
+        } else {
+            (0xBAADCAFEu32, 0xCAFEBABEu32)
         };
 
         let offset = PAGE_SIZE - mem::size_of::<PerfSample<u32>>();
+        write(
+            &mut mmapped_buf,
+            offset,
+            PerfSample {
+                s_hdr: Sample {
+                    header: perf_event_header {
+                        type_: PERF_RECORD_SAMPLE as u32,
+                        misc: 0,
+                        size: mem::size_of::<PerfSample<u64>>() as u16,
+                    },
+                    size: mem::size_of::<u64>() as u32,
+                },
+                value: left,
+            },
+        );
+        write(&mut mmapped_buf, 0, right);
         mmapped_buf.mmap_page.data_tail = offset as u64;
-        write(&mut mmapped_buf, offset, sample);
-        #[cfg(target_endian = "little")]
-        write(&mut mmapped_buf, 0, 0xBAADCAFEu32);
-        #[cfg(target_endian = "big")]
-        write(&mut mmapped_buf, 0, 0xCAFEBABEu32);
+
+        fake_mmap(&mut mmapped_buf);
+        let mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
 
         let mut out_bufs = [BytesMut::with_capacity(8)];