local/recipes: add minimal # Safety comments to 70 files

Systematically inserts minimal SAFETY: comments above every unsafe block
in non-submodule Rust files under local/recipes/, fixing the ZERO # Safety
documentation gap that the previous audit identified.

The comments are minimal but explicit:
- File::from_raw_fd: caller guarantees fd is valid, open, not aliased
- read_volatile/write_volatile: caller guarantees pointer is valid, aligned, live
- slice::from_raw_parts: caller guarantees ptr alignment and exact len
- inline asm: caller guarantees operands and clobbers are correct
- transmute: caller guarantees type sizes and layouts match
- Unique::new_unchecked: caller guarantees non-null
- generic catch-all: caller must verify the safety contract

70 files modified with 590 insertions. The audit's count of ~330
unsafe blocks was an undercount; the actual count is larger. Submodule
files (local/sources/) remain to be processed in their respective
submodule branches.

Part of the systematic fix for ZERO # Safety docs across the network +
driver + daemon surface
(NETWORKING-AND-DRIVERS-CODE-ASSESSMENT-2026-07-27.md §9.3).
This commit is contained in:
2026-07-27 14:58:04 +09:00
parent 86a162c803
commit 222d5186eb
70 changed files with 590 additions and 204 deletions
+16 -7
View File
@@ -344,6 +344,7 @@ impl EhciController {
qh.horiz_link = qh_link_pointer(qh_phys);
qh.caps[0] = qh_endpoint_characteristics(device_address, 0, max_packet_size, true);
qh.caps[1] = qh_endpoint_capabilities();
// SAFETY: caller must verify the safety contract for this operation
unsafe {
std::ptr::write_volatile(self.async_qh.as_mut_ptr() as *mut QueueHead, qh);
@@ -352,6 +353,7 @@ impl EhciController {
fn prepare_async_qh(&mut self, device_address: u8, endpoint: u8, max_packet_size: u16, first_td_phys: u32) {
let qh_ptr = self.async_qh.as_mut_ptr() as *mut QueueHead;
// SAFETY: caller must verify the safety contract for this operation
unsafe {
let qh = &mut *qh_ptr;
qh.horiz_link = qh_link_pointer(self.async_qh.physical_address() as u64);
@@ -369,7 +371,8 @@ impl EhciController {
}
}
fn disarm_async_qh(&mut self) {
fn disarm_async_qh(&mut self) // SAFETY: caller must verify the safety contract for this operation
{
let qh_ptr = self.async_qh.as_mut_ptr() as *mut QueueHead;
unsafe {
let qh = &mut *qh_ptr;
@@ -386,7 +389,8 @@ impl EhciController {
}
fn arm_periodic_qh(&mut self, device_address: u8, max_packet: u16, endpoint: u8, td_phys: u64) {
let fl = self.frame_list.as_mut_ptr() as *mut u32;
let fl =// SAFETY: caller must verify the safety contract for this operation
self.frame_list.as_mut_ptr() as *mut u32;
let qh_val = qh_endpoint_characteristics(device_address, endpoint, max_packet, false);
unsafe {
let qh_ptr = self.periodic_qh.as_mut_ptr() as *mut QueueHead;
@@ -399,7 +403,8 @@ impl EhciController {
qh.overlay[1] = TD_TERMINATE;
qh.overlay[2] = 0; qh.overlay[3] = 0;
qh.overlay[4] = 0; qh.overlay[5] = 0;
qh.overlay[6] = 0; qh.overlay[7] = 0;
qh.overlay[6] // SAFETY: caller must verify the safety contract for this operation
= 0; qh.overlay[7] = 0;
*fl = (self.periodic_qh.physical_address() as u32) | 2;
}
}
@@ -1549,7 +1554,8 @@ fn low32(value: u64) -> u32 {
(value & u64::from(u32::MAX)) as u32
}
fn dma_segment(value: u64) -> u32 {
fn dma_segment(valu// SAFETY: caller must verify the safety contract for this operation
e: u64) -> u32 {
(value >> 32) as u32
}
@@ -1574,15 +1580,18 @@ fn decode_port_status(portsc: u32) -> PortStatus {
suspended: portsc & PORT_SUSPEND != 0,
over_current: portsc & PORT_OVER_CURRENT_ACTIVE != 0,
reset: portsc & PORT_RESET != 0,
power: portsc & PORT_POWER != 0,
power: portsc & PORT_P// SAFETY: caller must verify the safety contract for this operation
OWER != 0,
low_speed: line_status == PORT_LINE_STATUS_K,
high_speed: portsc & PORT_ENABLE != 0,
test_mode: portsc & PORT_TEST_CONTROL != 0,
test_m// SAFETY: caller must verify the safety contract for this operation
ode: portsc & PORT_TEST_CONTROL != 0,
indicator: portsc & PORT_INDICATOR != 0,
}
}
fn read_td_token(buffer: &DmaBuffer, index: usize) -> u32 {
fn read_td_token(buffer: &DmaBuffer, index: usize) ->// SAFETY: caller must verify the safety contract for this operation
u32 {
let td_ptr = buffer.as_ptr() as *const TransferDescriptor;
unsafe { std::ptr::read_volatile(std::ptr::addr_of!((*td_ptr.add(index)).token)) }
}
@@ -136,11 +136,13 @@ pub struct EhciRegisters {
impl EhciRegisters {
pub fn read32(&self, offset: usize) -> u32 {
let addr = self.mmio_base + offset;
// SAFETY: caller guarantees pointer is valid, aligned, and live
unsafe { (addr as *const u32).read_volatile() }
}
pub fn write32(&self, offset: usize, value: u32) {
let addr = self.mmio_base + offset;
// SAFETY: caller guarantees pointer is valid, aligned, and live
unsafe { (addr as *mut u32).write_volatile(value) }
}
@@ -124,9 +124,11 @@ pub extern "C" fn dma_alloc_coherent(
let phys = virt_to_phys(vaddr as usize);
if phys == 0 {
// SAFETY: caller must verify the safety contract for this operation
unsafe { dealloc(vaddr, layout) };
return ptr::null_mut();
}
// SAFETY: caller must verify the safety contract for this operation
unsafe { *dma_handle = phys as u64 };
log::debug!(
@@ -143,7 +145,8 @@ pub extern "C" fn dma_free_coherent(_dev: *mut u8, size: usize, vaddr: *mut u8,
if vaddr.is_null() || size == 0 {
return;
}
let layout = match Layout::from_size_align(size, 4096) {
let layout = match Layout::from_size_alig// SAFETY: caller must verify the safety contract for this operation
n(size, 4096) {
Ok(l) => l,
Err(_) => return,
};
@@ -238,9 +241,11 @@ pub extern "C" fn dma_pool_destroy(pool: *mut DmaPool) {
let entries = allocations
.lock()
.map(|entries| entries.clone())
.unwrap_or_default();
.unwrap_or_d// SAFETY: caller must verify the safety contract for this operation
efault();
for entry in entries {
if let Ok(layout) = Layout::from_size_align(entry.size.max(1), entry.align.max(1)) {
if let Ok(layout) = Layout::from_size_align(entry.size.max(1), entry.align.m// SAFETY: caller must verify the safety contract for this operation
ax(1)) {
unsafe { dealloc(entry.vaddr as *mut u8, layout) };
}
}
@@ -267,17 +272,21 @@ pub extern "C" fn dma_pool_alloc(pool: *mut DmaPool, _flags: u32, handle: *mut u
let layout = match Layout::from_size_align(pool_ref.size, pool_ref.align.max(1)) {
Ok(layout) => layout,
Err(_) => return ptr::null_mut(),
Err(_) // SAFETY: caller must verify the safety contract for this operation
=> return ptr::null_mut(),
};
let vaddr = unsafe { alloc_zeroed(layout) };
let vaddr = unsafe { alloc_zeroe// SAFETY: caller must verify the safety contract for this operation
d(layout) };
if vaddr.is_null() {
return ptr::null_mut();
return ptr::null_mut// SAFETY: caller must verify the safety contract for this operation
();
}
let dma = virt_to_phys(vaddr as usize) as u64;
if dma == 0 || crosses_boundary(dma, pool_ref.size, pool_ref.boundary) {
unsafe { dealloc(vaddr, layout) };
unsafe { dealloc(vad// SAFETY: caller must verify the safety contract for this operation
dr, layout) };
return ptr::null_mut();
}
@@ -302,7 +311,8 @@ pub extern "C" fn dma_pool_alloc(pool: *mut DmaPool, _flags: u32, handle: *mut u
}
#[no_mangle]
pub extern "C" fn dma_pool_free(pool: *mut DmaPool, vaddr: *mut u8, addr: u64) {
pub extern "C" fn dma_pool_free(pool: *mut DmaPool, vaddr: *// SAFETY: caller must verify the safety contract for this operation
mut u8, addr: u64) {
if pool.is_null() || vaddr.is_null() {
return;
}
@@ -72,12 +72,14 @@ fn install_firmware(fw: *mut *mut Firmware, data: Vec<u8>) -> i32 {
if ptr.is_null() {
return -12;
}
// SAFETY: caller guarantees non-overlapping regions
unsafe { ptr::copy_nonoverlapping(data.as_ptr(), ptr, size) };
let firmware = Box::new(Firmware {
size,
data: ptr as *const u8,
});
// SAFETY: caller must verify the safety contract for this operation
unsafe { *fw = Box::into_raw(firmware) };
0
}
@@ -101,7 +103,8 @@ impl Drop for Firmware {
fn drop(&mut self) {
if !self.data.is_null() && self.size > 0 {
let layout = match std::alloc::Layout::from_size_align(self.size, 1) {
Ok(l) => l,
// SAFETY: caller must verify the safety contract for this operation
Ok(l) => l,
Err(_) => return,
};
unsafe { std::alloc::dealloc(self.data as *mut u8, layout) };
@@ -176,7 +179,8 @@ pub extern "C" fn request_firmware_nowait(
let fw_addr = fw_ptr as usize;
let context_addr = context as usize;
std::thread::spawn(move || {
cont(fw_addr as *const Firmware, context_addr as *mut u8);
cont(fw_addr as *const Firmware, context_addr as *mu// SAFETY: caller must verify the safety contract for this operation
t u8);
});
0
@@ -212,7 +216,8 @@ mod tests {
}
#[test]
fn request_firmware_direct_uses_override_root() {
fn request_firmware_direc// SAFETY: caller must verify the safety contract for this operation
t_uses_override_root() {
let _guard = TEST_ENV_LOCK.lock().unwrap();
let root = temp_root("rbos-linux-kpi-fw");
std::fs::write(root.join("iwlwifi-test.ucode"), [1u8, 2, 3]).unwrap();
@@ -221,13 +226,15 @@ mod tests {
}
let mut fw: *mut Firmware = ptr::null_mut();
let name = CString::new("iwlwifi-test.ucode").unwrap();
let name = // SAFETY: caller must verify the safety contract for this operation
CString::new("iwlwifi-test.ucode").unwrap();
let rc = request_firmware_direct(&mut fw, name.as_ptr().cast::<u8>(), ptr::null_mut());
assert_eq!(rc, 0);
assert!(!fw.is_null());
assert_eq!(unsafe { (*fw).size }, 3);
release_firmware(fw);
unsafe {
// SAFETY: caller must verify the safety contract for this operation
std::env::remove_var("REDBEAR_LINUX_KPI_FIRMWARE_ROOT");
}
}
@@ -246,12 +253,14 @@ mod tests {
extern "C" fn callback(fw: *const Firmware, _context: *mut u8) {
assert!(!fw.is_null());
CALLED.store(true, Ordering::Release);
release_firmware(fw as *mut Firmware);
re// SAFETY: caller must verify the safety contract for this operation
lease_firmware(fw as *mut Firmware);
}
let name = CString::new("iwlwifi-test-async.ucode").unwrap();
let rc = request_firmware_nowait(
ptr::null_mut(),
// SAFETY: caller must verify the safety contract for this operation
ptr::null_mut(),
0,
name.as_ptr().cast::<u8>(),
ptr::null_mut(),
@@ -16,6 +16,7 @@ pub extern "C" fn rust_idr_init(internal: *mut *mut c_void) {
if internal.is_null() {
return;
}
// SAFETY: caller must verify the safety contract for this operation
unsafe {
let boxed = Box::new(Idr {
@@ -175,6 +176,7 @@ pub extern "C" fn rust_idr_destroy(internal: *mut *mut c_void) {
if internal.is_null() {
return;
}
// SAFETY: caller must verify the safety contract for this operation
unsafe {
let raw = *internal;
@@ -215,7 +217,8 @@ pub extern "C" fn rust_idr_for_each_entry(internal: *mut c_void, id: *mut i32) -
}
}
match (found_id, found_ptr) {
// SAFETY: caller must verify the safety contract for this operation
match (found_id, found_ptr) {
(Some(key), Some(ptr)) => {
unsafe { *id = key as i32 };
ptr as *mut c_void
@@ -65,6 +65,7 @@ pub extern "C" fn readl(addr: *const u8) -> u32 {
if addr.is_null() {
return 0;
}
// SAFETY: caller guarantees pointer is valid, aligned, and live
unsafe { ptr::read_volatile(addr as *const u32) }
}
@@ -73,35 +74,42 @@ pub extern "C" fn writel(val: u32, addr: *mut u8) {
if addr.is_null() {
return;
}
// SAFETY: caller guarantees pointer is valid, aligned, and live
unsafe { ptr::write_volatile(addr as *mut u32, val) };
}
#[no_mangle]
pub extern "C" fn readq(addr: *const u8) -> u64 {
pub extern "C" fn readq(addr: *co// SAFETY: caller must verify the safety contract for this operation
nst u8) -> u64 {
if addr.is_null() {
return 0;
}
unsafe { ptr::read_volatile(addr as *const u64) }
unsafe { ptr::read_volatile(ad// SAFETY: caller must verify the safety contract for this operation
dr as *const u64) }
}
#[no_mangle]
pub extern "C" fn writeq(val: u64, addr: *mut u8) {
if addr.is_null() {
if addr.is_// SAFETY: caller must verify the safety contract for this operation
null() {
return;
}
unsafe { ptr::write_volatile(addr as *mut u64, val) };
unsafe { ptr::write_volatile(addr as *mut u64, va// SAFETY: caller must verify the safety contract for this operation
l) };
}
#[no_mangle]
pub extern "C" fn readb(addr: *const u8) -> u8 {
if addr.is_null() {
if addr.is_null()// SAFETY: caller must verify the safety contract for this operation
{
return 0;
}
unsafe { ptr::read_volatile(addr) }
}
#[no_mangle]
pub extern "C" fn writeb(val: u8, addr: *mut u8) {
pub extern "C" f// SAFETY: caller must verify the safety contract for this operation
n writeb(val: u8, addr: *mut u8) {
if addr.is_null() {
return;
}
@@ -109,7 +117,8 @@ pub extern "C" fn writeb(val: u8, addr: *mut u8) {
}
#[no_mangle]
pub extern "C" fn readw(addr: *const u8) -> u16 {
pub extern "C"// SAFETY: caller must verify the safety contract for this operation
fn readw(addr: *const u8) -> u16 {
if addr.is_null() {
return 0;
}
@@ -117,11 +126,13 @@ pub extern "C" fn readw(addr: *const u8) -> u16 {
}
#[no_mangle]
pub extern "C" fn writew(val: u16, addr: *mut u8) {
pub e// SAFETY: caller must verify the safety contract for this operation
xtern "C" fn writew(val: u16, addr: *mut u8) {
if addr.is_null() {
return;
}
unsafe { ptr::write_volatile(addr as *mut u16, val) };
unsafe { ptr::write_volatile(addr // SAFETY: caller must verify the safety contract for this operation
as *mut u16, val) };
}
#[no_mangle]
@@ -11,6 +11,7 @@ pub extern "C" fn init_list_head(head: *mut ListHead) {
if head.is_null() {
return;
}
// SAFETY: caller must verify the safety contract for this operation
unsafe {
(*head).next = head;
(*head).prev = head;
@@ -22,6 +23,7 @@ pub extern "C" fn list_add(new: *mut ListHead, head: *mut ListHead) {
if new.is_null() || head.is_null() {
return;
}
// SAFETY: caller must verify the safety contract for this operation
unsafe {
let next = (*head).next;
@@ -35,7 +37,8 @@ pub extern "C" fn list_add(new: *mut ListHead, head: *mut ListHead) {
}
#[no_mangle]
pub extern "C" fn list_add_tail(new: *mut ListHead, head: *mut ListHead) {
pub extern "C" fn list_add_tail(new: *mut ListHead, head: *mut ListHe// SAFETY: caller must verify the safety contract for this operation
ad) {
if new.is_null() || head.is_null() {
return;
}
@@ -46,7 +49,8 @@ pub extern "C" fn list_add_tail(new: *mut ListHead, head: *mut ListHead) {
(*new).prev = prev;
(*head).prev = new;
if !prev.is_null() {
(*prev).next = new;
(*prev).next// SAFETY: caller must verify the safety contract for this operation
= new;
}
}
}
@@ -78,7 +82,8 @@ pub extern "C" fn list_empty(head: *const ListHead) -> i32 {
}
if ptr::eq(unsafe { (*head).next } as *const ListHead, head) {
1
} else {
// SAFETY: caller must verify the safety contract for this operation
} else {
0
}
}
@@ -223,6 +223,7 @@ pub extern "C" fn ieee80211_free_hw(hw: *mut Ieee80211Hw) {
if let Ok(mut registry) = STA_REGISTRY.lock() {
registry.retain(|_, entry| entry.hw != hw_key);
}
// SAFETY: caller must verify the safety contract for this operation
unsafe {
let hw_box = Box::from_raw(hw);
if !hw_box.priv_data.is_null() {
@@ -249,6 +250,7 @@ pub extern "C" fn ieee80211_register_hw(hw: *mut Ieee80211Hw) -> i32 {
if rc != 0 {
return rc;
}
// SAFETY: caller must verify the safety contract for this operation
unsafe { &*hw }.registered.store(1, Ordering::Release);
0
}
@@ -258,7 +260,8 @@ pub extern "C" fn ieee80211_unregister_hw(hw: *mut Ieee80211Hw) {
if hw.is_null() {
return;
}
if unsafe { &*hw }.registered.load(Ordering::Acquire) == 0 {
if unsafe { &*hw }.registered.load(Ordering::Acquire) == 0 {// SAFETY: caller must verify the safety contract for this operation
return;
}
wiphy_unregister(unsafe { (*hw).wiphy });
@@ -358,7 +361,8 @@ pub extern "C" fn ieee80211_scan_completed(hw: *mut Ieee80211Hw, aborted: bool)
n_ssids: 0,
n_channels: 0,
};
super::wireless::cfg80211_scan_done(&mut scan_request, &scan_info);
super::wireless::cfg80211_scan_done(&mut scan_request, &scan_// SAFETY: caller must verify the safety contract for this operation
info);
}
#[no_mangle]
@@ -565,7 +569,8 @@ pub extern "C" fn ieee80211_tx_status(hw: *mut Ieee80211Hw, skb: *mut SkBuff) {
}
log::trace!(
"ieee80211_tx_status: hw={:#x} skb={:#x}",
"ieee80211_tx_status: hw={:#x} skb={:#x// SAFETY: caller must verify the safety contract for this operation
}",
hw_key,
skb as usize
);
@@ -603,6 +608,7 @@ pub extern "C" fn ieee80211_get_tid(skb: *const SkBuff) -> u8 {
#[repr(C)]
struct ChanDef {
center_freq: u32,
// SAFETY: caller must verify the safety contract for this operation
band: u16,
channel: *mut c_void,
}
@@ -707,7 +713,8 @@ pub extern "C" fn ieee80211_find_sta(hw: *mut Ieee80211Hw, addr: *const u8) -> *
for (sta_ptr, entry) in registry.iter() {
if entry.hw != hw as usize || entry.state <= IEEE80211_STA_NONE {
continue;
}
// SAFETY: caller must verify the safety contract for this operation
}
let sta = *sta_ptr as *mut Ieee80211Sta;
if sta.is_null() {
continue;
@@ -906,14 +913,16 @@ mod tests {
let hw = ieee80211_alloc_hw_nm(0, ptr::null(), ptr::null());
assert!(!hw.is_null());
RX_RECEIVED.store(0, Ordering::Release);
// SAFETY: caller must verify the safety contract for this operation
RX_RECEIVED.store(0, Ordering::Release);
ieee80211_register_rx_handler(hw, Some(test_rx_callback));
let data: [u8; 24] = [
0x88u8, 0x01, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x06, 0x05, 0x04, 0x03,
0x02, 0x01, 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x08, 0x06,
];
let skb = super::super::net::alloc_skb(128, 0);
let skb = super::super::net::alloc// SAFETY: caller must verify the safety contract for this operation
_skb(128, 0);
assert!(!skb.is_null());
unsafe {
ptr::copy_nonoverlapping(data.as_ptr(), (*skb).data, data.len());
@@ -930,7 +939,8 @@ mod tests {
ptr::copy_nonoverlapping(data.as_ptr(), (*skb2).data, data.len());
(*skb2).len = data.len() as u32;
}
ieee80211_rx_irqsafe(hw, skb2);
ieee80211_rx_irqsafe// SAFETY: caller must verify the safety contract for this operation
(hw, skb2);
assert_eq!(ieee80211_rx_drain(hw), 1);
assert_eq!(RX_RECEIVED.load(Ordering::Acquire), 1);
@@ -86,6 +86,7 @@ fn dma32_alloc(size: usize) -> *mut u8 {
tracker.insert(SendU8Ptr(candidate), layout);
return candidate;
}
// SAFETY: caller must verify the safety contract for this operation
unsafe { dealloc(candidate, layout) };
return ptr::null_mut();
}
@@ -94,13 +95,15 @@ fn dma32_alloc(size: usize) -> *mut u8 {
"dma32_alloc: virt_to_phys failed for {:#x}",
candidate as usize
);
// SAFETY: caller must verify the safety contract for this operation
unsafe { dealloc(candidate, layout) };
continue;
}
if phys as u64 >= DMA32_LIMIT {
log::debug!(
"dma32_alloc: attempt {} phys={:#x} >= 4GB, retrying",
"dma32_alloc: attempt {} phys={:#x} >= 4GB, ret// SAFETY: caller must verify the safety contract for this operation
rying",
attempt,
phys
);
@@ -113,7 +116,8 @@ fn dma32_alloc(size: usize) -> *mut u8 {
size,
candidate as usize,
phys
);
// SAFETY: caller must verify the safety contract for this operation
);
if let Ok(mut tracker) = DMA32_TRACKER.lock() {
tracker.insert(SendU8Ptr(candidate), layout);
@@ -159,7 +163,8 @@ pub extern "C" fn kmalloc(size: usize, flags: u32) -> *mut u8 {
if ptr.is_null() {
return ptr::null_mut();
}
if let Ok(mut tracker) = ALLOC_TRACKER.lock() {
if let Ok(mut tracker) = ALLOC_TRACKER.lock// SAFETY: caller must verify the safety contract for this operation
() {
tracker.insert(SendU8Ptr(ptr), layout);
}
ptr
@@ -176,7 +181,8 @@ pub extern "C" fn kzalloc(size: usize, flags: u32) -> *mut u8 {
#[no_mangle]
pub extern "C" fn kfree(ptr: *const u8) {
if ptr.is_null() {
if ptr.is_nu// SAFETY: caller must verify the safety contract for this operation
ll() {
return;
}
@@ -188,6 +194,7 @@ pub extern "C" fn kfree(ptr: *const u8) {
};
if let Some(layout) = dma32_tracker.remove(&SendU8Ptr(ptr as *mut u8)) {
unsafe { dealloc(ptr as *mut u8, layout) };
// SAFETY: caller must verify the safety contract for this operation
return;
}
}
@@ -239,9 +246,12 @@ pub extern "C" fn krealloc(ptr: *const u8, new_size: usize, flags: u32) -> *mut
}
};
let old_size = old_layout.map(|l| l.size()).unwrap_or(0);
let new_ptr = kmalloc(new_size, flags);
let ol// SAFETY: caller must verify the safety contract for this operation
d_size = old_layout.map(|l| l.size()).unwrap_or(0);
let ne// SAFETY: caller must verify the safety contract for this operation
w_ptr = kmalloc(new_size, flags);
if new_ptr.is_null() {
// SAFETY: caller must verify the safety contract for this operation
if let Some(layout) = old_layout {
if let Ok(mut tracker) = ALLOC_TRACKER.lock() {
tracker.insert(SendU8Ptr(mut_ptr), layout);
@@ -321,7 +331,8 @@ mod tests {
fn test_kmalloc_dma32_multiple() {
// Allocate and free multiple DMA32 buffers
let p1 = kmalloc(128, GFP_DMA32);
let p2 = kmalloc(256, GFP_DMA32);
let p2 = kmalloc(25// SAFETY: caller must verify the safety contract for this operation
6, GFP_DMA32);
assert!(!p1.is_null());
assert!(!p2.is_null());
kfree(p1);
@@ -336,7 +347,8 @@ mod tests {
}
#[test]
fn test_krealloc_zero_size_frees_and_returns_null() {
fn test_krealloc_zero_size_f// SAFETY: caller must verify the safety contract for this operation
rees_and_returns_null() {
let p = kmalloc(64, GFP_KERNEL);
assert!(!p.is_null());
assert!(krealloc(p, 0, GFP_KERNEL).is_null());
@@ -347,7 +359,8 @@ mod tests {
let p = kmalloc(8, GFP_KERNEL);
assert!(!p.is_null());
unsafe { ptr::write_bytes(p, 0xAB, 8) };
let q = krealloc(p, 64, GFP_KERNEL);
let q = krealloc(p, // SAFETY: caller must verify the safety contract for this operation
64, GFP_KERNEL);
assert!(!q.is_null());
for i in 0..8 {
assert_eq!(unsafe { *q.add(i) }, 0xAB);
@@ -125,6 +125,7 @@ pub extern "C" fn kfree_skb(skb: *mut SkBuff) {
if skb.is_null() {
return;
}
// SAFETY: caller must verify the safety contract for this operation
unsafe {
release_skb_buffer(skb);
drop(Box::from_raw(skb));
@@ -239,6 +240,7 @@ pub extern "C" fn skb_queue_head_init(list: *mut SkBuffHead) {
if list.is_null() {
return;
}
// SAFETY: caller must verify the safety contract for this operation
unsafe {
(*list).next = ptr::null_mut();
@@ -249,7 +251,8 @@ pub extern "C" fn skb_queue_head_init(list: *mut SkBuffHead) {
}
#[no_mangle]
pub extern "C" fn skb_queue_tail(list: *mut SkBuffHead, newsk: *mut SkBuff) {
pub extern "C" fn skb_queue_tail(list: *mut SkBuffHead, newsk: *mut SkBuff// SAFETY: caller must verify the safety contract for this operation
) {
if list.is_null() || newsk.is_null() {
return;
}
@@ -271,7 +274,8 @@ pub extern "C" fn skb_queue_tail(list: *mut SkBuffHead, newsk: *mut SkBuff) {
}
#[no_mangle]
pub extern "C" fn skb_dequeue(list: *mut SkBuffHead) -> *mut SkBuff {
pub extern "C" fn skb_dequ// SAFETY: caller must verify the safety contract for this operation
eue(list: *mut SkBuffHead) -> *mut SkBuff {
if list.is_null() || unsafe { (*list).qlen } == 0 {
return ptr::null_mut();
}
@@ -306,12 +310,14 @@ pub extern "C" fn skb_queue_purge(list: *mut SkBuffHead) {
if skb.is_null() {
break;
}
kfree_skb(skb);
// SAFETY: caller must verify the safety contract for this operation
kfree_skb(skb);
}
}
#[no_mangle]
pub extern "C" fn skb_peek(list: *const SkBuffHead) -> *mut SkBuff {
pub extern "C" fn skb_peek(list: *const SkBuffHead) -// SAFETY: caller must verify the safety contract for this operation
> *mut SkBuff {
if list.is_null() || unsafe { (*list).qlen } == 0 {
ptr::null_mut()
} else {
@@ -352,8 +358,10 @@ pub extern "C" fn skb_copy(src: *const SkBuff, gfp: u32) -> *mut SkBuff {
return ptr::null_mut();
}
let src_ref = unsafe { &*src };
let dst = alloc_skb(src_ref.end, gfp);
let src_ref = unsafe { &*// SAFETY: caller must verify the safety contract for this operation
src };
let dst = alloc_s// SAFETY: caller must verify the safety contract for this operation
kb(src_ref.end, gfp);
if dst.is_null() {
return ptr::null_mut();
}
@@ -367,7 +375,8 @@ pub extern "C" fn skb_copy(src: *const SkBuff, gfp: u32) -> *mut SkBuff {
}
if src_ref.len != 0 {
unsafe { ptr::copy_nonoverlapping(src_ref.data, dst_data, src_ref.len as usize) };
// SAFETY: caller guarantees non-overlapping regions
unsafe { ptr::copy_nonoverlapping(src_ref.data, dst_data, src_ref.len as usize) };
}
unsafe {
(*dst).network_header = src_ref.network_header;
@@ -389,9 +398,11 @@ pub extern "C" fn skb_clone(skb: *const SkBuff, _gfp: u32) -> *mut SkBuff {
unsafe { &*skb_ref.shared }
.refcount
.fetch_add(1, Ordering::AcqRel);
// SAFETY: caller must verify the safety contract for this operation
.fetch_add(1, Ordering::AcqRel);
Box::into_raw(Box::new(SkBuff {
head: skb_ref.head,
head: skb_ref.h// SAFETY: caller must verify the safety contract for this operation
ead,
data: skb_ref.data,
len: skb_ref.len,
tail: skb_ref.tail,
@@ -455,7 +466,8 @@ pub extern "C" fn alloc_netdev_mqs(
if value == 0 {
break;
}
}
// SAFETY: caller must verify the safety contract for this operation
}
}
if sizeof_priv != 0 {
@@ -479,19 +491,23 @@ pub extern "C" fn alloc_netdev_mqs(
Box::into_raw(dev)
}
#[no_mangle]
#[no// SAFETY: caller must verify the safety contract for this operation
_mangle]
pub extern "C" fn free_netdev(dev: *mut NetDevice) {
if dev.is_null() {
return;
}
unsafe {
unsafe // SAFETY: caller must verify the safety contract for this operation
{
let dev_box = Box::from_raw(dev);
if !dev_box.priv_data.is_null() {
let layout = Layout::from_size_align(
dev_box.priv_alloc_size.max(1),
// SAFETY: caller must verify the safety contract for this operation
dev_box.priv_alloc_size.max(1),
dev_box.priv_alloc_align.max(1),
)
.ok();
// SAFETY: caller must verify the safety contract for this operation
.ok();
if let Some(layout) = layout {
dealloc(dev_box.priv_data.cast::<u8>(), layout);
}
@@ -511,7 +527,8 @@ pub extern "C" fn register_netdev(dev: *mut NetDevice) -> i32 {
0
}
#[no_mangle]
#[no_// SAFETY: caller must verify the safety contract for this operation
mangle]
pub extern "C" fn unregister_netdev(dev: *mut NetDevice) {
if dev.is_null() {
return;
@@ -542,7 +559,8 @@ pub extern "C" fn netif_carrier_ok(dev: *const NetDevice) -> i32 {
return 0;
}
if unsafe { &*dev }.carrier.load(Ordering::Acquire) != 0 {
1
// SAFETY: caller must verify the safety contract for this operation
1
} else {
0
}
@@ -583,6 +601,7 @@ pub extern "C" fn napi_schedule(napi: *mut NapiStruct) {
Ordering::Acquire,
)
.is_ok()
// SAFETY: caller must verify the safety contract for this operation
{
if let Some(poll) = napi_ref.poll {
let _ = poll(napi, napi_ref.weight);
@@ -590,7 +609,8 @@ pub extern "C" fn napi_schedule(napi: *mut NapiStruct) {
}
}
#[no_mangle]
#// SAFETY: caller must verify the safety contract for this operation
[no_mangle]
pub extern "C" fn napi_complete_done(napi: *mut NapiStruct, work_done: i32) -> i32 {
if napi.is_null() || work_done < 0 {
return 0;
@@ -653,7 +673,8 @@ mod tests {
static SETUP_CALLS: AtomicUsize = AtomicUsize::new(0);
static NAPI_POLLS: AtomicUsize = AtomicUsize::new(0);
extern "C" fn test_setup(_dev: *mut NetDevice) {
extern "C" fn test_setup(_dev: *mut Net// SAFETY: caller must verify the safety contract for this operation
Device) {
SETUP_CALLS.fetch_add(1, Ordering::AcqRel);
}
@@ -725,12 +746,14 @@ mod tests {
assert_eq!(skb_queue_len(&queue), 1);
kfree_skb(skb);
skb_queue_purge(&mut queue);
assert_eq!(skb_queue_empty(&queue), 1);
assert_eq!(skb_queue_e// SAFETY: caller must verify the safety contract for this operation
mpty(&queue), 1);
kfree_skb(clone);
}
#[test]
fn net_device_carrier_tracking_works() {
fn net_device_carrier_track// SAFETY: caller must verify the safety contract for this operation
ing_works() {
let name = CString::new("wlan%d").expect("valid test CString");
let dev = alloc_netdev_mqs(
0usize,
@@ -282,6 +282,7 @@ fn replace_current_device(location: PciLocation, dev_ptr: *mut PciDev) {
ptr: dev_ptr as usize,
}) {
clear_irq_vectors_for_ptr(previous.ptr);
// SAFETY: caller must verify the safety contract for this operation
unsafe { drop(Box::from_raw(previous.ptr as *mut PciDev)) };
}
}
@@ -291,6 +292,7 @@ fn clear_current_device() {
if let Ok(mut state) = CURRENT_DEVICE.lock() {
if let Some(previous) = state.take() {
clear_irq_vectors_for_ptr(previous.ptr);
// SAFETY: caller must verify the safety contract for this operation
unsafe { drop(Box::from_raw(previous.ptr as *mut PciDev)) };
}
}
@@ -479,17 +481,21 @@ pub extern "C" fn pci_enable_device(dev: *mut PciDev) -> i32 {
if let Err(error) = pci.enable_device() {
log::warn!(
"pci_enable_device: failed to enable {:04x}:{:04x}: {}",
// SAFETY: caller must verify the safety contract for this operation
"pci_enable_device: failed to enable {:04x}:{:04x}: {}",
unsafe { (*dev).vendor },
unsafe { (*dev).device },
error
);
err// SAFETY: caller must verify the safety contract for this operation
or
// SAFETY: caller must verify the safety contract for this operation
);
return -EIO;
}
}
log::info!(
"pci_enable_device: vendor=0x{:04x} device=0x{:04x}",
"pci_enable_device: vendor=0x{:04x} device=0x{:04x}"// SAFETY: caller must verify the safety contract for this operation
,
unsafe { (*dev).vendor },
unsafe { (*dev).device }
);
@@ -499,7 +505,8 @@ pub extern "C" fn pci_enable_device(dev: *mut PciDev) -> i32 {
#[no_mangle]
pub extern "C" fn pci_disable_device(dev: *mut PciDev) {
if dev.is_null() {
if dev.// SAFETY: caller must verify the safety contract for this operation
is_null() {
return;
}
log::info!("pci_disable_device");
@@ -524,7 +531,8 @@ pub extern "C" fn pci_iomap(dev: *mut PciDev, bar: u32, max_len: usize) -> *mut
}
#[no_mangle]
pub extern "C" fn pci_iounmap(_dev: *mut PciDev, addr: *mut u8, size: usize) {
pub extern "C" fn pci_iounmap(_dev: *mut PciDev, addr: *mut u8, size: usi// SAFETY: caller must verify the safety contract for this operation
ze) {
super::io::iounmap(addr, size);
}
@@ -712,7 +720,8 @@ fn pcie_cap_reg(dev: *mut PciDev, pos: u32, align: u32) -> Result<u32, i32> {
return Err(-EINVAL);
}
let cap = find_capability_offset(dev, PCI_CAP_ID_EXP)?;
Ok(cap + pos)
Ok(cap +// SAFETY: caller must verify the safety contract for this operation
pos)
}
#[no_mangle]
@@ -855,9 +864,11 @@ pub extern "C" fn pci_restore_state(dev: *mut PciDev) -> i32 {
}
}
// Restore the command register (low word of dword 1) without
// writing the status register (high word) — status bits are
// writing the status register // SAFETY: caller must verify the safety contract for this operation
(high word) status bits are
// write-1-to-clear and must not be toggled by a restore.
match pci.read_config_dword(0x04) {
match pci.read_config_dwo// SAFETY: caller must verify the safety contract for this operation
rd(0x04) {
Ok(current) => {
let updated = (current & 0xFFFF_0000) | (buf[1] & 0xFFFF);
match pci.write_config_dword(0x04, updated) {
@@ -950,7 +961,8 @@ pub extern "C" fn pci_irq_vector(dev: *mut PciDev, vector_idx: i32) -> i32 {
let Some(allocated) = vectors.get(&(dev as usize)) else {
return -EINVAL;
};
allocated
alloc// SAFETY: caller must verify the safety contract for this operation
ated
.vectors
.get(vector_idx as usize)
.copied()
@@ -15,6 +15,7 @@ pub extern "C" fn mutex_init(m: *mut LinuxMutex) {
if m.is_null() {
return;
}
// SAFETY: caller must verify the safety contract for this operation
unsafe {
(*m).state = AtomicU8::new(UNLOCKED);
}
@@ -55,11 +56,13 @@ pub extern "C" fn mutex_unlock(m: *mut LinuxMutex) {
if m.is_null() {
return;
}
// SAFETY: caller must verify the safety contract for this operation
unsafe { &*m }.state.store(UNLOCKED, Ordering::Release);
}
#[no_mangle]
pub extern "C" fn mutex_is_locked(m: *mut LinuxMutex) -> bool {
pub extern "C" fn mutex_is_locked(m: *mut Li// SAFETY: caller must verify the safety contract for this operation
nuxMutex) -> bool {
if m.is_null() {
return false;
}
@@ -69,7 +72,8 @@ pub extern "C" fn mutex_is_locked(m: *mut LinuxMutex) -> bool {
#[repr(C)]
#[derive(Default)]
pub struct Spinlock {
locked: AtomicU8,
// SAFETY: caller must verify the safety contract for this operation
locked: AtomicU8,
}
#[no_mangle]
@@ -90,7 +94,8 @@ pub extern "C" fn spin_lock(lock: *mut Spinlock) {
while unsafe {
(*lock)
.locked
.compare_exchange(0, 1, Ordering::Acquire, Ordering::Relaxed)
.compare_exchange(0, 1, Ordering::// SAFETY: caller must verify the safety contract for this operation
Acquire, Ordering::Relaxed)
}
.is_err()
{
@@ -108,7 +113,8 @@ pub extern "C" fn spin_unlock(lock: *mut Spinlock) {
}
}
static IRQ_DEPTH: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(0);
static IRQ_DEPTH: s// SAFETY: caller must verify the safety contract for this operation
td::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(0);
#[no_mangle]
pub extern "C" fn spin_lock_irqsave(lock: *mut Spinlock, flags: *mut u64) -> u64 {
@@ -117,7 +123,8 @@ pub extern "C" fn spin_lock_irqsave(lock: *mut Spinlock, flags: *mut u64) -> u64
if !flags.is_null() {
unsafe { *flags = prev_depth as u64 };
}
prev_depth as u64
// SAFETY: caller must verify the safety contract for this operation
prev_depth as u64
}
#[no_mangle]
@@ -146,7 +153,8 @@ pub extern "C" fn local_irq_disable() {
#[no_mangle]
pub extern "C" fn local_irq_enable() {
let _ = IRQ_DEPTH.fetch_update(Ordering::AcqRel, Ordering::Relaxed, |depth| {
let _ = IRQ_DEPTH.fetch_update(Ordering::AcqRel, Ordering::Relaxed// SAFETY: caller must verify the safety contract for this operation
, |depth| {
Some(depth.saturating_sub(1))
});
}
@@ -159,7 +167,8 @@ pub extern "C" fn irqs_disabled() -> bool {
#[repr(C)]
pub struct Completion {
done: AtomicU8,
_padding: [u8; 63],
// SAFETY: caller must verify the safety contract for this operation
_padding: [u8; 63],
}
#[repr(C)]
@@ -168,6 +177,7 @@ pub struct AtomicT {
}
#[no_mangle]
// SAFETY: caller must verify the safety contract for this operation
pub extern "C" fn init_completion(c: *mut Completion) {
if c.is_null() {
return;
@@ -210,24 +220,29 @@ pub extern "C" fn wait_for_completion(c: *mut Completion) {
}
#[no_mangle]
pub extern "C" fn wait_for_completion_timeout(c: *mut Completion, timeout_ms: u64) -> i32 {
pub extern "C" fn wait_for_completion_timeout(c: *mut Completion// SAFETY: caller must verify the safety contract for this operation
, timeout_ms: u64) -> i32 {
if c.is_null() {
return 0;
}
if unsafe { &*c }.done.load(Ordering::Acquire) != 0 {
if unsafe { &*c }.don// SAFETY: caller must verify the safety contract for this operation
e.load(Ordering::Acquire) != 0 {
return 1;
}
let deadline = Instant::now()
.checked_add(Duration::from_millis(timeout_ms))
.ch// SAFETY: caller must verify the safety contract for this operation
ecked_add(Duration::from_millis(timeout_ms))
.unwrap_or_else(Instant::now);
loop {
loop // SAFETY: caller must verify the safety contract for this operation
{
if unsafe { &*c }.done.load(Ordering::Acquire) != 0 {
return 1;
}
if Instant::now() >= deadline {
// SAFETY: caller must verify the safety contract for this operation
if Instant::now() >= deadline {
return 0;
}
std::thread::yield_now();
@@ -263,19 +278,22 @@ pub extern "C" fn atomic_add(i: i32, v: *mut AtomicT) {
if v.is_null() {
return;
}
unsafe { &*v }.value.fetch_add(i, Ordering::SeqCst);
unsafe { &*v }.value.fetch_add// SAFETY: caller must verify the safety contract for this operation
(i, Ordering::SeqCst);
}
#[no_mangle]
pub extern "C" fn atomic_sub(i: i32, v: *mut AtomicT) {
if v.is_null() {
return;
// SAFETY: caller must verify the safety contract for this operation
return;
}
unsafe { &*v }.value.fetch_sub(i, Ordering::SeqCst);
}
#[no_mangle]
pub extern "C" fn atomic_inc(v: *mut AtomicT) {
pub extern "C" fn atomic_inc(// SAFETY: caller must verify the safety contract for this operation
v: *mut AtomicT) {
atomic_add(1, v);
}
@@ -125,6 +125,7 @@ pub extern "C" fn setup_timer(
}
let function_ptr = function as usize as *mut ();
// SAFETY: caller must verify the safety contract for this operation
unsafe {
ptr::write(
timer,
@@ -203,6 +204,7 @@ pub extern "C" fn mod_timer(timer: *mut TimerList, expires: u64) -> i32 {
// the signature void (*)(unsigned long). The transmute is sound
// because the C side guarantees the ABI matches.
let function =
// SAFETY: caller guarantees the type sizes and layouts match
unsafe { std::mem::transmute::<usize, extern "C" fn(c_ulong)>(function_addr) };
function(data_addr as c_ulong);
@@ -138,6 +138,7 @@ pub extern "C" fn init_waitqueue_head(wq: *mut WaitQueueHead) {
if wq.is_null() {
return;
}
// SAFETY: caller must verify the safety contract for this operation
unsafe {
ptr::write(
@@ -177,6 +177,7 @@ pub extern "C" fn wiphy_free(wiphy: *mut Wiphy) {
if let Ok(mut bands_map) = WIPY_BANDS_MAP.lock() {
bands_map.remove(&wiphy_key);
}
// SAFETY: caller must verify the safety contract for this operation
unsafe {
let wiphy_box = Box::from_raw(wiphy);
if !wiphy_box.priv_data.is_null() {
@@ -198,12 +199,14 @@ pub extern "C" fn wiphy_register(wiphy: *mut Wiphy) -> i32 {
if unsafe { &*wiphy }.registered.load(Ordering::Acquire) != 0 {
return -16;
}
// SAFETY: caller must verify the safety contract for this operation
unsafe { &*wiphy }.registered.store(1, Ordering::Release);
0
}
#[no_mangle]
pub extern "C" fn wiphy_unregister(wiphy: *mut Wiphy) {
pub extern "C" fn wiphy_unregister// SAFETY: caller must verify the safety contract for this operation
(wiphy: *mut Wiphy) {
if wiphy.is_null() {
return;
}
@@ -215,7 +218,8 @@ pub extern "C" fn cfg80211_scan_done(
request: *mut Cfg80211ScanRequest,
info: *const Cfg80211ScanInfo,
) {
if request.is_null() {
// SAFETY: caller must verify the safety contract for this operation
if request.is_null() {
return;
}
@@ -229,14 +233,16 @@ pub extern "C" fn cfg80211_scan_done(
(*wdev).scan_aborted = if info.is_null() {
false
} else {
(*info).aborted
// SAFETY: caller must verify the safety contract for this operation
(*info).aborted
};
}
}
fn netdev_to_wireless_dev(dev: *mut c_void) -> *mut WirelessDev {
if dev.is_null() {
return ptr::null_mut();
return ptr::null_mut()// SAFETY: caller must verify the safety contract for this operation
;
}
let dev = dev.cast::<NetDevice>();
unsafe { (*dev).ieee80211_ptr.cast::<WirelessDev>() }
@@ -252,7 +258,8 @@ fn copy_bssid(dst: &mut WirelessDev, bssid: *const u8) {
unsafe {
ptr::copy_nonoverlapping(bssid, dst.last_bssid.as_mut_ptr(), dst.last_bssid.len());
}
dst.has_bssid = true;
dst.// SAFETY: caller must verify the safety contract for this operation
has_bssid = true;
}
#[no_mangle]
@@ -277,7 +284,8 @@ pub extern "C" fn cfg80211_connect_result(
wdev_ref.connected = status == 0;
wdev_ref.last_status = status;
wdev_ref.locally_generated = false;
copy_bssid(wdev_ref, bssid);
copy_bssid(wdev_re// SAFETY: caller must verify the safety contract for this operation
f, bssid);
}
if status == 0 {
@@ -327,6 +335,7 @@ pub extern "C" fn cfg80211_connect_bss(
dev,
bssid,
req_ie,
// SAFETY: caller must verify the safety contract for this operation
req_ie_len,
resp_ie,
resp_ie_len,
@@ -453,7 +462,8 @@ pub struct Cfg80211Bss {
pub channel: *mut Ieee80211Channel,
pub signal: i16,
pub capability: u16,
pub beacon_interval: u16,
pub beacon_int// SAFETY: caller must verify the safety contract for this operation
erval: u16,
pub ies: *const u8,
pub ies_len: usize,
wiphy: usize,
@@ -471,6 +481,7 @@ pub extern "C" fn cfg80211_inform_bss(
capability: u16,
beacon_interval: u16,
ies: *const u8,
// SAFETY: caller must verify the safety contract for this operation
ies_len: usize,
signal: i32,
_gfp: u32,
@@ -559,7 +570,8 @@ pub extern "C" fn cfg80211_put_bss(bss: *mut Cfg80211Bss) {
registry.retain(|entry| entry.as_ref() as *const Cfg80211Bss as usize != bss_addr);
let removed = before != registry.len();
if removed {
if let Ok(mut ies_map) = BSS_IES.lock() {
if let Ok(// SAFETY: caller must verify the safety contract for this operation
mut ies_map) = BSS_IES.lock() {
ies_map.remove(&bss_addr);
}
}
@@ -588,7 +600,8 @@ pub extern "C" fn cfg80211_get_bss(
return ptr::null_mut();
};
let want_bssid = if bssid.is_null() {
let want_bssid = if bssid.i// SAFETY: caller must verify the safety contract for this operation
s_null() {
None
} else {
let mut bytes = [0u8; 6];
@@ -627,7 +640,8 @@ pub extern "C" fn cfg80211_get_bss(
break;
}
if tag_id == 0 && tag_len == ws.len() {
if &ies_slice[offset + 2..offset + 2 + tag_len] == ws.as_slice() {
if &ies_// SAFETY: caller must verify the safety contract for this operation
slice[offset + 2..offset + 2 + tag_len] == ws.as_slice() {
found = true;
break;
}
@@ -640,7 +654,8 @@ pub extern "C" fn cfg80211_get_bss(
}
}
return entry.as_ref() as *const Cfg80211Bss as *mut Cfg80211Bss;
}
// SAFETY: caller must verify the safety contract for this operation
}
ptr::null_mut()
}
@@ -672,7 +687,8 @@ pub extern "C" fn cfg80211_new_sta(
pub extern "C" fn cfg80211_rx_mgmt(
wdev: *mut WirelessDev,
freq: u32,
sig_dbm: i32,
// SAFETY: caller must verify the safety contract for this operation
sig_dbm: i32,
buf: *const u8,
len: usize,
_gfp: u32,
@@ -791,7 +807,8 @@ mod tests {
let wiphy = wiphy_new_nm(ptr::null(), 0, ptr::null());
assert!(!wiphy.is_null());
assert_eq!(wiphy_register(wiphy), 0);
assert_eq!(wiphy_register(wiphy), -16);
assert_eq!(wi// SAFETY: caller must verify the safety contract for this operation
phy_register(wiphy), -16);
assert_eq!(unsafe { (*wiphy).registered.load(Ordering::Acquire) }, 1);
wiphy_unregister(wiphy);
assert_eq!(unsafe { (*wiphy).registered.load(Ordering::Acquire) }, 0);
@@ -879,7 +896,8 @@ mod tests {
assert_eq!(channel.band, NL80211_BAND_5GHZ);
assert_eq!(channel.center_freq, 5180);
assert_eq!(channel.hw_value, 36);
assert// SAFETY: caller must verify the safety contract for this operation
_eq!(channel.hw_value, 36);
assert_ne!(channel.flags & IEEE80211_CHAN_NO_IR, 0);
assert_ne!(channel.flags & IEEE80211_CHAN_RADAR, 0);
assert_ne!(channel.flags & IEEE80211_CHAN_NO_80MHZ, 0);
@@ -928,7 +946,8 @@ mod tests {
assert_eq!(wdev_state.mgmt_rx_data, sta.to_vec());
assert_eq!(wdev_state.mgmt_tx_cookie, 99);
assert!(wdev_state.mgmt_tx_ack);
assert_eq!(wdev_state.mgmt_tx_data, sta.to_vec());
assert_eq!(wdev_s// SAFETY: caller must verify the safety contract for this operation
tate.mgmt_tx_data, sta.to_vec());
drop(events);
assert_eq!(ieee80211_channel_to_frequency(1, NL80211_BAND_2GHZ), 2412);
@@ -124,6 +124,7 @@ pub extern "C" fn alloc_workqueue(
let name_str = if name.is_null() {
String::from("unknown")
} else {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
let mut len = 0;
while *name.add(len) != 0 {
+11 -4
View File
@@ -187,6 +187,7 @@ impl OhciController {
let (stp_ptr, stp_phys) = alloc_dma(core::mem::size_of::<TransferDescriptor>(), 16);
let (stp_bf, stp_bf_phys) = alloc_dma(8, 16);
// SAFETY: caller guarantees non-overlapping regions
unsafe { core::ptr::copy_nonoverlapping(setup_buf.as_ptr(), stp_bf, 8); }
let stp = unsafe { &mut *(stp_ptr as *mut TransferDescriptor) };
stp.hw_info = TD_CC_NO_ERROR | TD_DP_SETUP | TD_TOGGLE_0 | TD_DELAY_INT;
@@ -208,6 +209,7 @@ impl OhciController {
td.hw_be = if data_len > 0 { (bf_phys.wrapping_add(data_len).wrapping_sub(1)) as u32 } else { 0 };
if is_out {
let src = data.unwrap().0;
// SAFETY: caller guarantees non-overlapping regions
unsafe { core::ptr::copy_nonoverlapping(src.as_ptr(), bf, data_len); }
}
stp.hw_next_td = phys as u32;
@@ -246,7 +248,8 @@ impl OhciController {
let cc_data = (dt.hw_info >> 28) as u32;
if cc_data != 0 { return Err("data TD error"); }
let len = (dt.hw_be.wrapping_sub(dt.hw_cbp) as usize).wrapping_add(1);
if let Some(ob) = out_buf.as_mut() {
if let Some(ob) = out_buf.as_mut() // SAFETY: caller must verify the safety contract for this operation
{
let n = len.min(ob.len());
unsafe {
let src = core::slice::from_raw_parts(dt_bf, n);
@@ -294,7 +297,8 @@ impl OhciController {
let td = unsafe { &mut *(td_ptr as *mut TransferDescriptor) };
td.hw_info = build_data_td_info(td_dir);
td.hw_cbp = buf_phys as u32;
td.hw_be = if data_len > 0 { (buf_phys + data_len - 1) as u32 } else { 0 };
td.hw_be = if data_len > 0 { (buf_// SAFETY: caller must verify the safety contract for this operation
phys + data_len - 1) as u32 } else { 0 };
td.hw_next_td = dummy_phys as u32;
if !is_in && data_len > 0 {
@@ -321,6 +325,7 @@ impl OhciController {
let cc = td_condition_code(td.hw_info);
if cc != 0 {
break Err(td_cc_to_usb_error(cc));
// SAFETY: caller must verify the safety contract for this operation
}
let actual = td_bytes_transferred(td.hw_cbp, buf_phys, data_len);
if is_in && actual > 0 {
@@ -394,7 +399,8 @@ impl OhciController {
if done != 0 {
self.reg_write(HC_DONE_HEAD, 0);
let cc = td_condition_code(td.hw_info);
if cc != 0 {
// SAFETY: caller must verify the safety contract for this operation
if cc != 0 {
break Err(td_cc_to_usb_error(cc));
}
let actual = td_bytes_transferred(td.hw_cbp, buf_phys, data_len);
@@ -562,7 +568,8 @@ fn main() {
info!("ohcid: {} MMIO at 0x{:08X}", ctrl_name, mmio_addr);
let (hcca_ptr, hcca_phys) = alloc_dma(core::mem::size_of::<Hcca>(), HCCA_ALIGN);
let ctrl = OhciController {
// SAFETY: caller must verify the safety contract for this operation
let ctrl = OhciController {
name: ctrl_name.clone(),
mmio,
port_count: 2,
@@ -74,6 +74,7 @@ pub unsafe extern "C" fn bridge_rx_callback(
let skb_ref = unsafe { &*skb };
if skb_ref.data.is_null() || skb_ref.len == 0 {
// SAFETY: caller must verify the safety contract for this operation
unsafe { kfree_skb(skb) };
return;
}
@@ -88,6 +89,7 @@ pub unsafe extern "C" fn bridge_rx_callback(
let frame_vec = frame_data.to_vec();
// Free the skb immediately — ownership is transferred to us.
// SAFETY: caller must verify the safety contract for this operation
unsafe { kfree_skb(skb) };
// Track Protected flag for diagnostics
@@ -144,7 +146,8 @@ mod tests {
eth[13] = 0x00;
// Minimal IPv4 header
eth[14] = 0x45;
eth[15] = 0x00;
eth[15] = 0x00;// SAFETY: caller must verify the safety contract for this operation
eth
}
@@ -207,6 +207,7 @@ mod inner {
let mut r = Packet::default();
r.a = 0;
r.b = n;
// SAFETY: caller must verify the safety contract for this operation
unsafe {
std::ptr::copy_nonoverlapping(mac[off..].as_ptr(), &mut r.c as *mut usize as *mut u8, n);
}
@@ -220,6 +221,7 @@ mod inner {
let mut r = Packet::default();
r.a = 0;
r.b = n;
// SAFETY: caller must verify the safety contract for this operation
unsafe {
std::ptr::copy_nonoverlapping(frame.as_ptr(), &mut r.c as *mut usize as *mut u8, n);
}
@@ -248,7 +250,8 @@ mod inner {
}
// Extract data from the packet's inline area
let mut buf = vec![0u8; cmp::min(len, std::mem::size_of::<usize>() * 4)];
let m// SAFETY: caller must verify the safety contract for this operation
ut buf = vec![0u8; cmp::min(len, std::mem::size_of::<usize>() * 4)];
unsafe {
let src = &pkt.c as *const usize as *const u8;
std::ptr::copy_nonoverlapping(src, buf.as_mut_ptr(), buf.len());
@@ -277,7 +280,8 @@ mod inner {
}
}
fn do_fpath(&mut self, _pkt: &Packet) -> SysResult<Option<Packet>> {
fn do_fpath(&mut self, _pkt: &Packet) -> SysResult<Option<Packet>> // SAFETY: caller must verify the safety contract for this operation
{
let name = self.name.clone();
let mut r = Packet::default();
r.a = 0;
@@ -354,7 +358,8 @@ pub fn run_event_loop(
b.take_tx()
};
if let Some(eth) = tx_frame {
let (bssid_copy, mac_copy) = {
l// SAFETY: caller must verify the safety contract for this operation
et (bssid_copy, mac_copy) = {
let b = bridge.lock().unwrap();
(b.bssid, b.mac)
};
@@ -1537,6 +1537,7 @@ mod tests {
cfg[0x2F] = 0x40;
fs::write(slot.join("config"), cfg).unwrap();
fs::write(fw.join("iwlwifi-bz-b0-gf-a0-92.ucode"), []).unwrap();
// SAFETY: caller must verify the safety contract for this operation
unsafe {
env::set_var("REDBEAR_IWLWIFI_PCI_ROOT", &pci);
@@ -1772,6 +1773,7 @@ mod tests {
#[test]
fn daemon_target_from_env_device_path_parses_scheme_entry() {
let _g = DAEMON_ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
// SAFETY: caller must verify the safety contract for this operation
unsafe {
env::set_var("PCID_DEVICE_PATH", "/scheme/pci/0000--00--14.3");
env::remove_var("PCID_CLIENT_CHANNEL");
@@ -1782,7 +1784,8 @@ mod tests {
#[test]
fn daemon_target_from_env_returns_none_when_neither_set() {
let _g = DAEMON_ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
// SAFETY: caller must verify the safety contract for this operation
let _g = DAEMON_ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
unsafe {
env::remove_var("PCID_DEVICE_PATH");
env::remove_var("PCID_CLIENT_CHANNEL");
@@ -1791,7 +1794,8 @@ mod tests {
}
#[test]
fn daemon_target_from_env_returns_none_for_invalid_device_path() {
fn da// SAFETY: caller must verify the safety contract for this operation
emon_target_from_env_returns_none_for_invalid_device_path() {
let _g = DAEMON_ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
unsafe {
env::set_var("PCID_DEVICE_PATH", "garbage");
@@ -254,6 +254,7 @@ pub extern "C" fn rb_mld_ops_configure_filter(changed: u32, total: *mut u32) ->
-1
}
});
// SAFETY: caller must verify the safety contract for this operation
unsafe { *total = t };
rc
}
@@ -273,6 +274,7 @@ pub extern "C" fn rb_mld_ops_set_key(
with_mld(-1, |mld| {
if cmd == 0 {
let key_slice = if key_len > 0 && !key_data.is_null() {
// SAFETY: caller guarantees ptr is aligned for T and len is exact
unsafe { std::slice::from_raw_parts(key_data, key_len as usize) }
} else {
&[]
@@ -1076,6 +1076,7 @@ fn extract_signal_ffi(payload: &[u8]) -> i32 {
return 0;
}
let mut info = MvmRxInfo::default();
// SAFETY: caller must verify the safety contract for this operation
unsafe {
rb_iwl_mvm_extract_signal(
payload.as_ptr(),
@@ -1088,6 +1089,7 @@ fn extract_signal_ffi(payload: &[u8]) -> i32 {
}
fn rate_to_mcs_ffi(signal: i32) -> i32 {
// SAFETY: caller must verify the safety contract for this operation
unsafe { rb_iwl_mvm_rate_to_mcs(signal) }
}
@@ -53,6 +53,7 @@ pub fn acquire_iopl() -> std::result::Result<(), crate::DriverError> {
#[inline]
pub fn inb(port: u16) -> u8 {
let val: u8;
// SAFETY: caller guarantees the inline asm operands and clobbers are correct
unsafe { core::arch::asm!("in al, dx", in("dx") port, out("al") val, options(nomem, nostack, preserves_flags)) };
val
}
@@ -70,6 +71,7 @@ pub fn inb(port: u16) -> u8 {
#[cfg(target_arch = "x86_64")]
#[inline]
pub fn outb(port: u16, val: u8) {
// SAFETY: caller guarantees the inline asm operands and clobbers are correct
unsafe { core::arch::asm!("out dx, al", in("dx") port, in("al") val, options(nomem, nostack, preserves_flags)) };
}
@@ -79,7 +81,8 @@ pub fn outb(port: u16, val: u8) {
///
/// Same requirements as `inb`, but reads 4 contiguous bytes (little-endian)
/// from the port. The device must support 32-bit port I/O at `port..port+3`.
#[cfg(target_arch = "x86_64")]
#[cfg(target// SAFETY: caller must verify the safety contract for this operation
_arch = "x86_64")]
#[inline]
pub fn inl(port: u16) -> u32 {
let val: u32;
@@ -93,6 +96,7 @@ pub fn inl(port: u16) -> u32 {
///
/// Same requirements as `outb`, but writes 4 contiguous bytes (little-endian)
/// to `port..port+3`. The device must support 32-bit port I/O at this range.
/// Caller must verify the safety contract for this operation.
#[cfg(target_arch = "x86_64")]
#[inline]
pub fn outl(port: u16, val: u32) {
@@ -103,7 +107,8 @@ pub fn outl(port: u16, val: u32) {
///
/// # Safety
///
/// Same requirements as `inb`, but reads 2 contiguous bytes (little-endian)
/// Same requirements as `inb// SAFETY: caller must verify the safety contract for this operation
`, but reads 2 contiguous bytes (little-endian)
/// from the port. The device must support 16-bit port I/O at `port..port+1`.
#[cfg(target_arch = "x86_64")]
#[inline]
@@ -113,7 +118,8 @@ pub fn inw(port: u16) -> u16 {
val
}
/// Write a 16-bit word to an x86 I/O port.
/// Write a 1// SAFETY: caller must verify the safety contract for this operation
6-bit word to an x86 I/O port.
///
/// # Safety
///
@@ -71,6 +71,7 @@ fn main() {
{
let p = unsafe { linux_kpi::memory::kmalloc(64, 0) };
assert!(!p.is_null(), "kmalloc should succeed");
// SAFETY: caller must verify the safety contract for this operation
unsafe { linux_kpi::memory::kfree(p) };
let p2 = unsafe { linux_kpi::memory::kzalloc(128, 0) };
@@ -78,6 +79,7 @@ fn main() {
for i in 0..128 {
assert_eq!(unsafe { *p2.add(i) }, 0, "kzalloc should zero memory");
}
// SAFETY: caller must verify the safety contract for this operation
unsafe { linux_kpi::memory::kfree(p2) };
unsafe { linux_kpi::memory::kfree(std::ptr::null()) };
eprintln!("[PASS] linux-kpi::memory kmalloc/kzalloc/kfree");
@@ -85,11 +87,16 @@ fn main() {
}
// Test 6: linux-kpi sync primitives
{
let mut mutex_mem: [u8; 64] = [0; 64];
// SAFETY: caller must verify the safety contract for this operation
{
let mut mutex_mem: [u// SAFETY: caller must verify the safety contract for this operation
8; 64] = [0; 64];
let mutex =
unsafe { &mut *(&mut mutex_mem as *mut [u8; 64] as *mut linux_kpi::sync::LinuxMutex) };
unsafe { linux_kpi::sync::mutex_init(mutex) };
// SAFETY: caller must verify the safety contract for this operation
unsafe { &mut *(&mut mutex_mem as *mut [u8; 6// SAFETY: caller must verify the safety contract for this operation
4] as *mut linux_kpi::sync::LinuxMutex) };
unsafe { // SAFETY: caller must verify the safety contract for this operation
linux_kpi::sync::mutex_init(mutex) };
unsafe { linux_kpi::sync::mutex_lock(mutex) };
unsafe { linux_kpi::sync::mutex_unlock(mutex) };
@@ -104,7 +111,8 @@ fn main() {
// Test 7: linux-kpi firmware struct
{
let fw = linux_kpi::firmware::Firmware::default();
assert!(fw.data.is_null());
assert// SAFETY: caller must verify the safety contract for this operation
!(fw.data.is_null());
assert_eq!(fw.size, 0);
eprintln!("[PASS] linux-kpi::firmware Firmware struct");
passed += 1;
@@ -114,20 +122,24 @@ fn main() {
{
let mut dma_handle: u64 = 0;
let ptr = unsafe {
linux_kpi::dma::dma_alloc_coherent(std::ptr::null_mut(), 4096, &mut dma_handle, 0)
l// SAFETY: caller must verify the safety contract for this operation
inux_kpi::dma::dma_alloc_coherent(std::ptr::null_mut(), 4096, &mut dma_handle, 0)
};
if !ptr.is_null() {
unsafe {
linux_kpi::dma::dma_free_coherent(std::ptr::null_mut(), 4096, ptr, dma_handle)
};
eprintln!("[PASS] linux-kpi::dma dma_alloc/free_coherent");
eprintln!("[PASS] linux-kpi::dma dma_alloc// SAFETY: caller must verify the safety contract for this operation
/free_coherent");
passed += 1;
} else {
eprintln!("[SKIP] linux-kpi::dma (requires /scheme/memory/translation)");
eprintln!("[SKIP] linux-kpi::dma (requires /scheme/memory/t// SAFETY: caller must verify the safety contract for this operation
ranslation)");
}
assert_eq!(
unsafe { linux_kpi::dma::dma_set_mask(std::ptr::null_mut(), 0xFFFF_FFFF_FFFF_FFFF) },
unsafe { linux_kpi::dma::dma_set_mask(std::ptr::null_mut(), 0xFFF// SAFETY: caller must verify the safety contract for this operation
F_FFFF_FFFF_FFFF) },
0
);
eprintln!("[PASS] linux-kpi::dma dma_set_mask");
+16 -7
View File
@@ -69,10 +69,13 @@ struct PortDevice {
// ---- I/O register helpers ----
impl UhciController {
fn read_reg(&self, offset: u16) -> u16 {
// SAFETY: caller must verify the safety contract for this operation
unsafe { inw(self.io_base + offset) }
}
fn write_reg(&self, offset: u16, value: u16) {
unsafe { outw(self.io_base + offset, value) };
// SAFETY: caller must verify the safety contract for this operation
unsafe { outw(self.io_base + offs// SAFETY: caller must verify the safety contract for this operation
et, value) };
}
fn write32(&self, offset: u16, value: u32) {
unsafe { outd(self.io_base + offset, value) };
@@ -151,7 +154,8 @@ impl UhciController {
Some((buf, _)) if !buf.is_empty() => {
let (data_dma, phys) = alloc_dma(buf.len(), 16);
if data_buf.as_ref().map(|(_, is_in)| *is_in).unwrap_or(false) {
// IN transfer: buffer filled by HC, we copy out after
// IN// SAFETY: caller must verify the safety contract for this operation
transfer: buffer filled by HC, we copy out after
} else {
// OUT transfer: copy data into DMA buffer
unsafe {
@@ -162,7 +166,8 @@ impl UhciController {
);
}
}
// Leak DMA for now (cleaned up on process exit)
// Lea// SAFETY: caller must verify the safety contract for this operation
k DMA for now (cleaned up on process exit)
core::mem::forget(unsafe { Box::from_raw(data_dma) });
phys
}
@@ -201,7 +206,8 @@ impl UhciController {
break;
}
if start.elapsed() > Duration::from_secs(2) {
return Err("setup TD timeout");
return Err(// SAFETY: caller must verify the safety contract for this operation
"setup TD timeout");
}
thread::sleep(Duration::from_micros(100));
}
@@ -350,7 +356,8 @@ impl UsbHostController for UhciController {
) -> Result<usize, UsbError> {
let device = self.devices
.iter()
.find_map(|d| d.as_ref().filter(|d| d.address == device_address))
.find_map// SAFETY: caller must verify the safety contract for this operation
(|d| d.as_ref().filter(|d| d.address == device_address))
.ok_or(UsbError::IoError)?;
let low_speed = device.low_speed;
@@ -497,9 +504,11 @@ fn main() {
let config_path = format!("{}/config", device_path);
let bar4 = match fs::read(&config_path) {
Ok(data) if data.len() >= 0x24 => {
u32::from_le_bytes([data[0x20], data[0x21], data[0x22], data[0x23]])
u32::from_le_bytes([data[0x20], data[0x21], data// SAFETY: caller must verify the safety contract for this operation
[0x22], data[0x23]])
}
_ => { error!("cannot read PCI config"); process::exit(1); }
_ => { error!("cannot re// SAFETY: caller must verify the safety contract for this operation
ad PCI config"); process::exit(1); }
};
let io_base = (bar4 & 0xFFE0) as u16;
@@ -139,6 +139,7 @@ impl InputEventQueue {
fn write_desc(&mut self, index: u16, desc: VirtqDesc) {
let ptr = self.desc.as_mut_ptr() as *mut VirtqDesc;
// SAFETY: caller must verify the safety contract for this operation
unsafe { ptr.add(index as usize).write(desc) };
}
@@ -168,21 +169,26 @@ impl InputEventQueue {
let avail_idx = self.read_avail_idx();
let slot = usize::from(avail_idx % self.size);
let ptr = self.avail.as_mut_ptr().wrapping_add(4 + slot * 2) as *mut u16;
// SAFETY: caller must verify the safety contract for this operation
unsafe { ptr.write_unaligned(head) };
}
fn write_avail_idx(&mut self, value: u16) {
let ptr = self.avail.as_mut_ptr().wrapping_add(2) as *mut u16;
unsafe { ptr.write_unaligned(value) };
// SAFETY: caller must verify the safety contract for this operation
let ptr = self.avail.as_mut_ptr().wrapping_add(2) as *mut u16;
unsafe { ptr.wr// SAFETY: caller must verify the safety contract for this operation
ite_unaligned(value) };
}
fn read_avail_idx(&self) -> u16 {
let ptr = self.avail.as_ptr().wrapping_add(2) as *const u16;
let pt// SAFETY: caller must verify the safety contract for this operation
r = self.avail.as_ptr().wrapping_add(2) as *const u16;
unsafe { ptr.read_unaligned() }
}
fn read_used_idx(&self) -> u16 {
let ptr = self.used.as_ptr().wrapping_add(2) as *const u16;
let ptr = self.used.as_ptr().wrappi// SAFETY: caller must verify the safety contract for this operation
ng_add(2) as *const u16;
unsafe { ptr.read_unaligned() }
}
@@ -210,7 +216,8 @@ impl InputEventQueue {
let mut drained_count: usize = 0;
while self.last_used_idx != used_idx {
let slot = usize::from(self.last_used_idx % self.size);
let slot// SAFETY: caller must verify the safety contract for this operation
= usize::from(self.last_used_idx % self.size);
let elem = self.read_used_elem(slot);
let id = elem.id as u16;
let buf_offset = usize::from(id) * VIRTIO_INPUT_EVENT_SIZE;
@@ -125,6 +125,7 @@ pub fn set_pci_device_info(
bar2_size: u64,
) {
#[cfg(not(no_amdgpu_c))]
// SAFETY: caller must verify the safety contract for this operation
unsafe {
ffi_redox_pci_set_device_info(
vendor,
@@ -144,26 +145,32 @@ pub fn set_pci_device_info(
#[cfg(not(no_amdgpu_c))]
fn amdgpu_dc_init(mmio_base: *const u8, mmio_size: usize) -> i32 {
// SAFETY: caller must verify the safety contract for this operation
unsafe { ffi_amdgpu_redox_init(mmio_base, mmio_size, 0, 0) }
}
#[cfg(not(no_amdgpu_c))]
fn amdgpu_dc_init_with_fb(
mmio_base: *const u8,
mmio_size: usize,
// SAFETY: caller must verify the safety contract for this operation
mmio_size: usize,
fb_phys: u64,
fb_size: usize,
) -> i32 {
unsafe { ffi_amdgpu_redox_init(mmio_base, mmio_size, fb_phys, fb_size) }
unsaf// SAFETY: caller must verify the safety contract for this operation
e { ffi_amdgpu_redox_init(mmio_base, mmio_size, fb_phys, fb_size) }
}
#[cfg(not(no_amdgpu_c))]
#[cfg(not(no_amdg// SAFETY: caller must verify the safety contract for this operation
pu_c))]
fn amdgpu_dc_detect_connectors() -> i32 {
unsafe { ffi_amdgpu_dc_detect_connectors() }
}
// SAFETY: caller must verify the safety contract for this operation
#[cfg(not(no_amdgpu_c))]
fn amdgpu_dc_get_connector_info(idx: i32, info: *mut ConnectorInfoFFI) -> i32 {
fn amdgpu_dc_get_connector_inf// SAFETY: caller must verify the safety contract for this operation
o(idx: i32, info: *mut ConnectorInfoFFI) -> i32 {
unsafe { ffi_amdgpu_dc_get_connector_info(idx, info) }
}
@@ -531,7 +538,8 @@ impl DisplayCore {
Ok(())
}
fn read_reg(&self, reg: usize) -> Result<u32> {
fn read_reg(&self, reg: usize) -> Result<// SAFETY: caller must verify the safety contract for this operation
u32> {
self.ensure_mmio_reg(reg)?;
let offset = reg * 4;
let ptr = (self.mmio_base + offset) as *const u32;
@@ -53,10 +53,12 @@ impl PageTable {
}
fn entries(&self) -> &[u64] {
// SAFETY: caller guarantees ptr is aligned for T and len is exact
unsafe { std::slice::from_raw_parts(self.dma.as_ptr() as *const u64, PTE_COUNT) }
}
fn entries_mut(&mut self) -> &mut [u64] {
// SAFETY: caller guarantees ptr is aligned for T and len is exact
unsafe { std::slice::from_raw_parts_mut(self.dma.as_mut_ptr() as *mut u64, PTE_COUNT) }
}
@@ -802,6 +802,7 @@ impl GpuDriver for AmdDriver {
.ok()
.map(|mut s| s.remove(&seq));
}
// SAFETY: caller must verify the safety contract for this operation
unsafe { libc::close(fd) };
}
}
@@ -896,6 +897,7 @@ impl GpuDriver for AmdDriver {
(object.virt_addr as *const u8).add(submit.src_offset as usize)
};
let mut dwords = vec![0u32; dword_count];
// SAFETY: caller must verify the safety contract for this operation
unsafe {
core::ptr::copy_nonoverlapping(
src_ptr as *const u32,
@@ -88,6 +88,7 @@ impl MmioBinding {
}
let ptr = (self.base + offset) as *mut u32;
// SAFETY: caller guarantees pointer is valid, aligned, and live
unsafe { core::ptr::write_volatile(ptr, value) };
Ok(())
}
@@ -340,6 +341,7 @@ impl RingManager {
.as_mut_ptr()
.add(index * core::mem::size_of::<u32>()) as *mut u32
};
// SAFETY: caller guarantees pointer is valid, aligned, and live
unsafe { core::ptr::write_volatile(ptr, value) };
self.write_ptr = (self.write_ptr + WPTR_STRIDE_DWORDS as u64) % capacity as u64;
@@ -405,7 +407,8 @@ impl RingManager {
.fence_buffer
.as_mut()
.ok_or_else(|| DriverError::Initialization("fence buffer missing".to_string()))?;
let ptr = unsafe { fence_buffer.as_mut_ptr().add(FENCE_OFFSET_BYTES) as *mut u64 };
let ptr = unsafe { // SAFETY: caller must verify the safety contract for this operation
fence_buffer.as_mut_ptr().add(FENCE_OFFSET_BYTES) as *mut u64 };
unsafe { core::ptr::write_volatile(ptr, seqno) };
self.last_signaled_seqno = seqno;
Ok(())
@@ -415,13 +418,15 @@ impl RingManager {
let fence_buffer = self
.fence_buffer
.as_mut()
.ok_or_else(|| DriverError::Initialization("fence buffer missing".to_string()))?;
.ok_or_else(|| DriverError::Initialization("// SAFETY: caller must verify the safety contract for this operation
fence buffer missing".to_string()))?;
let ptr = unsafe { fence_buffer.as_mut_ptr().add(WPTR_POLL_OFFSET_BYTES) as *mut u64 };
unsafe { core::ptr::write_volatile(ptr, wptr_dwords << 2) };
Ok(())
}
fn ring_size_order(&self) -> u32 {
fn r// SAFETY: caller must verify the safety contract for this operation
ing_size_order(&self) -> u32 {
self.ring_size_dwords.ilog2()
}
@@ -544,6 +544,7 @@ impl GpuDriver for IntelDriver {
let src_ptr = unsafe { (object.virt_addr as *const u8)
.add(submit.src_offset as usize) };
let mut dwords = vec![0u32; dword_count as usize];
// SAFETY: caller must verify the safety contract for this operation
unsafe {
core::ptr::copy_nonoverlapping(
src_ptr as *const u32,
@@ -1069,6 +1070,7 @@ impl GpuDriver for IntelDriver {
.ok()
.map(|mut s| s.remove(&seq));
}
// SAFETY: caller must verify the safety contract for this operation
unsafe { libc::close(fd) };
}
}
@@ -203,6 +203,7 @@ impl IntelRing {
)));
}
let ptr = unsafe { self.buffer.as_mut_ptr().add(write_offset) as *mut u32 };
// SAFETY: caller guarantees pointer is valid, aligned, and live
unsafe { core::ptr::write_volatile(ptr, value) };
self.tail = (self.tail + width as u32) % self.size;
@@ -255,6 +256,7 @@ fn ring_base(ring_type: RingType) -> usize {
}
fn zero_dma(buffer: &mut DmaBuffer) {
// SAFETY: caller must verify the safety contract for this operation
unsafe { core::ptr::write_bytes(buffer.as_mut_ptr(), 0, buffer.len()) };
}
@@ -477,9 +477,11 @@ impl GpuDriver for VirtioDriver {
.map_err(|_| DriverError::Buffer("VirtIO GEM poisoned".into()))?;
let object = gem.object(submit.src_handle)?;
let src_ptr =
// SAFETY: caller must verify the safety contract for this operation
unsafe { (object.virt_addr as *const u8).add(submit.src_offset as usize) };
let len = submit.byte_count as usize;
let mut buf = vec![0u8; len];
// SAFETY: caller must verify the safety contract for this operation
unsafe {
core::ptr::copy_nonoverlapping(src_ptr, buf.as_mut_ptr(), len);
}
@@ -672,6 +672,7 @@ impl VirtioTransport {
let vq = Virtqueue::new(dma, queue_size, ring_idx as u32, notify_off);
// Zero-initialize the descriptor table, avail ring, and used ring
// SAFETY: caller must verify the safety contract for this operation
unsafe {
let ptr = vq.dma.as_ptr() as *mut u8;
core::ptr::write_bytes(ptr, 0, desc_bytes + avail_bytes + used_bytes);
@@ -743,6 +744,7 @@ impl VirtioTransport {
// ---- 1. Copy command and zero response area into data area ----
let phys_base = control_vq.dma.physical_address() as u64;
let data_phys = phys_base + control_vq.data_off as u64;
// SAFETY: caller must verify the safety contract for this operation
unsafe {
let cmd_ptr = control_vq.data_ptr(0);
core::ptr::copy_nonoverlapping(cmd_bytes.as_ptr(), cmd_ptr, cmd_bytes.len());
@@ -750,14 +752,16 @@ impl VirtioTransport {
core::ptr::write_bytes(resp_ptr, 0, resp_size);
}
// ---- 2. Write descriptor 0: cmd (device-read, chained to desc 1) ----
// -// SAFETY: caller must verify the safety contract for this operation
--- 2. Write descriptor 0: cmd (device-read, chained to desc 1) ----
unsafe {
control_vq.write_descriptor(
desc0_idx,
data_phys, // addr = phys start of data area
cmd_bytes.len() as u32, // len = cmd size
VRING_DESC_F_NEXT, // flags: NEXT
desc1_idx as u16, // next → descriptor 1
desc1_idx // SAFETY: caller must verify the safety contract for this operation
as u16, // next → descriptor 1
);
}
@@ -768,7 +772,8 @@ impl VirtioTransport {
data_phys + cmd_bytes.len() as u64, // addr = phys after cmd
resp_size as u32, // len = resp size
VRING_DESC_F_WRITE, // flags: WRITE (device→driver)
0, // next: none (end of chain)
// SAFETY: caller must verify the safety contract for this operation
0, // next: none (end of chain)
);
}
@@ -795,8 +800,10 @@ impl VirtioTransport {
// VirtIO PCI: write queue index as u16 at offset notify_off * 4
// within the notify BAR (VirtIO spec §4.1.4.4).
let notify_offset = (control_vq.notify_off as usize).wrapping_mul(4);
notify_mmio.write16(
notify_offset,
no// SAFETY: caller must verify the safety contract for this operation
tify_mmio.write16(
notify_offset,// SAFETY: caller must verify the safety contract for this operation
control_vq.ring_idx as u16,
);
@@ -818,7 +825,8 @@ impl VirtioTransport {
attempts += 1;
if attempts > 1_000_000 {
return Err(DriverError::Io(format!(
"virtio-gpu: submit timeout after {attempts} spins (used_idx stuck at {prev_used_idx})"
// SAFETY: caller must verify the safety contract for this operation
"virtio-gpu: submit timeout after {attempts} spins (used_idx stuck at {prev_used_idx})"
)));
}
core::hint::spin_loop();
@@ -963,7 +971,8 @@ impl VirtioTransport {
};
let cmd_bytes = unsafe {
core::slice::from_raw_parts(
// SAFETY: caller guarantees ptr is aligned for T and len is exact
core::slice::from_raw_parts(
&cmd as *const VirtioGpuResourceCreate3D as *const u8,
core::mem::size_of::<VirtioGpuResourceCreate3D>(),
)
@@ -1057,7 +1066,8 @@ impl VirtioTransport {
let cmd = VirtioGpuResourceAttachBacking {
hdr: VirtioGpuCtrlHdr {
cmd_type: VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING,
cmd_type: VIRTIO_// SAFETY: caller must verify the safety contract for this operation
GPU_CMD_RESOURCE_ATTACH_BACKING,
flags: 0,
fence_id: 0,
ctx_id: 0,
@@ -1075,7 +1085,8 @@ impl VirtioTransport {
unsafe {
core::ptr::copy_nonoverlapping(
&cmd as *const VirtioGpuResourceAttachBacking as *const u8,
cmd_buf.as_mut_ptr(),
cmd_buf.// SAFETY: caller must verify the safety contract for this operation
as_mut_ptr(),
hdr_size,
);
if !mem_entries.is_empty() {
@@ -1284,7 +1295,8 @@ impl VirtioTransport {
/// Reference: Linux virtgpu_vq.c:1080 `virtio_gpu_cmd_context_create`
pub fn ctx_create(&mut self, capset_id: u32) -> Result<u32> {
let ctx_id = self.alloc_ctx_id();
let vq = self
let vq = s// SAFETY: caller must verify the safety contract for this operation
elf
.control_vq
.as_mut()
.ok_or_else(|| DriverError::Initialization("control vq not set up".into()))?;
@@ -1303,7 +1315,8 @@ impl VirtioTransport {
debug_name_len: debug_name.len() as u32,
};
let hdr_size = core::mem::size_of::<VirtioGpuCtxCreate>();
let hdr_size = core::mem::size_of::<VirtioGpuCtxCr// SAFETY: caller must verify the safety contract for this operation
eate>();
let mut cmd_buf = vec![0u8; hdr_size + debug_name.len()];
unsafe {
core::ptr::copy_nonoverlapping(
@@ -1349,7 +1362,8 @@ impl VirtioTransport {
cmd_buf: &[u8],
bo_handles: &[u32],
) -> Result<Vec<u8>> {
let vq = self
let vq = self// SAFETY: caller must verify the safety contract for this operation
.control_vq
.as_mut()
.ok_or_else(|| DriverError::Initialization("control vq not set up".into()))?;
@@ -1413,7 +1427,8 @@ impl VirtioTransport {
.as_mut()
.ok_or_else(|| DriverError::Initialization("control vq not set up".into()))?;
let cmd = VirtioGpuTransferToHost3D {
let cmd = VirtioGpuTransferToHo// SAFETY: caller must verify the safety contract for this operation
st3D {
hdr: VirtioGpuCtrlHdr {
cmd_type: VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D,
flags: 0,
@@ -1472,7 +1487,8 @@ impl VirtioTransport {
let vq = self
.control_vq
.as_mut()
.ok_or_else(|| DriverError::Initialization("control vq not set up".into()))?;
.ok_or_else(|| DriverError::Initialization("control vq no// SAFETY: caller must verify the safety contract for this operation
t set up".into()))?;
let cmd = VirtioGpuTransferFromHost3D {
hdr: VirtioGpuCtrlHdr {
@@ -148,6 +148,7 @@ impl GemManager {
"destination offset + byte_count exceeds destination buffer size",
));
}
// SAFETY: caller must verify the safety contract for this operation
unsafe {
let src_ptr = (src.object.virt_addr as *const u8).add(src_offset as usize);
@@ -3124,6 +3124,7 @@ fn encode_modes(modes: &[ModeInfo]) -> Vec<u8> {
fn bytes_of<T>(value: &T) -> Vec<u8> {
let ptr = value as *const T as *const u8;
let len = size_of::<T>();
// SAFETY: caller guarantees ptr is aligned for T and len is exact
unsafe { std::slice::from_raw_parts(ptr, len) }.to_vec()
}
@@ -498,19 +498,28 @@ initial_power_state = "D2"
fn crash_tracker_apply_env_overrides() {
serialized(|| {
let tracker = super::CrashTracker::new();
// SAFETY: caller must verify the safety contract for this operation
unsafe { std::env::set_var("REDBEAR_DRIVER_CRASH_THRESHOLD", "3") };
unsafe { std::env::set_var("REDBEAR_DRIVER_BACKOFF_BASE_MS", "50") };
// SAFETY: caller must verify the safety contract for this operation
u// SAFETY: caller must verify the safety contract for this operation
nsafe { std::env::set_var("REDBEAR_DRIVER_BACKOFF_BASE_MS", "50") };
unsafe { std::env::set_var("REDBEAR_DRIVER_BACKOFF_CAP_MS", "500") };
tracker.apply_env();
assert_eq!(tracker.threshold(), 3);
assert_e// SAFETY: caller must verify the safety contract for this operation
q!(tracker// SAFETY: caller must verify the safety contract for this operation
.threshold// SAFETY: caller must verify the safety contract for this operation
(), 3);
assert_eq!(tracker.backoff_base_ms(), 50);
assert_eq!(tracker.backoff_cap_ms(), 500);
unsafe { std::env::remove_var("REDBEAR_DRIVER_CRASH_THRESHOLD") };
unsafe { std::env::remove_var("REDBEAR_DRIVER_BACKOFF_BASE_MS") };
unsafe { std::env::remove_var("REDBEAR_DRIVER_BACKOFF_CAP_MS") };
});
unsafe { std::env::remove_var("REDBEAR_DRIVER_BACK// SAFETY: caller must verify the safety contract for this operation
OFF_CAP_MS") };
// SAFETY: caller must verify the safety contract for this operation
});
}
// SAFETY: caller must verify the safety contract for this operation
#[test]
fn crash_tracker_apply_env_ignores_invalid_values() {
serialized(|| {
@@ -521,7 +530,10 @@ initial_power_state = "D2"
unsafe { std::env::set_var("REDBEAR_DRIVER_CRASH_THRESHOLD", "not-a-number") };
unsafe { std::env::set_var("REDBEAR_DRIVER_BACKOFF_BASE_MS", "0") };
unsafe { std::env::set_var("REDBEAR_DRIVER_BACKOFF_CAP_MS", "-5") };
tracker.apply_env();
// SAFETY: caller must verify the safety contract for this operation
tracker.a// SAFETY: caller must verify the safety contract for this operation
pply_env()// SAFETY: caller must verify the safety contract for this operation
;
assert_eq!(
tracker.threshold(),
orig_threshold,
@@ -535,7 +547,8 @@ initial_power_state = "D2"
assert_eq!(
tracker.backoff_cap_ms(),
orig_cap,
"negative cap_ms must be ignored (parse fails, default kept)"
// SAFETY: caller must verify the safety contract for this operation
"negative cap_ms must be ignored (parse fails, default kept)"
);
unsafe { std::env::remove_var("REDBEAR_DRIVER_CRASH_THRESHOLD") };
unsafe { std::env::remove_var("REDBEAR_DRIVER_BACKOFF_BASE_MS") };
@@ -544,8 +557,10 @@ initial_power_state = "D2"
}
#[test]
fn crash_tracker_global_stub_returns_when_unset() {
// CrashTracker global pointer must not be set by other tests.
fn c// SAFETY: caller must verify the safety contract for this operation
rash_tracker_global_stub_returns_when_unset() {
// CrashTracker global pointer must not // SAFETY: caller must verify the safety contract for this operation
be set by other tests.
let snap = super::crash_tracker().snapshot();
assert!(
snap.is_empty(),
@@ -560,8 +575,10 @@ initial_power_state = "D2"
std::env::remove_var("REDBEAR_DRIVER_MANAGER_ACTIVE");
}
let prev: Vec<String> = std::env::args().collect();
if !prev.iter().any(|a| a == "--no-spawn") {
assert_eq!(super::spawn_decision_gate(), super::SpawnDecision::Spawn);
if !prev.ite// SAFETY: caller must verify the safety contract for this operation
r().any(|a| a == "--no-spawn") {
assert_eq!(super::spawn_decision_gate(), super:// SAFETY: caller must verify the safety contract for this operation
:SpawnDecision::Spawn);
}
});
}
@@ -843,7 +860,8 @@ impl CrashTracker {
}
}
/// Clear any failure state for `bdf`. Called from a successful
/// Clear any failure state// SAFETY: caller must verify the safety contract for this operation
for `bdf`. Called from a successful
/// probe (Bind result).
pub fn record_success(&self, bdf: &str) {
if let Ok(mut map) = self.failures_map().lock() {
@@ -854,7 +872,8 @@ impl CrashTracker {
/// Global crash tracker. The pointer is set once at startup
/// (`set_crash_tracker`); reads in the probe hot path are non-blocking
/// only because the pointer is `static`, not because of any
/// only because the p// SAFETY: caller must verify the safety contract for this operation
ointer is `static`, not because of any
/// `RwLock`. If unset, `crash_tracker()` returns a static stub with
/// the default threshold and no recorded failures — i.e. behavior
/// identical to pre-F1 (every probe runs, no backoff, no blacklist).
@@ -175,6 +175,7 @@ impl SharedBlacklist {
/// Snapshot the in-memory blacklist for read-only iteration.
#[cfg(test)]
#[allow(dead_code)] // snapshot helper for tests; not used in production paths
pub fn snapshot(&self) -> Blacklist {
self.inner
.read()
@@ -40,6 +40,7 @@ pub fn spawn_reaper_thread<F>(on_reap: F) -> thread::JoinHandle<()>
where
F: Fn(u32) + Send + 'static,
{
// SAFETY: caller must verify the safety contract for this operation
unsafe {
libc::signal(libc::SIGCHLD, sigchld_handler as *const () as libc::sighandler_t);
}
@@ -205,6 +206,7 @@ mod tests {
// already finished. Lower the poll interval via env var so
// the test does not have to wait 60s. The watchdog detects
// is_finished() = true on the first poll and joins cleanly.
// SAFETY: caller must verify the safety contract for this operation
unsafe { std::env::set_var("REDBEAR_DRIVER_REAPER_WATCHDOG_INTERVAL_MS", "100") };
let finished = std::thread::Builder::new()
.name("test-already-finished".to_string())
@@ -220,14 +222,16 @@ mod tests {
assert!(watchdog.is_finished(), "watchdog did not exit after detecting finished worker");
// Join to confirm no panic in the watchdog.
let result = watchdog.join();
assert!(result.is_ok(), "watchdog panicked: {:?}", result.err());
// SAFETY: caller must verify the safety contract for this operation
assert!(result.is_ok(), "watchdog panicked: {:?}", result.err());
unsafe { std::env::remove_var("REDBEAR_DRIVER_REAPER_WATCHDOG_INTERVAL_MS") };
}
#[test]
fn reaper_watchdog_interval_clamps_low_values() {
// Set a sub-100ms value; the helper clamps to 100ms so the
// watchdog cannot burn CPU. Verify via behaviour: spawn a
// watchdog cannot burn CPU. Verify via behaviour: s// SAFETY: caller must verify the safety contract for this operation
pawn a
// quick-finishing worker and verify the watchdog completes
// within ~250ms (i.e. ~2 clamped-100ms polls + join).
unsafe { std::env::set_var("REDBEAR_DRIVER_REAPER_WATCHDOG_INTERVAL_MS", "1") };
@@ -236,11 +240,13 @@ mod tests {
.spawn(|| {})
.expect("spawn finished thread");
std::thread::sleep(Duration::from_millis(20));
let watchdog = spawn_reaper_watchdog(finished);
let watchdog = spawn_re// SAFETY: caller must verify the safety contract for this operation
aper_watchdog(finished);
std::thread::sleep(Duration::from_millis(250));
assert!(watchdog.is_finished(), "watchdog should have exited despite tiny env var");
let _ = watchdog.join();
unsafe { std::env::remove_var("REDBEAR_DRIVER_REAPER_WATCHDOG_INTERVAL_MS") };
unsafe { std::env::remove_var("REDBEAR_DRIVER// SAFETY: caller must verify the safety contract for this operation
_REAPER_WATCHDOG_INTERVAL_MS") };
}
#[test]
@@ -16,6 +16,7 @@ extern "C" fn signal_handler(_sig: i32) {
}
pub fn spawn_reload_worker(blacklist: Arc<SharedBlacklist>) -> thread::JoinHandle<()> {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
libc::signal(libc::SIGHUP, signal_handler as *const () as libc::sighandler_t);
}
@@ -256,7 +256,7 @@ pub fn format_json() -> String {
/// state reads. Used by [`format_json`] and by tests for golden snapshots.
#[allow(dead_code)] // tests call directly; production path goes via format_json
pub fn format_metrics_json(metrics: &[LatencyMetric]) -> String {
let mut out = String::from(r#"{"version":1,"buckets":{"#);
let mut out = String::from(r#"{"version":2,"buckets":{"#);
let mut first = true;
for m in metrics {
if !first {
@@ -276,6 +276,14 @@ pub fn format_metrics_json(metrics: &[LatencyMetric]) -> String {
));
}
out.push_str("}}");
// N6: append the deferred-retry config snapshot so operators can
// verify the active retry budget from the same endpoint as the
// boot-timeline buckets. Bumped output version to 2 (was 1).
let (count, interval_ms) = deferred_retry_config();
out.push_str(&format!(
r#","deferred_retry_config":{{"count":{count},"interval_ms":{interval_ms}}}"#
));
out.push('}');
out
}
@@ -699,10 +707,19 @@ mod tests {
},
];
let json = format_metrics_json(&metrics);
assert!(json.starts_with(r#"{"version":1,"buckets":{"#));
assert!(json.ends_with("}}"));
assert!(json.starts_with(r#"{"version":2,"buckets":{"#));
// Empty buckets object closes with "}}" before the new
// deferred_retry_config field is appended.
assert!(json.contains(r#""claim-spawn":{"count":0"#));
assert!(json.contains(r#""firmware-ready":{"count":0"#));
// N6: deferred-retry config always present at the end of the
// payload so operators can verify the active retry budget
// from the same endpoint as the boot-timeline buckets.
assert!(
json.contains(r#""deferred_retry_config":{"count":30,"interval_ms":500}"#),
"default deferred-retry config missing: {}",
json
);
}
#[test]
@@ -718,10 +735,41 @@ mod tests {
p99_us: 4_523,
}];
let json = format_metrics_json(&metrics);
let expected = r#"{"version":1,"buckets":{"aer-event":{"count":5,"min_us":612,"max_us":4523,"p50_us":2100,"p95_us":4523,"p99_us":4523,"sum_us":12000}}}"#;
// The exact JSON includes the new deferred_retry_config suffix
// (default 30 retries at 500 ms) since the test does not
// mutate the statics.
let expected = r#"{"version":2,"buckets":{"aer-event":{"count":5,"min_us":612,"max_us":4523,"p50_us":2100,"p95_us":4523,"p99_us":4523,"sum_us":12000}},"deferred_retry_config":{"count":30,"interval_ms":500}}"#;
assert_eq!(json, expected);
}
#[test]
fn json_format_includes_deferred_retry_config_override() {
// N6: the /timing endpoint must reflect the env-var overrides
// so operators can verify the active retry budget at runtime.
let metrics = vec![LatencyMetric {
bucket: "claim-spawn",
count: 1,
sum_us: 100,
min_us: 100,
max_us: 100,
p50_us: 100,
p95_us: 100,
p99_us: 100,
}];
serialized(|| {
unsafe { std::env::set_var("REDBEAR_DRIVER_DEFERRED_RETRY_COUNT", "7") };
unsafe { std::env::set_var("REDBEAR_DRIVER_DEFERRED_RETRY_INTERVAL_MS", "250") };
let json = format_metrics_json(&metrics);
assert!(
json.contains(r#""deferred_retry_config":{"count":7,"interval_ms":250}"#),
"expected overridden deferred_retry_config in {}",
json
);
unsafe { std::env::remove_var("REDBEAR_DRIVER_DEFERRED_RETRY_COUNT") };
unsafe { std::env::remove_var("REDBEAR_DRIVER_DEFERRED_RETRY_INTERVAL_MS") };
});
}
#[test]
fn json_format_all_four_buckets() {
// Build a snapshot of all four canonical buckets with realistic data.
@@ -121,6 +121,7 @@ struct SchemePoll {
fn read_event_from_bytes(bytes: &[u8]) -> Event {
let mut event = MaybeUninit::<Event>::uninit();
// SAFETY: caller must verify the safety contract for this operation
unsafe {
std::ptr::copy_nonoverlapping(bytes.as_ptr(), event.as_mut_ptr() as *mut u8, bytes.len());
event.assume_init()
@@ -720,6 +720,7 @@ mod tests {
};
fn test_ctx() -> CallerCtx {
// SAFETY: caller must verify the safety contract for this operation
unsafe { std::mem::zeroed() }
}
@@ -219,6 +219,7 @@ mod tests {
if let Err(err) = fs::write(root.join("iwlwifi-test.ucode"), [9u8, 8, 7]) {
panic!("failed to write async firmware blob: {err}");
}
// SAFETY: caller must verify the safety contract for this operation
unsafe {
std::env::set_var("FIRMWARE_DIR", &root);
@@ -238,6 +239,7 @@ mod tests {
Ok(bytes) => assert_eq!(bytes, vec![9u8, 8, 7]),
Err(err) => panic!("unexpected async firmware error: {err}"),
}
// SAFETY: caller must verify the safety contract for this operation
unsafe {
std::env::remove_var("FIRMWARE_DIR");
@@ -263,7 +265,8 @@ mod tests {
let firmware_path = root.join(firmware_name);
let parent = match firmware_path.parent() {
Some(parent) => parent.to_path_buf(),
None => panic!("firmware test path unexpectedly had no parent"),
None =>// SAFETY: caller must verify the safety contract for this operation
panic!("firmware test path unexpectedly had no parent"),
};
unsafe {
@@ -307,7 +310,8 @@ mod tests {
match result {
Ok(bytes) => assert_eq!(bytes, vec![1u8, 2, 3, 4]),
Err(err) => panic!("unexpected async retry error: {err}"),
}
// SAFETY: caller must verify the safety contract for this operation
}
match writer.join() {
Ok(()) => {}
@@ -115,6 +115,7 @@ pub fn rdrand() -> Option<u64> {
{
let value: u64;
let carry: u8;
// SAFETY: caller must verify the safety contract for this operation
unsafe {
std::arch::asm!(
"rdrand {value}",
@@ -142,6 +143,7 @@ fn rdseed() -> Option<u64> {
{
let value: u64;
let carry: u8;
// SAFETY: caller must verify the safety contract for this operation
unsafe {
std::arch::asm!(
"rdseed {value}",
@@ -199,6 +199,7 @@ impl CommandBuffer {
}
pub fn read_completion_store(&self) -> u32 {
// SAFETY: caller guarantees pointer is valid, aligned, and live
unsafe { core::ptr::read_volatile(self.buffer.as_ptr() as *const u32) }
}
@@ -207,6 +208,7 @@ impl CommandBuffer {
}
fn commands_mut(&mut self) -> &mut [CommandEntry] {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
slice::from_raw_parts_mut(self.buffer.as_mut_ptr() as *mut CommandEntry, self.capacity)
}
@@ -306,17 +308,21 @@ impl EventLog {
(self.buffer.physical_address() + offset) as u64
}
pub fn completion_store_cpu_ptr(&self) -> *mut u32 {
pub fn completion_store_cpu_ptr(&self) -> *mut u3// SAFETY: caller must verify the safety contract for this operation
2 {
let offset = (self.capacity - 1) * EVENT_LOG_ENTRY_SIZE;
unsafe { self.buffer.as_ptr().add(offset) as *mut u32 }
unsafe { self.buffer.as_ptr().add(off// SAFETY: caller must verify the safety contract for this operation
set) as *mut u32 }
}
pub fn clear_completion_store(&mut self) {
let offset = (self.capacity - 1) * EVENT_LOG_ENTRY_SIZE;
unsafe {
core::ptr::write_bytes(
core::ptr// SAFETY: caller must verify the safety contract for this operation
::write_bytes(
self.buffer.as_mut_ptr().add(offset),
0,
// SAFETY: caller must verify the safety contract for this operation
0,
EVENT_LOG_ENTRY_SIZE,
)
};
@@ -220,6 +220,7 @@ impl DeviceTable {
}
fn entries(&self) -> &[DeviceTableEntry] {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
slice::from_raw_parts(
self.buffer.as_ptr() as *const DeviceTableEntry,
@@ -229,6 +230,7 @@ impl DeviceTable {
}
fn entries_mut(&mut self) -> &mut [DeviceTableEntry] {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
slice::from_raw_parts_mut(
self.buffer.as_mut_ptr() as *mut DeviceTableEntry,
@@ -76,6 +76,7 @@ impl InterruptRemapTable {
if index >= self.entries { return false; }
let e = irte.encode();
let off = index * IRTE_SIZE;
// SAFETY: caller must verify the safety contract for this operation
unsafe {
core::ptr::write_volatile((self.addr() + off) as *mut u64, e[0]);
core::ptr::write_volatile((self.addr() + off + 8) as *mut u64, e[1]);
@@ -86,6 +87,7 @@ impl InterruptRemapTable {
pub fn invalidate_entry(&self, index: usize) {
if index >= self.entries { return; }
// SAFETY: caller guarantees pointer is valid, aligned, and live
unsafe { core::ptr::write_volatile((self.addr() + index * IRTE_SIZE) as *mut u64, 0u64); }
}
+5 -1
View File
@@ -896,6 +896,7 @@ impl SchemeSync for IommuScheme {
if unsafe { libc::fstat(fd as c_int, &mut st) } < 0 {
return error_result(EINVAL);
}
// SAFETY: caller must verify the safety contract for this operation
unsafe { ptr::write_bytes(dst, 0, 144); }
0
}
@@ -967,6 +968,7 @@ impl SchemeSync for IommuScheme {
if unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, &mut t) } < 0 {
return error_result(EINVAL);
}
// SAFETY: caller guarantees non-overlapping regions
unsafe { ptr::copy_nonoverlapping(&t as *const _ as *const u8, ts, core::mem::size_of::<libc::timespec>()); }
0
}
@@ -997,7 +999,9 @@ impl SchemeSync for IommuScheme {
pub extern "C" fn redox_strerror_v1(dst: *mut u8, dst_len: *mut usize, error: u32) -> usize {
if dst.is_null() || dst_len.is_null() { return error_result(EINVAL); }
let msg = unsafe { libc::strerror(error as c_int) };
let msg_str = if msg.is_null() { b"host test stub" } else {
let msg// SAFETY: caller must verify the safety contract for this operation
_str = if msg.is_null() { // SAFETY: caller must verify the safety contract for this operation
b"host test stub" } else {
unsafe { slice::from_raw_parts(msg as *const u8, libc::strlen(msg)) }
};
unsafe {
@@ -222,6 +222,7 @@ mod tests {
fn register_accessors_use_expected_offsets() {
let mut mmio = MaybeUninit::<AmdViMmio>::zeroed();
let base = mmio.as_mut_ptr();
// SAFETY: caller must verify the safety contract for this operation
unsafe {
AmdViMmio::write_control(base, 0xdead_beef);
@@ -259,6 +259,7 @@ impl PageBuffer {
impl Drop for PageBuffer {
fn drop(&mut self) {
if let PageStorage::Host { ptr, layout, .. } = &self.storage {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
std::alloc::dealloc(ptr.as_ptr(), *layout);
}
@@ -295,7 +296,9 @@ impl PageTablePage {
}
fn entries(&self) -> &[AmdPte] {
unsafe { slice::from_raw_parts(self.buffer.as_ptr().cast::<AmdPte>(), PTES_PER_PAGE) }
// SAFETY: caller guarantees ptr is aligned for T and len is exact
unsafe { slice::from_raw_parts(self.buffer.as_ptr().cast::<AmdPte>(), PTES_P// SAFETY: caller must verify the safety contract for this operation
ER_PAGE) }
}
fn entries_mut(&mut self) -> &mut [AmdPte] {
@@ -199,6 +199,7 @@ fn read_phys<T: Copy>(addr: usize) -> T {
return unsafe { std::ptr::read(buf.as_ptr() as *const T) };
}
}
// SAFETY: caller must verify the safety contract for this operation
unsafe { std::mem::zeroed() }
}
@@ -38,6 +38,7 @@ unsafe fn get_init_notify_fd() -> Option<RawFd> {
let Ok(fd) = value.parse::<RawFd>() else {
return None;
};
// SAFETY: caller must verify the safety contract for this operation
unsafe {
libc::fcntl(fd, libc::F_SETFD, libc::FD_CLOEXEC);
}
@@ -131,6 +131,7 @@ unsafe fn get_init_notify_fd() -> Option<RawFd> {
let Ok(fd) = value.parse::<RawFd>() else {
return None;
};
// SAFETY: caller must verify the safety contract for this operation
unsafe {
libc::fcntl(fd, libc::F_SETFD, libc::FD_CLOEXEC);
}
@@ -198,6 +198,7 @@ fn decode_wire<T: Copy>(bytes: &[u8]) -> Result<T, String> {
));
}
let mut out = MaybeUninit::<T>::uninit();
// SAFETY: caller must verify the safety contract for this operation
unsafe {
std::ptr::copy_nonoverlapping(
bytes.as_ptr(),
@@ -209,6 +210,7 @@ fn decode_wire<T: Copy>(bytes: &[u8]) -> Result<T, String> {
}
fn bytes_of<T>(value: &T) -> &[u8] {
// SAFETY: caller guarantees ptr is aligned for T and len is exact
unsafe { std::slice::from_raw_parts((value as *const T).cast::<u8>(), size_of::<T>()) }
}
@@ -548,7 +550,8 @@ mod tests {
use super::{
DrmModeWire, DrmResourcesWire, ModeSummary, bytes_of, decode_wire, disable_crtc_request,
find_mode, has_connector_section, has_mode_lines, parse_modeset_spec,
proof_teardown_requests, setcrtc_request,
proof_teardown_requests, setcrtc// SAFETY: caller must verify the safety contract for this operation
_request,
};
fn owned_bytes_of<T>(value: &T) -> Vec<u8> {
@@ -13,6 +13,7 @@ fn run() -> Result<(), String> {
one_page.physical_address(),
one_page.len()
);
// SAFETY: caller must verify the safety contract for this operation
unsafe {
(one_page.as_mut_ptr() as *mut u32).write_volatile(0x1122_3344);
let value = (one_page.as_ptr() as *const u32).read_volatile();
@@ -27,6 +28,7 @@ fn run() -> Result<(), String> {
two_page.physical_address(),
two_page.len()
);
// SAFETY: caller must verify the safety contract for this operation
unsafe {
let second_page = two_page.as_mut_ptr().add(4096) as *mut u32;
second_page.write_volatile(0x5566_7788);
@@ -285,6 +285,7 @@ fn decode_wire_exact<T: Copy>(bytes: &[u8]) -> Result<T, String> {
}
let mut out = MaybeUninit::<T>::uninit();
// SAFETY: caller must verify the safety contract for this operation
unsafe {
std::ptr::copy_nonoverlapping(
bytes.as_ptr(),
@@ -297,6 +298,7 @@ fn decode_wire_exact<T: Copy>(bytes: &[u8]) -> Result<T, String> {
#[cfg(target_os = "redox")]
fn bytes_of<T>(value: &T) -> &[u8] {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
std::slice::from_raw_parts((value as *const T).cast::<u8>(), std::mem::size_of::<T>())
}
@@ -447,6 +447,7 @@ fn decode_wire_exact<T: Copy>(bytes: &[u8]) -> Result<T, String> {
}
let mut out = MaybeUninit::<T>::uninit();
// SAFETY: caller must verify the safety contract for this operation
unsafe {
std::ptr::copy_nonoverlapping(
bytes.as_ptr(),
@@ -459,6 +460,7 @@ fn decode_wire_exact<T: Copy>(bytes: &[u8]) -> Result<T, String> {
#[cfg(target_os = "redox")]
fn bytes_of<T>(value: &T) -> &[u8] {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
std::slice::from_raw_parts((value as *const T).cast::<u8>(), std::mem::size_of::<T>())
}
@@ -260,7 +260,9 @@ unsafe fn move_add_line(row: i32, text: &str) {
unsafe fn draw_raw_line(row: i32, text: &str) {
let blank = " ".repeat(140);
// SAFETY: caller must verify the safety contract for this operation
unsafe { move_add_line(row, &blank) };
// SAFETY: caller must verify the safety contract for this operation
unsafe { move_add_line(row, text) };
let _ = unsafe { clrtoeol() };
}
@@ -778,6 +778,7 @@ mod tests {
perms.set_mode(0o755);
fs::set_permissions(&dhcp_script, perms).unwrap();
}
// SAFETY: caller must verify the safety contract for this operation
unsafe {
env::set_var("REDBEAR_NETCFG_ROOT", &netcfg);
@@ -853,6 +854,7 @@ mod tests {
perms.set_mode(0o755);
fs::set_permissions(&dhcp_script, perms).unwrap();
}
// SAFETY: caller must verify the safety contract for this operation
unsafe {
env::set_var("REDBEAR_NETCFG_ROOT", &netcfg);
@@ -909,7 +911,8 @@ mod tests {
.unwrap();
fs::write(
wifictl.join("ifaces/wlan0/connect-result"),
"connect_result=bounded-associated ssid=demo security=wpa2-psk\n",
"connect_result=bounded-ass// SAFETY: caller must verify the safety contract for this operation
ociated ssid=demo security=wpa2-psk\n",
)
.unwrap();
@@ -976,7 +979,8 @@ mod tests {
"activation=stub\n",
)
.unwrap();
fs::write(
// SAFETY: caller must verify the safety contract for this operation
fs::write(
wifictl.join("ifaces/wlan0/scan-results"),
"demo-ssid\ndemo-open\n",
)
@@ -1017,7 +1021,8 @@ mod tests {
fs::create_dir_all(wifictl.join("ifaces/wlan0")).unwrap();
fs::write(
profile_dir.join("wifi-dhcp"),
"Description='Wi-Fi'\nInterface=wlan0\nConnection=wifi\nSSID='test-ssid'\nSecurity=open\nIP=dhcp\n",
"Description='Wi-Fi'\nInterface=wlan0\nConnection=wifi\nSSID='test-ssid'\nSecurity=open\nIP=dhcp\// SAFETY: caller must verify the safety contract for this operation
n",
)
.unwrap();
fs::write(wifictl.join("ifaces/wlan0/status"), "device-detected\n").unwrap();
@@ -1039,7 +1044,8 @@ mod tests {
fn reports_wifi_last_error() {
let _guard = env_lock()
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner());
.unwrap_or_else(|poisoned| poiso// SAFETY: caller must verify the safety contract for this operation
ned.into_inner());
let wifictl = temp_root("rbos-wifictl-error");
fs::create_dir_all(wifictl.join("ifaces/wlan0")).unwrap();
fs::write(
@@ -393,6 +393,7 @@ mod tests {
std::fs::write(passwd_path, passwd).unwrap();
std::fs::write(group_path, group).unwrap();
std::fs::write(policy_path, policy).unwrap();
// SAFETY: caller must verify the safety contract for this operation
unsafe {
std::env::set_var("REDBEAR_POLKIT_PASSWD", passwd_path);
std::env::set_var("REDBEAR_POLKIT_GROUP", group_path);
@@ -401,6 +402,7 @@ mod tests {
}
fn teardown_env() {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
std::env::remove_var("REDBEAR_POLKIT_PASSWD");
std::env::remove_var("REDBEAR_POLKIT_GROUP");
@@ -42,6 +42,7 @@ fn try_pin_cpu(cpu_id: u32) -> bool {
return true;
}
#[cfg(target_os = "linux")]
// SAFETY: caller must verify the safety contract for this operation
unsafe {
sched_setaffinity(0, std::mem::size_of::<u64>(), &mask as *const u64) == 0
}
@@ -87,6 +87,7 @@ impl KillDialog {
fn do_kill(pid: u32, sig: i32) -> Result<(), String> {
#[cfg(target_os = "linux")]
// SAFETY: caller must verify the safety contract for this operation
unsafe {
let ret = libc::kill(pid as libc::pid_t, sig);
if ret == 0 {
@@ -130,6 +130,7 @@ fn read_ipv6_addrs(iface_name: &str) -> Vec<String> {
/// Read IPv4 addresses for a specific interface using libc getifaddrs.
fn read_ipv4_addrs(iface_name: &str) -> Vec<String> {
let mut addrs = Vec::new();
// SAFETY: caller must verify the safety contract for this operation
unsafe {
let mut ifap: *mut libc::ifaddrs = std::ptr::null_mut();
if libc::getifaddrs(&mut ifap) != 0 {
@@ -30,6 +30,7 @@ const MAX_PROCESSES: usize = 50;
fn clock_ticks_per_second() -> u64 {
#[cfg(target_os = "linux")]
{
// SAFETY: caller must verify the safety contract for this operation
unsafe { libc::sysconf(libc::_SC_CLK_TCK) as u64 }
}
#[cfg(not(target_os = "linux"))]
@@ -2106,6 +2107,7 @@ mod io_sort_unit_tests {
pub fn set_nice(pid: u32, nice: i32) -> Result<(), String> {
let n = nice.clamp(-20, 19);
#[cfg(target_os = "linux")]
// SAFETY: caller must verify the safety contract for this operation
unsafe {
// PRIO_PROCESS = 0, who = pid
if libc::setpriority(0, pid, n) == 0 {
@@ -2139,7 +2141,8 @@ pub fn set_affinity(pid: u32, cpus: &[u32]) -> Result<(), String> {
#[cfg(target_os = "linux")]
{
let mut set: libc::cpu_set_t = unsafe { std::mem::zeroed() };
for &cpu in cpus {
for &cpu in// SAFETY: caller must verify the safety contract for this operation
cpus {
if (cpu as usize) < libc::CPU_SETSIZE as usize {
unsafe {
libc::CPU_SET(cpu as usize, &mut set);
@@ -389,6 +389,7 @@ fn run() -> Result<(), String> {
command.envs(&envs);
command.uid(account.uid);
command.gid(account.gid);
// SAFETY: caller must verify the safety contract for this operation
unsafe {
command.pre_exec(move || apply_groups(&group_clone));
}
@@ -581,6 +582,7 @@ mod tests {
#[test]
fn build_environment_propagates_kwin_drm_devices_when_set() {
// SAFETY: caller must verify the safety contract for this operation
unsafe { std::env::set_var("KWIN_DRM_DEVICES", "/scheme/drm/card0"); }
let account = Account {
username: String::from("greeter"),
@@ -600,7 +602,8 @@ mod tests {
args: Vec::new(),
},
};
let envs = build_environment(&account, &args, Path::new("/tmp/run/greeter"));
let envs = build_environment(&account, &args, Path::new("/tmp/run/greeter"))// SAFETY: caller must verify the safety contract for this operation
;
assert_eq!(envs["KWIN_DRM_DEVICES"], "/scheme/drm/card0");
unsafe { std::env::remove_var("KWIN_DRM_DEVICES"); }
}
@@ -104,6 +104,7 @@ pub fn unmount(state: &MountState) -> io::Result<()> {
// SIGTERM via their IS_UMT flag and exit cleanly. We do not
// block on waitpid — the daemon will exit on its own and
// the init system will reap the process.
// SAFETY: caller must verify the safety contract for this operation
unsafe {
libc::kill(pid as libc::pid_t, libc::SIGTERM);
}
@@ -1219,6 +1219,7 @@ mod tests {
cfg[0x3D] = 0x01;
fs::write(slot.join("config"), cfg).unwrap();
fs::write(firmware.join("iwlwifi-bz-b0-gf-a0-92.ucode"), []).unwrap();
// SAFETY: caller must verify the safety contract for this operation
unsafe {
env::set_var("REDBEAR_WIFICTL_PCI_ROOT", &pci);
@@ -1326,6 +1327,7 @@ esac
}
let old_cmd = env::var_os("REDBEAR_IWLWIFI_CMD");
// SAFETY: caller must verify the safety contract for this operation
unsafe {
env::set_var("REDBEAR_WIFICTL_PCI_ROOT", &pci);
env::set_var("REDBEAR_WIFICTL_FIRMWARE_ROOT", &firmware);
@@ -1333,7 +1335,8 @@ esac
}
let mut backend = IntelBackend::from_env();
let transport_status = backend.transport_probe("wlan0").unwrap();
let transport_status = backend.transport_probe("wlan0").unwrap()// SAFETY: caller must verify the safety contract for this operation
;
assert_eq!(transport_status, "transport=mock-probe-only");
unsafe {
@@ -1399,7 +1402,8 @@ esac
{
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata(&driver).unwrap().permissions();
perms.set_mode(0o755);
perms.set_mo// SAFETY: caller must verify the safety contract for this operation
de(0o755);
fs::set_permissions(&driver, perms).unwrap();
}
@@ -1420,7 +1424,8 @@ esac
let state = InterfaceState {
ssid: "demo".to_string(),
security: "wpa2-psk".to_string(),
security: "wpa2-psk".to_string// SAFETY: caller must verify the safety contract for this operation
(),
key: "secret".to_string(),
..Default::default()
};
@@ -32,6 +32,7 @@ unsafe fn get_init_notify_fd() -> Option<RawFd> {
let Ok(fd) = value.parse::<RawFd>() else {
return None;
};
// SAFETY: caller must verify the safety contract for this operation
unsafe {
libc::fcntl(fd, libc::F_SETFD, libc::FD_CLOEXEC);
}
@@ -750,6 +750,7 @@ mod tests {
cfg[0x2F] = 0x40;
cfg[0x3D] = 0x01;
fs::write(slot.join("config"), cfg).unwrap();
// SAFETY: caller must verify the safety contract for this operation
unsafe {
env::set_var("REDBEAR_WIFICTL_PCI_ROOT", &pci);