Coverage Report

Created: 2026-10-16 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hostap/tests/fuzzing/ml-elems/ml-elems.c
Line
Count
Source
1
/*
2
 * Multi-Link element parsing - fuzzer
3
 * Copyright (c) 2026, Louis Kotze <loukot@gmail.com>
4
 *
5
 * This software may be distributed under the terms of the BSD license.
6
 * See README for more details.
7
 */
8
9
#include "utils/includes.h"
10
#include "utils/common.h"
11
#include "common/ieee802_11_common.h"
12
#include "common/ieee802_11_defs.h"
13
#include "common/defs.h"
14
#include "../fuzzer-common.h"
15
16
17
/*
18
 * Drive the per-STA profile parsers the way the callers in bss.c and events.c
19
 * do: the buffer starts at the Multi-Link Control field, not at the element
20
 * header. Both parsers may defragment subelements in place, so each call gets
21
 * its own copy.
22
 */
23
static void fuzz_link_profile(const u8 *mle, size_t mle_len)
24
16.2k
{
25
16.2k
  struct ieee802_11_elems elems;
26
16.2k
  struct wpabuf *mlbuf;
27
16.2k
  u8 link_id;
28
29
16.2k
  if (!mle || !mle_len)
30
14.6k
    return;
31
32
25.1k
  for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
33
23.5k
    mlbuf = ieee802_11_defrag(mle, mle_len, true);
34
23.5k
    if (!mlbuf)
35
0
      return;
36
23.5k
    os_memset(&elems, 0, sizeof(elems));
37
23.5k
    ieee802_11_parse_link_assoc_req(&elems, mlbuf, link_id, 1);
38
23.5k
    wpabuf_free(mlbuf);
39
40
23.5k
    mlbuf = ieee802_11_defrag(mle, mle_len, true);
41
23.5k
    if (!mlbuf)
42
0
      return;
43
23.5k
    os_memset(&elems, 0, sizeof(elems));
44
23.5k
    ieee802_11_parse_link_assoc_resp(&elems, mlbuf, link_id, 1);
45
23.5k
    wpabuf_free(mlbuf);
46
23.5k
  }
47
48
  /* parent_subelem must point inside mlbuf and, as every in-tree caller
49
   * guarantees by looping on "len > 2", must have a readable two octet
50
   * subelement header. Passing anything shorter breaks the callee's
51
   * contract and would only report a defect in this harness. */
52
1.57k
  if (mle_len >= 2) {
53
1.57k
    mlbuf = ieee802_11_defrag(mle, mle_len, true);
54
1.57k
    if (mlbuf) {
55
1.57k
      size_t defrag_len = 0;
56
57
1.57k
      ieee802_11_defrag_mle_subelem(mlbuf, wpabuf_head(mlbuf),
58
1.57k
                  &defrag_len);
59
1.57k
      wpabuf_free(mlbuf);
60
1.57k
    }
61
1.57k
  }
62
1.57k
}
63
64
65
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
66
3.25k
{
67
3.25k
  struct ieee802_11_elems elems;
68
3.25k
  struct wpabuf *buf;
69
3.25k
  u8 type;
70
71
3.25k
  wpa_fuzzer_set_debug_level();
72
73
3.25k
  if (size > 10000)
74
8
    return 0;
75
76
  /* Full element parsing; dispatches to the Multi-Link element handling
77
   * and to element fragment reassembly. */
78
3.25k
  ieee802_11_parse_elems(data, size, &elems, 1);
79
80
  /* Each Multi-Link element variant the parser recognised, handed on in
81
   * the same shape the real callers use. */
82
3.25k
  fuzz_link_profile(elems.basic_mle, elems.basic_mle_len);
83
3.25k
  fuzz_link_profile(elems.probe_req_mle, elems.probe_req_mle_len);
84
3.25k
  fuzz_link_profile(elems.reconf_mle, elems.reconf_mle_len);
85
3.25k
  fuzz_link_profile(elems.tdls_mle, elems.tdls_mle_len);
86
3.25k
  fuzz_link_profile(elems.prior_access_mle, elems.prior_access_mle_len);
87
88
  /* Basic Multi-Link element accessors, both on the element payload the
89
   * parser found and on the raw input, so the short-buffer rejection
90
   * paths are covered too. */
91
3.25k
  if (elems.basic_mle) {
92
1.45k
    get_basic_mle_mld_addr(elems.basic_mle, elems.basic_mle_len);
93
1.45k
    get_basic_mle_eml_capa(elems.basic_mle, elems.basic_mle_len);
94
1.45k
    get_basic_mle_link_id(elems.basic_mle, elems.basic_mle_len);
95
1.45k
  }
96
3.25k
  get_basic_mle_mld_addr(data, size);
97
3.25k
  get_basic_mle_eml_capa(data, size);
98
3.25k
  get_basic_mle_link_id(data, size);
99
100
29.2k
  for (type = 0; type < 8; type++)
101
26.0k
    get_ml_ie(data, size, type);
102
103
  /* Element defragmentation, both element and extended-element forms. */
104
3.25k
  buf = ieee802_11_defrag(data, size, true);
105
3.25k
  if (buf) {
106
    /* Also drive subelement defragmentation straight off the input,
107
     * not only via a Multi-Link element the parser recognised. */
108
3.25k
    if (wpabuf_len(buf) >= 2) {
109
3.24k
      size_t defrag_len = 0;
110
111
3.24k
      ieee802_11_defrag_mle_subelem(buf, wpabuf_head(buf),
112
3.24k
                  &defrag_len);
113
3.24k
    }
114
3.25k
    wpabuf_free(buf);
115
3.25k
  }
116
3.25k
  buf = ieee802_11_defrag(data, size, false);
117
3.25k
  wpabuf_free(buf);
118
119
3.25k
  return 0;
120
3.25k
}