Commit Graph

5 Commits

Author SHA1 Message Date
test0r 9e38ac5523 bes2600: fix concurrency UAF in bes2600_hw_scan and sched_scan
bes2600_bss_info_changed() and bes2600_hw_scan() can run concurrently.
The probe-request SKB allocated by ieee80211_probereq_get() before
scan.lock + conf_lock are taken can be touched by a concurrent
bss_info_changed (via wsm_set_template_frame's path) while we hold no
lock.  Reorder to acquire both locks BEFORE the SKB allocation.

Also reorder cleanup paths so dev_kfree_skb() runs BEFORE up() —
otherwise a small window exists where the SKB has been touched but the
lock has been released, allowing concurrent code to also touch it.

Three sites fixed:
  - bes2600_hw_scan: lock-take + ENOMEM cleanup + wsm_set_template_frame
    error cleanup + success-path SKB free + lock release order
  - bes2600_sched_scan_start (#ifdef ROAM_OFFLOAD): same three sub-fixes
    (compiled-out at default build, fixed for consistency)
  - All success/error paths: dev_kfree_skb before up()

Backport of cw1200 mainline commit 86760e0dfe36 ("cw1200: Fix
concurrency use-after-free bugs in cw1200_hw_scan()", 2018-12-14),
which fixed the identical bug in the same code shape we inherited.
That commit was merged from upstream 4f68ef64cd7f.

Cherry-picked from upstream Linux:
  86760e0dfe36 cw1200: Fix concurrency use-after-free bugs in cw1200_hw_scan()
  Author: Jia-Ju Bai <baijiaju1990@gmail.com>
  Link: https://lore.kernel.org/r/20181214035521.7575-1-baijiaju1990@gmail.com
2026-05-20 20:17:58 +02:00
test0r bdb0450bdf bes2600: widen scan-defer backoff to 30s and decay count on quiet
The scan-defer logic added in the previous patch ("bes2600: defer
scan and soften WARN on firmware reject") used a 10-second backoff
window and never cleared reject_count outside of a successful scan.
Field testing on a PineTab2 (linux-pinetab2 6.19.10-danctnix1) shows
two distinct mac80211 scan-retry cadences in practice:

  * Idle background scans every ~5 minutes when associated -- well
    outside any plausible backoff, the defer guard correctly falls
    through to a real WSM scan attempt.

  * Roam-evaluation bursts triggered when mac80211 wants to find a
    candidate AP for handover (signal degradation, beacon loss,
    locally-generated DEAUTH_LEAVING reason=3). Cadence is ~12 s, and
    one boot reproduced 14 such rejected scans in 3 minutes during a
    single burst, none of which engaged the defer guard because every
    retry landed just outside the 10 s window.

Two-line behaviour change to fix that:

  1. BES2600_SCAN_BACKOFF_JIFFIES grows from 10*HZ to 30*HZ, so a
     12 s-cadence burst stays inside the window across consecutive
     rejects and the third reject in the burst trips the threshold
     guard. The 5 min idle case is still naturally past the window
     and is unaffected.

  2. bes2600_scan_should_defer() resets reject_count to 0 when
     time_after(jiffies, backoff_until). Without this, reject_count
     accumulated indefinitely across the slow-cadence rejects, so an
     isolated reject after long quiet would have tripped the
     threshold the moment it arrived. After the change, count is
     latched only inside an active burst and decays cleanly when the
     burst ends.

Net effect on a roam burst:

  * t=0   reject #1 (count 1, backoff_until = t0 + 30s)
  * t=12  reject #2 (count 2, backoff_until = t1 + 30s)
  * t=24  reject #3 (count 3, threshold met, next scan deferred)
  * t=36  defer fires, no WSM round-trip, reject not sent
  * ...   defers continue until the firmware-policy state clears
  * scan succeeds -> reject_count = 0, normal cadence resumes

WSM 0x0007 confirm rejections in a burst drop from ~14 to ~3 (just
the scans needed to reach the threshold). wpa_supplicant's reason=3
locally-generated disconnects driven by exhausted roam candidates
during the same burst window also drop.

No new state, no new symbols, no change to mac80211-facing semantics:
the deferred scan still completes via the existing fail: path with
status=-EBUSY, the same response a real firmware-busy would produce.

Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
2026-05-20 20:16:59 +02:00
test0r 4fec8b2ecc bes2600: defer scan and soften WARN on firmware reject
On a BES2600-based PineTab2, mac80211's background-scan cadence
(about every 30 s when associated) triggers a two-step WARN splat
pattern, visible in dmesg roughly 30 times per 10 min of regular
WiFi use:

  wsm_generic_confirm ret 2
  WARNING: at wsm_handle_rx+0x8a4/0xf30 [bes2600]
  ... full stack trace ...
  ieee80211 phy0: wsm_generic_confirm failed for request 0x0007.
  WARNING: at bes2600_scan_work+0x5d4/0x810 [bes2600]
  ... full stack trace ...
  ieee80211 phy0: [SCAN] Scan failed (-22).

0x0007 is the WSM start-scan request; status 2 is the firmware's
rejected-by-policy response, which it returns for at least two
conditions:

  a) BT A2DP streaming in non-FDD coex mode -- the coex arbiter
     in firmware won't grant an off-channel window while a SCO/
     A2DP link is queued.
  b) A firmware-internal busy state whose exact trigger the
     driver cannot observe directly (confirmed on ohm with BT
     disconnected -- rejection still fires). Likely transient
     firmware-PM transitions.

Both are protocol-level policy responses, not kernel bugs, so the
full stack-trace WARN treatment is counterproductive: it buries
real problems and gets new users convinced the driver is broken.

Three-part fix:

  1. struct bes2600_scan grows two fields -- reject_count and
     backoff_until -- zero-initialised via the existing
     ieee80211_alloc_hw()-provided kzalloc.

  2. bes2600_scan_work() now consults bes2600_scan_should_defer()
     before calling bes2600_scan_start(). The helper short-
     circuits in two cases:

       - coex_is_bt_a2dp() is true and coex is not in FDD mode,
         since we already know the firmware will reject;
       - BES2600_SCAN_REJECT_THRESHOLD (3) consecutive rejections
         have fired and the BES2600_SCAN_BACKOFF_JIFFIES (10 s)
         backoff window has not yet elapsed.

     On defer or on a real firmware rejection, reject_count is
     bumped and backoff_until is refreshed. A successful scan
     clears reject_count.

  3. The WARN_ON(hw_priv->scan.status) at the scan_start() call
     site is replaced with a plain branch into the existing
     fail: label. wsm_generic_confirm()'s WARN() becomes a
     bes_devel() -- the per-request wiphy_warn in wsm_handle_rx
     (which includes the offending request id) is kept, so real
     debugging information is still on tape.

Net behaviour:

  - Expected rejections no longer produce stack traces. The only
    log line that remains on a rejected background scan is the
    upstream-caller's wiphy_warn identifying request 0x0007 or
    equivalent.
  - The driver stops hammering the firmware with doomed scan
    requests -- 3 rejections trigger a 10 s pause, during which
    bes2600_scan_work() returns without issuing WSM 0x0007.
  - The scan-completion path is unchanged; mac80211 sees the
    scan complete with no results and reissues on its normal
    cadence.
  - Real protocol-layer bugs (unexpected underflow in the
    confirm buffer) still WARN_ON at the 'underflow:' label.

Verified on ohm (PineTab2, linux-pinetab2 6.19.10-danctnix1-1):
WARN splat count dropped from 32 to 0 per 10 min uptime. WiFi
stays associated. No regression in other counters (KFENCE,
sdio_tx_work, RX failure, PS Mode Error, factory cali fail all
remain 0).

Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
2026-05-20 20:16:59 +02:00
test0r e0d752aae9 sync bes2600/ to v7.0-danctnix1 baseline (rebasing reference) 2026-05-19 09:04:33 +02:00
Julian ba20341e70 Upload
Source: https://github.com/cringeops/bes2600
Source: https://github.com/cringeops/bes2600/pull/14
Source: https://github.com/cringeops/bes2600/pull/17
Source: https://github.com/cringeops/bes2600/pull/20
2025-09-17 16:35:45 +02:00