CVE-2026-49878 AI-generated analysis
platform/external/wpa_supplicant_8, wpa_supplicant Robust AV / SCS (Stream Classification Service) action frame handling (wpa_supplicant/robust_av.c)
Replaces two undersized os_zalloc(num_active_scs) allocations for the int arrays scs_resp[0] and scs_resp[1] in wpas_handle_robust_av_scs_recv_action with os_calloc(num_active_scs, sizeof(int)). This fixes the heap out-of-bounds write in the SCS Response handler.
Root cause
In wpa_supplicant/robust_av.c, wpas_handle_robust_av_scs_recv_action() processes a received SCS Response action frame. It first checks three things: the dialog token matches, the count field is valid (count != 0 and count * 3 <= remaining len), and count does not exceed num_active_scs = dl_list_len(&wpa_s->active_scs_ids). It then allocated two result arrays with scs_resp[0] = (int *) os_zalloc(num_active_scs) and scs_resp[1] = (int *) os_zalloc(num_active_scs). os_zalloc takes a byte size, so each buffer was only num_active_scs bytes. According to the commit message, the code uses these buffers as int arrays, which led to heap out-of-bounds writes. The writes happen in the per-response loop (for i < count). The exact write sites are not shown in the material.
How the fix works
- wpa_supplicant/robust_av.c:wpas_handle_robust_av_scs_recv_action: scs_resp[0] = (int *) os_zalloc(num_active_scs) is replaced by scs_resp[0] = os_calloc(num_active_scs, sizeof(int)). This allocates num_active_scs zeroed int elements instead of num_active_scs bytes.
- wpa_supplicant/robust_av.c:wpas_handle_robust_av_scs_recv_action: the same change is made for scs_resp[1] = os_calloc(num_active_scs, sizeof(int)). The existing NULL checks, and the os_free(scs_resp[0]) when the second allocation fails, are unchanged.
- No validation logic changes. The existing frame checks (dialog token match, count != 0, count * 3 <= len, count <= num_active_scs) are unchanged, and they limit the loop to at most num_active_scs iterations.
Completeness
- Both undersized allocations shown (scs_resp[0] and scs_resp[1]) are corrected. The shown context (lines 614-673) has no other os_zalloc call.
- The fix relies on the existing check at line 637 (num_active_scs < count leads to a drop) to bound the loop count by num_active_scs. That check is untouched.
- Only part of the loop that writes into scs_resp is shown (up to line 673), so the exact write sites are not visible in the material.
- The fix only corrects the allocation size. It adds no new bounds checks, and the diff touches no other code in robust_av.c.
Behavior changes
- scs_resp[0] and scs_resp[1] are now num_active_scs * sizeof(int) bytes instead of num_active_scs bytes. The diff does not change which frames are accepted or rejected, the logging, or the return paths.
- os_calloc in the hostap os abstraction checks nmemb * size for overflow and returns NULL on overflow, which would take the existing allocation-failure paths (general platform knowledge).
Per major
- Android 14: same fix: commit 5de2705a451f in android-security-14.0.0_r29, the same two-line change at robust_av.c hunk @@ -640. The code at android-security-14.0.0_r30 shows the os_calloc lines in place.
- Android 15: same fix: commit d14e657ca1ae in android-security-15.0.0_r17, the same change at hunk @@ -807 (only the line offset differs).
- Android 16: same fix: commit d131540379d6 in android-security-16.0.0_r8, the same change at hunk @@ -881.
- Android 17: same fix: commit ffd3987bbece in android-security-17.0.0_r1, the same change at hunk @@ -1072.
Unknowns
- The exact write sites into scs_resp[0]/scs_resp[1] inside the response loop, the values written, and how the arrays are used afterwards are not shown.
- Whether the SCS feature (populating active_scs_ids) is enabled or reachable by default on Android builds, and how scs_dialog_token gets set, is not shown.
- The content of the two internal Cherrypick-From commits is not shown.
- The material does not explain the resolver's '5/7 lines of the patched region present' figure, even though the os_calloc lines are visible at r30.