Search Linux Wireless

divide by zero in ath9k_htc_choose_bslot()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The attached demo uses usbip to pretend to be a USB device for 

  drivers/net/wireless/ath/ath9k/

It sets up the wifi interface, and then maliciously generates a frame
that claims to be on the USB endpoint that ath9k_htc_rx_msg() passes to
ath9k_wmi_ctrl_rx(). The cmd_id in the frame is 0x1002, or
WMI_SWBA_EVENTID, which causes ath9k_wmi_ctrl_rx() to wake up the
ath9k_wmi_event_tasklet. Which calls ath9k_htc_swba(), which calls
ath9k_htc_choose_bslot(), which says

        intval = priv->cur_beacon_conf.beacon_interval;
        tsf = be64_to_cpu(swba->tsf);
        tsftu = TSF_TO_TU(tsf >> 32, tsf);
        slot = ((tsftu % intval) * ATH9K_HTC_MAX_BCN_VIF) / intval;
        slot = ATH9K_HTC_MAX_BCN_VIF - slot - 1;

At this point beacon_interval is zero, so this divides by zero. On an
amd64, a fault. On a RISC-V, which produces -1 for divide by zero,
slot ends up as 2, which is too large; later on, slot=2 causes
ath9k_htc_send_buffered() to index off the end of the bslot array;
ieee80211_get_buffered_bc() then dereferences the resulting bad vif
pointer.

        vif = priv->beacon.bslot[slot];
        skb = ieee80211_get_buffered_bc(priv->hw, vif);

Changing ath9k_htc_choose_bslot() to return zero if intval is zero makes
the crash go away. I don't know if that would be correct with a real
Atheros device, but it probably doesn't matter since I imagine this
would only ever arise with a broken or malicious USB device.

# uname -a
Linux xxx 6.14.0-rc7 #18 SMP PREEMPT_DYNAMIC Thu Mar 27 11:26:30 EDT 2025 x86_64 x86_64 x86_64 GNU/Linux
# cc usbath1c.c
# ./a.out
...
  Oops: divide error: 0000 [#1] PREEMPT SMP PTI
  CPU: 2 UID: 0 PID: 29 Comm: ksoftirqd/2 Not tainted 6.14.0-rc7 #18
  Hardware name: FreeBSD BHYVE/BHYVE, BIOS 14.0 10/17/2021
  RIP: 0010:ath9k_htc_swba+0x5f/0x3a0
  Code: 0f 85 93 02 00 00 48 8b 06 0f b7 8d c0 03 00 00 4c 8d ad b0 03 00 00 4c 89 ef 48 0f c8 48 89 c2 48 c1 ea 20 0f ac d0 0a 31 d2 <f7> f1 8d 04 12 31 d2 f7 f1 89 c3 e8 31 23 56 00 b8 01 00 00 00 29
  RSP: 0018:ffffbc49c014fd88 EFLAGS: 00010246
  RAX: 0000000000000000 RBX: ffff9ef116c1ef40 RCX: 0000000000000000
  RDX: 0000000000000000 RSI: ffff9ef102fc006c RDI: ffff9ef116f56390
  RBP: ffff9ef116f55fe0 R08: 0000000000000800 R09: 0000000000000000
  R10: ffffffff862070c0 R11: 0000000000000210 R12: ffff9ef104b0c0cc
  R13: ffff9ef116f56390 R14: ffff9ef104b0c060 R15: 0000000000000210
  FS:  0000000000000000(0000) GS:ffff9ef42fa80000(0000) knlGS:0000000000000000
  CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
  CR2: 00007ffd54f0c1dc CR3: 00000001024f4001 CR4: 00000000003706f0
  DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
  DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
  Call Trace:
   <TASK>
   ? die+0x31/0x80
   ? do_trap+0xd8/0x100
   ? ath9k_htc_swba+0x5f/0x3a0
   ? do_error_trap+0x60/0x80
   ? ath9k_htc_swba+0x5f/0x3a0
   ? exc_divide_error+0x39/0x50
   ? ath9k_htc_swba+0x5f/0x3a0
   ? asm_exc_divide_error+0x1a/0x20
   ? ath9k_htc_swba+0x5f/0x3a0
   ? sched_balance_newidle.isra.0+0x29f/0x3a0
   ath9k_wmi_event_tasklet+0x33/0x150
   tasklet_action_common+0xb3/0x220
   handle_softirqs+0xc5/0x2b0
   ? __pfx_smpboot_thread_fn+0x10/0x10
   run_ksoftirqd+0x20/0x30
   smpboot_thread_fn+0xd8/0x1d0
   kthread+0xe9/0x1f0
   ? __pfx_kthread+0x10/0x10
   ret_from_fork+0x2f/0x50
   ? __pfx_kthread+0x10/0x10
   ret_from_fork_asm+0x1a/0x30
   </TASK>
  Modules linked in:
  ---[ end trace 0000000000000000 ]---
  RIP: 0010:ath9k_htc_swba+0x5f/0x3a0

Robert Morris
rtm@xxxxxxx

Attachment: usbath1c.c
Description: Binary data


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Wireless Regulations]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux