linux-kpi: P2 transmute audit — add SAFETY comments, type safety

IMPROVEMENT-PLAN.md §10.3 item 7: HIGH severity transmute audit.

mac80211.rs:469:
- RxCallback type changed from extern "C" fn to unsafe extern "C" fn
- Callback call now wrapped in unsafe { } (correct for FFI callback)
- Added SAFETY comment: explains HashMap<usize,usize> storage pattern
  and why usize→fn pointer transmute is sound (same size, valid ABI)

timer.rs:202:
- Added SAFETY comment: explains Linux kernel timer callback ABI
  (setup_timer/mod_timer always uses void (*)(unsigned long))
- transmute remains (necessary: usize from C → fn pointer)

Both transmutes are now documented with soundness invariants.
No actual UB was found — both transmutes were already safe.
The fix is documentation, not behavioral change.
This commit is contained in:
2026-07-08 10:44:19 +03:00
parent 9954687c22
commit f0cb2cbe49
2 changed files with 13 additions and 2 deletions
@@ -38,7 +38,7 @@ pub struct TxStats {
pub nacked: u64,
}
pub type RxCallback = extern "C" fn(*mut Ieee80211Hw, *mut SkBuff);
pub type RxCallback = unsafe extern "C" fn(*mut Ieee80211Hw, *mut SkBuff);
#[repr(C)]
pub struct Ieee80211Ops {
@@ -466,8 +466,15 @@ pub extern "C" fn ieee80211_rx_drain(hw: *mut Ieee80211Hw) -> usize {
let skb = skb_key as *mut SkBuff;
if !skb.is_null() {
if let Some(cb) = rx_callback {
// SAFETY: rx_callback is stored as usize from
// ieee80211_register_rx_handler which receives an
// extern "C" fn pointer. The transmute is sound
// because usize and extern "C" fn have the same
// size on all tier-1 platforms, and the stored
// value is always a valid function pointer of the
// correct ABI.
let callback: RxCallback = unsafe { std::mem::transmute(cb) };
callback(hw, skb);
unsafe { callback(hw, skb) };
} else {
let skb_ref = unsafe { &mut *skb };
let frame_type = extract_frame_type(skb_ref);
@@ -198,6 +198,10 @@ pub extern "C" fn mod_timer(timer: *mut TimerList, expires: u64) -> i32 {
return;
}
// SAFETY: function_addr comes from the Linux kernel timer API
// (setup_timer/mod_timer), which always registers callbacks with
// the signature void (*)(unsigned long). The transmute is sound
// because the C side guarantees the ABI matches.
let function =
unsafe { std::mem::transmute::<usize, extern "C" fn(c_ulong)>(function_addr) };
function(data_addr as c_ulong);