perf_buffer: attempt to preserve provenance

In tests, provide write provenance.
pull/1161/merge
Tamir Duberstein 2 weeks ago
parent 888701425b
commit f51ab80075

@ -145,28 +145,24 @@ impl PerfBuffer {
return Err(PerfBufferError::NoBuffers); return Err(PerfBufferError::NoBuffers);
} }
let header = self.buf().as_ptr(); 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 events = Events { read: 0, lost: 0 };
let mut buf_n = 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 len = out_buf.len();
let end = (start_off + len) % mmap_size; let end = (start_off + len) % mmap_size;
let start = start_off % mmap_size; let start = start_off % mmap_size;
if start < end { if start < end {
out_buf.copy_from_slice(unsafe { out_buf.copy_from_slice(unsafe { slice::from_raw_parts(base.add(start), len) });
slice::from_raw_parts((base + start) as *const u8, len)
});
} else { } else {
let size = mmap_size - start; let size = mmap_size - start;
unsafe { unsafe {
out_buf[..size] out_buf[..size].copy_from_slice(slice::from_raw_parts(base.add(start), 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, len - size));
out_buf[size..]
.copy_from_slice(slice::from_raw_parts(base as *const u8, len - size));
} }
} }
}; };
@ -227,11 +223,11 @@ impl PerfBuffer {
let buf = &mut buffers[buf_n]; let buf = &mut buffers[buf_n];
let event_start = tail % self.size; let event_start = tail % self.size;
let event = let event: perf_event_header =
unsafe { ptr::read_unaligned((base + event_start) as *const perf_event_header) }; unsafe { ptr::read_unaligned(base.byte_add(event_start).cast()) };
let event_size = event.size as usize; 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))) => { Ok(Some((read, lost))) => {
if read > 0 { if read > 0 {
buf_n += 1; buf_n += 1;
@ -290,14 +286,15 @@ mod tests {
data: [u8; PAGE_SIZE * 2], 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 { override_syscall(|call| match call {
Syscall::PerfEventOpen { .. } | Syscall::PerfEventIoctl { .. } => { Syscall::PerfEventOpen { .. } | Syscall::PerfEventIoctl { .. } => {
Ok(crate::MockableFd::mock_signed_fd().into()) Ok(crate::MockableFd::mock_signed_fd().into())
} }
call => panic!("unexpected syscall: {:?}", call), 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] #[test]
@ -318,27 +315,25 @@ mod tests {
#[test] #[test]
fn test_no_out_bufs() { fn test_no_out_bufs() {
let mmapped_buf = MMappedBuf { let mut mmapped_buf = MMappedBuf {
data: [0; PAGE_SIZE * 2], 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 mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
assert_matches!(buf.read_events(&mut []), Err(PerfBufferError::NoBuffers)) assert_matches!(buf.read_events(&mut []), Err(PerfBufferError::NoBuffers))
} }
#[test] #[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() { fn test_no_events() {
let mmapped_buf = MMappedBuf { let mut mmapped_buf = MMappedBuf {
data: [0; PAGE_SIZE * 2], 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 mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
let out_buf = BytesMut::with_capacity(4); let out_buf = BytesMut::with_capacity(4);
assert_eq!( assert_eq!(
buf.read_events(&mut [out_buf]).unwrap(), 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] #[test]
fn test_read_first_lost() { fn test_read_first_lost() {
let mut mmapped_buf = MMappedBuf {
data: [0; PAGE_SIZE * 2],
};
fake_mmap(&mmapped_buf);
#[repr(C)] #[repr(C)]
#[derive(Debug)] #[derive(Debug)]
struct LostSamples { struct LostSamples {
@ -361,18 +361,27 @@ mod tests {
count: u64, count: u64,
} }
let evt = LostSamples { let mut mmapped_buf = MMappedBuf {
header: perf_event_header { data: [0; PAGE_SIZE * 2],
type_: PERF_RECORD_LOST as u32,
misc: 0,
size: mem::size_of::<LostSamples>() as u16,
},
id: 1,
count: 0xCAFEBABE,
}; };
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 mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
let out_buf = BytesMut::with_capacity(0); let out_buf = BytesMut::with_capacity(0);
let events = buf.read_events(&mut [out_buf]).unwrap(); let events = buf.read_events(&mut [out_buf]).unwrap();
assert_eq!(events.lost, 0xCAFEBABE); assert_eq!(events.lost, 0xCAFEBABE);
@ -385,28 +394,22 @@ mod tests {
value: T, 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 { fn write_sample<T: Debug>(mmapped_buf: &mut MMappedBuf, offset: usize, value: T) -> usize {
let sample = PerfSample { write(
s_hdr: Sample { mmapped_buf,
header: perf_event_header { offset,
type_: PERF_RECORD_SAMPLE as u32, PerfSample {
misc: 0, s_hdr: Sample {
size: mem::size_of::<PerfSample<T>>() as u16, 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 { fn u32_from_buf(buf: &[u8]) -> u32 {
@ -422,11 +425,12 @@ mod tests {
let mut mmapped_buf = MMappedBuf { let mut mmapped_buf = MMappedBuf {
data: [0; PAGE_SIZE * 2], 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); 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 mut out_bufs = [BytesMut::with_capacity(4)];
let events = buf.read_events(&mut out_bufs).unwrap(); let events = buf.read_events(&mut out_bufs).unwrap();
@ -439,12 +443,13 @@ mod tests {
let mut mmapped_buf = MMappedBuf { let mut mmapped_buf = MMappedBuf {
data: [0; PAGE_SIZE * 2], 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); let next = write_sample(&mut mmapped_buf, 0, 0xCAFEBABEu32);
write_sample(&mut mmapped_buf, next, 0xBADCAFEu32); 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 mut out_bufs = [BytesMut::with_capacity(4)];
let events = buf.read_events(&mut out_bufs).unwrap(); let events = buf.read_events(&mut out_bufs).unwrap();
@ -461,12 +466,13 @@ mod tests {
let mut mmapped_buf = MMappedBuf { let mut mmapped_buf = MMappedBuf {
data: [0; PAGE_SIZE * 2], 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); let next = write_sample(&mut mmapped_buf, 0, 0xCAFEBABEu32);
write_sample(&mut mmapped_buf, next, 0xBADCAFEu32); 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) let mut out_bufs = (0..3)
.map(|_| BytesMut::with_capacity(4)) .map(|_| BytesMut::with_capacity(4))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -482,12 +488,13 @@ mod tests {
let mut mmapped_buf = MMappedBuf { let mut mmapped_buf = MMappedBuf {
data: [0; PAGE_SIZE * 2], 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>>(); 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); 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)]; let mut out_bufs = [BytesMut::with_capacity(4)];
@ -501,31 +508,31 @@ mod tests {
let mut mmapped_buf = MMappedBuf { let mut mmapped_buf = MMappedBuf {
data: [0; PAGE_SIZE * 2], 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; 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; 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); 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 mut out_bufs = [BytesMut::with_capacity(8)];
let events = buf.read_events(&mut out_bufs).unwrap(); let events = buf.read_events(&mut out_bufs).unwrap();
@ -538,31 +545,34 @@ mod tests {
let mut mmapped_buf = MMappedBuf { let mut mmapped_buf = MMappedBuf {
data: [0; PAGE_SIZE * 2], data: [0; PAGE_SIZE * 2],
}; };
fake_mmap(&mmapped_buf);
let mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
let sample = PerfSample { let (left, right) = if cfg!(target_endian = "little") {
s_hdr: Sample { (0xCAFEBABEu32, 0xBAADCAFEu32)
header: perf_event_header { } else {
type_: PERF_RECORD_SAMPLE as u32, (0xBAADCAFEu32, 0xCAFEBABEu32)
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 offset = PAGE_SIZE - mem::size_of::<PerfSample<u32>>(); 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; mmapped_buf.mmap_page.data_tail = offset as u64;
write(&mut mmapped_buf, offset, sample);
#[cfg(target_endian = "little")] fake_mmap(&mut mmapped_buf);
write(&mut mmapped_buf, 0, 0xBAADCAFEu32); let mut buf = PerfBuffer::open(1, PAGE_SIZE, 1).unwrap();
#[cfg(target_endian = "big")]
write(&mut mmapped_buf, 0, 0xCAFEBABEu32);
let mut out_bufs = [BytesMut::with_capacity(8)]; let mut out_bufs = [BytesMut::with_capacity(8)];

Loading…
Cancel
Save