WPS: Optimize attribute parsing workaround

Optimize the search for nonzero octets when checking for the need to
work around WPS M1 padding. The previous implementation was really
inefficient (O(n^2)) and while that was likely sufficiently fast for the
cases where the MMPDU size limit prevents long buffers (e.g., all P2P
Action frames), it might be able to take tens of seconds on low-end CPUs
with maximum length EAP-WSC messages during WPS provisioning. More
visibly, this was causing OSS-Fuzz to time out a test case with
unrealisticly long data (i.e., almost 10 times the maximum EAP-WSC
buffer length).

Credit to OSS-Fuzz: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=60039
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
This commit is contained in:
Jouni Malinen 2023-07-18 11:33:37 +03:00 committed by Jouni Malinen
parent 518ae8c7cc
commit a4c133ea73

View file

@ -599,10 +599,15 @@ int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
u16 type, len; u16 type, len;
#ifdef WPS_WORKAROUNDS #ifdef WPS_WORKAROUNDS
u16 prev_type = 0; u16 prev_type = 0;
size_t last_nonzero = 0;
const u8 *start;
#endif /* WPS_WORKAROUNDS */ #endif /* WPS_WORKAROUNDS */
os_memset(attr, 0, sizeof(*attr)); os_memset(attr, 0, sizeof(*attr));
pos = wpabuf_head(msg); pos = wpabuf_head(msg);
#ifdef WPS_WORKAROUNDS
start = pos;
#endif /* WPS_WORKAROUNDS */
end = pos + wpabuf_len(msg); end = pos + wpabuf_len(msg);
while (pos < end) { while (pos < end) {
@ -649,9 +654,15 @@ int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
* end of M1. Skip those to avoid interop issues. * end of M1. Skip those to avoid interop issues.
*/ */
int i; int i;
if (last_nonzero > (size_t) (pos - start))
continue;
for (i = 0; i < end - pos; i++) { for (i = 0; i < end - pos; i++) {
if (pos[i]) if (pos[i]) {
last_nonzero = pos - start + i;
break; break;
}
} }
if (i == end - pos) { if (i == end - pos) {
wpa_printf(MSG_DEBUG, "WPS: Workaround - skip " wpa_printf(MSG_DEBUG, "WPS: Workaround - skip "