# DF-3970 — rt2560_set_chan: unbounded walk of the unterminated RT2560_RF5222 channel table → OOB read + misprogrammed RF (admin-installed channel)

**File:** sys/dev/netif/ral/rt2560.c (pass 2, GLM 5.3)

## What
`rt2560_set_chan` (2210) does `for (i = 0; rt2560_rf5222[i].chan != chan; i++);`
with **no bound** against a 41-entry table (rt2560reg.h:449-489) that has **no
terminator**. The stock channel lists (ieee80211_regdomain.c:101-108) are fully
covered by the table, so the default configuration never misses — but
`SIOCS80211/IEEE80211_IOC_REGDOMAIN` (ieee80211_ioctl.c:2126-2162 →
ieee80211_setregdomain → the driver's `null_setregdomain`, ieee80211_regdomain.c:59-65,
accepts **anything**) memcpy's an admin-supplied channel table into
`ic->ic_channels` validating only freq/flags/maxregpower — never the ieee
number against the driver's RF tables. Selecting an installed channel whose
ieee number is not among the 41 entries (165, 34, 184-196, …) walks the loop
off the end of the table into adjacent kernel .rodata until a byte coincidentally
equals `chan`, then programs whatever 12 bytes follow into RF registers R1/R2/R4.

## Impact
Kernel OOB read (bounded by kernel image mapping; data not returned to
userspace) + garbage RF programming → radio misbehavior / potential hang.
Admin-gated (regdomain ioctl + channel set are privileged), Low.

## Build / Run
Hardware-gated (RT2560/RT5222 dual-band NIC; guest has none — env.txt):
  cc trigger.c        (informational)
  # on target as root: install a regdomain channel table containing ieee=165,
  # then `ifconfig wlan0 channel 165`

## Fix validation
fix.diff bounds the walk with nitems() and logs+bails on unknown channels;
`git apply --check` clean; module rebuilt clean with -Werror on the guest
(build.log).
