Skip to content

Commit 38970c0

Browse files
Tomasz Bursztykajukkar
authored andcommitted
net/ieee802154: Validate length on received frames
Frame format was validated, but its length should be also validated relevantly against the format. Fixes #24970 Signed-off-by: Tomasz Bursztyka <[email protected]>
1 parent 45bdb23 commit 38970c0

File tree

3 files changed

+110
-46
lines changed

3 files changed

+110
-46
lines changed

subsys/net/l2/ieee802154/ieee802154_frame.c

Lines changed: 92 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ const u8_t level_2_tag_size[4] = {
3737
};
3838
#endif
3939

40-
struct ieee802154_fcf_seq *ieee802154_validate_fc_seq(u8_t *buf, u8_t **p_buf)
40+
struct ieee802154_fcf_seq *ieee802154_validate_fc_seq(u8_t *buf, u8_t **p_buf,
41+
u8_t *length)
4142
{
4243
struct ieee802154_fcf_seq *fs = (struct ieee802154_fcf_seq *)buf;
4344

@@ -81,17 +82,20 @@ struct ieee802154_fcf_seq *ieee802154_validate_fc_seq(u8_t *buf, u8_t **p_buf)
8182
#endif
8283

8384
if (p_buf) {
84-
*p_buf = buf + 3;
85+
*length -= IEEE802154_FCF_SEQ_LENGTH;
86+
*p_buf = buf + IEEE802154_FCF_SEQ_LENGTH;
8587
}
8688

8789
return fs;
8890
}
8991

9092
static inline struct ieee802154_address_field *
91-
validate_addr(u8_t *buf, u8_t **p_buf,
93+
validate_addr(u8_t *buf, u8_t **p_buf, u8_t *length,
9294
enum ieee802154_addressing_mode mode,
9395
bool pan_id_compression)
9496
{
97+
u8_t len = 0;
98+
9599
*p_buf = buf;
96100

97101
NET_DBG("Buf %p - mode %d - pan id comp %d",
@@ -102,59 +106,76 @@ validate_addr(u8_t *buf, u8_t **p_buf,
102106
}
103107

104108
if (!pan_id_compression) {
105-
*p_buf += IEEE802154_PAN_ID_LENGTH;
109+
len = IEEE802154_PAN_ID_LENGTH;
106110
}
107111

108112
if (mode == IEEE802154_ADDR_MODE_SHORT) {
109-
*p_buf += IEEE802154_SHORT_ADDR_LENGTH;
113+
len += IEEE802154_SHORT_ADDR_LENGTH;
110114
} else {
111115
/* IEEE802154_ADDR_MODE_EXTENDED */
112-
*p_buf += IEEE802154_EXT_ADDR_LENGTH;
116+
len += IEEE802154_EXT_ADDR_LENGTH;
113117
}
114118

119+
if (len > *length) {
120+
return NULL;
121+
}
122+
123+
*p_buf += len;
124+
*length -= len;
125+
115126
return (struct ieee802154_address_field *)buf;
116127
}
117128

118129
#ifdef CONFIG_NET_L2_IEEE802154_SECURITY
119130
struct ieee802154_aux_security_hdr *
120-
ieee802154_validate_aux_security_hdr(u8_t *buf, u8_t **p_buf)
131+
ieee802154_validate_aux_security_hdr(u8_t *buf, u8_t **p_buf, u8_t *length)
121132
{
122133
struct ieee802154_aux_security_hdr *ash =
123134
(struct ieee802154_aux_security_hdr *)buf;
135+
u8_t len = IEEE802154_SECURITY_CF_LENGTH +
136+
IEEE802154_SECURITY_FRAME_COUNTER_LENGTH;
124137

125-
*p_buf = buf;
138+
/* At least the asf is sized of: control field + frame counter */
139+
if (*length < len) {
140+
return NULL;
141+
}
126142

127143
/* Only implicit key mode is supported for now */
128144
if (ash->control.key_id_mode != IEEE802154_KEY_ID_MODE_IMPLICIT) {
129145
return NULL;
130146
}
131147

132-
/* At least the asf is sized of: control field + frame counter */
133-
*p_buf += sizeof(struct ieee802154_security_control_field) +
134-
sizeof(u32_t);
135-
136148
/* Explicit key must have a key index != 0x00, see Section 7.4.3.2 */
137149
switch (ash->control.key_id_mode) {
138150
case IEEE802154_KEY_ID_MODE_IMPLICIT:
139151
break;
140152
case IEEE802154_KEY_ID_MODE_INDEX:
141-
*p_buf += IEEE8021254_KEY_ID_FIELD_INDEX_LENGTH;
153+
len += IEEE8021254_KEY_ID_FIELD_INDEX_LENGTH;
154+
if (*length < len) {
155+
return NULL;
156+
}
142157

143158
if (!ash->kif.mode_1.key_index) {
144159
return NULL;
145160
}
146161

147162
break;
148163
case IEEE802154_KEY_ID_MODE_SRC_4_INDEX:
149-
*p_buf += IEEE8021254_KEY_ID_FIELD_SRC_4_INDEX_LENGTH;
164+
len += IEEE8021254_KEY_ID_FIELD_SRC_4_INDEX_LENGTH;
165+
if (*length < len) {
166+
return NULL;
167+
}
150168

151169
if (!ash->kif.mode_2.key_index) {
152170
return NULL;
153171
}
154172

155173
break;
156174
case IEEE802154_KEY_ID_MODE_SRC_8_INDEX:
157-
*p_buf += IEEE8021254_KEY_ID_FIELD_SRC_8_INDEX_LENGTH;
175+
len += IEEE8021254_KEY_ID_FIELD_SRC_8_INDEX_LENGTH;
176+
if (*length < len) {
177+
return NULL;
178+
}
158179

159180
if (!ash->kif.mode_3.key_index) {
160181
return NULL;
@@ -163,44 +184,52 @@ ieee802154_validate_aux_security_hdr(u8_t *buf, u8_t **p_buf)
163184
break;
164185
}
165186

187+
*p_buf = buf + len;
188+
*length -= len;
189+
166190
return ash;
167191
}
168192
#endif /* CONFIG_NET_L2_IEEE802154_SECURITY */
169193

170194
static inline bool
171-
validate_beacon(struct ieee802154_mpdu *mpdu, u8_t *buf, u8_t length)
195+
validate_beacon(struct ieee802154_mpdu *mpdu, u8_t *buf, u8_t *length)
172196
{
173197
struct ieee802154_beacon *b = (struct ieee802154_beacon *)buf;
174-
u8_t *p_buf = buf;
175198
struct ieee802154_pas_spec *pas;
199+
u8_t len = IEEE802154_BEACON_SF_SIZE +
200+
IEEE802154_BEACON_GTS_SPEC_SIZE;
201+
176202

177-
if (length < IEEE802154_BEACON_MIN_SIZE) {
203+
if (*length < len) {
178204
return false;
179205
}
180206

181-
p_buf += IEEE802154_BEACON_SF_SIZE + IEEE802154_BEACON_GTS_SPEC_SIZE;
182-
183207
if (b->gts.desc_count) {
184-
p_buf += IEEE802154_BEACON_GTS_DIR_SIZE +
208+
len += IEEE802154_BEACON_GTS_DIR_SIZE +
185209
b->gts.desc_count * IEEE802154_BEACON_GTS_SIZE;
186210
}
187211

188-
if (length < (p_buf - buf)) {
212+
if (*length < len) {
189213
return false;
190214
}
191215

192-
pas = (struct ieee802154_pas_spec *)p_buf;
193-
p_buf += IEEE802154_BEACON_PAS_SPEC_SIZE;
216+
pas = (struct ieee802154_pas_spec *)buf + len;
217+
218+
len += IEEE802154_BEACON_PAS_SPEC_SIZE;
219+
if (*length < len) {
220+
return false;
221+
}
194222

195223
if (pas->nb_sap || pas->nb_eap) {
196-
p_buf += (pas->nb_sap * IEEE802154_SHORT_ADDR_LENGTH) +
224+
len += (pas->nb_sap * IEEE802154_SHORT_ADDR_LENGTH) +
197225
(pas->nb_eap * IEEE802154_EXT_ADDR_LENGTH);
198226
}
199227

200-
if (length < (p_buf - buf)) {
228+
if (*length < len) {
201229
return false;
202230
}
203231

232+
*length -= len;
204233
mpdu->beacon = b;
205234

206235
return true;
@@ -241,26 +270,37 @@ validate_mac_command_cfi_to_mhr(struct ieee802154_mhr *mhr,
241270
}
242271

243272
static inline bool
244-
validate_mac_command(struct ieee802154_mpdu *mpdu, u8_t *buf, u8_t length)
273+
validate_mac_command(struct ieee802154_mpdu *mpdu, u8_t *buf, u8_t *length)
245274
{
246275
struct ieee802154_command *c = (struct ieee802154_command *)buf;
276+
u8_t len = IEEE802154_CMD_CFI_LENGTH;
247277
bool src_pan_brdcst_chk = false;
248278
bool dst_brdcst_chk = false;
249279
u8_t comp = 0U;
250280
u8_t ar = 0U;
251281
u8_t src, dst;
252282

283+
if (*length < len) {
284+
return false;
285+
}
286+
253287
switch (c->cfi) {
254288
case IEEE802154_CFI_UNKNOWN:
255289
return false;
256290
case IEEE802154_CFI_ASSOCIATION_REQUEST:
291+
len += IEEE802154_CMD_ASSOC_REQ_LENGTH;
257292
src = IEEE802154_EXT_ADDR_LENGTH;
258293
src_pan_brdcst_chk = true;
259294
dst = IEEE802154_ADDR_MODE_SHORT |
260295
IEEE802154_ADDR_MODE_EXTENDED;
296+
261297
break;
262298
case IEEE802154_CFI_ASSOCIATION_RESPONSE:
299+
len += IEEE802154_CMD_ASSOC_RES_LENGTH;
263300
case IEEE802154_CFI_DISASSOCIATION_NOTIFICATION:
301+
if (c->cfi == IEEE802154_CFI_DISASSOCIATION_NOTIFICATION) {
302+
len += IEEE802154_CMD_DISASSOC_NOTE_LENGTH;
303+
}
264304
case IEEE802154_CFI_PAN_ID_CONLICT_NOTIFICATION:
265305
ar = 1U;
266306
comp = 1U;
@@ -296,6 +336,7 @@ validate_mac_command(struct ieee802154_mpdu *mpdu, u8_t *buf, u8_t length)
296336

297337
break;
298338
case IEEE802154_CFI_COORDINATOR_REALIGNEMENT:
339+
len += IEEE802154_CMD_COORD_REALIGN_LENGTH;
299340
src = IEEE802154_EXT_ADDR_LENGTH;
300341

301342
if (mpdu->mhr.fs->fc.dst_addr_mode ==
@@ -308,6 +349,7 @@ validate_mac_command(struct ieee802154_mpdu *mpdu, u8_t *buf, u8_t length)
308349

309350
break;
310351
case IEEE802154_CFI_GTS_REQUEST:
352+
len += IEEE802154_GTS_REQUEST_LENGTH;
311353
ar = 1U;
312354
src = IEEE802154_ADDR_MODE_SHORT;
313355
dst = IEEE802154_ADDR_MODE_NONE;
@@ -317,54 +359,60 @@ validate_mac_command(struct ieee802154_mpdu *mpdu, u8_t *buf, u8_t length)
317359
return false;
318360
}
319361

362+
if (*length < len) {
363+
return false;
364+
}
365+
320366
if (!validate_mac_command_cfi_to_mhr(&mpdu->mhr, ar, comp,
321367
src, src_pan_brdcst_chk,
322368
dst, dst_brdcst_chk)) {
323369
return false;
324370
}
325371

372+
*length -= len;
326373
mpdu->command = c;
327374

328375
return true;
329376
}
330377

331378
static inline bool
332379
validate_payload_and_mfr(struct ieee802154_mpdu *mpdu,
333-
u8_t *buf, u8_t *p_buf, u8_t length)
380+
u8_t *buf, u8_t *p_buf, u8_t *length)
334381
{
335382
u8_t type = mpdu->mhr.fs->fc.frame_type;
336-
u8_t payload_length;
337-
338-
payload_length = length - (p_buf - buf);
339383

340-
NET_DBG("Header size: %u, vs total length %u: payload size %u",
341-
(u32_t)(p_buf - buf), length, payload_length);
384+
NET_DBG("Header size: %u, payload size %u",
385+
(u32_t)(p_buf - buf), *length);
342386

343387
if (type == IEEE802154_FRAME_TYPE_BEACON) {
344-
if (!validate_beacon(mpdu, p_buf, payload_length)) {
388+
if (!validate_beacon(mpdu, p_buf, length)) {
345389
return false;
346390
}
347391
} else if (type == IEEE802154_FRAME_TYPE_DATA) {
348392
/** A data frame embeds a payload */
349-
if (payload_length == 0U) {
393+
if (*length == 0U) {
350394
return false;
351395
}
352396

353397
mpdu->payload = (void *)p_buf;
354398
} else if (type == IEEE802154_FRAME_TYPE_ACK) {
355399
/** An ACK frame has no payload */
356-
if (payload_length) {
400+
if (*length) {
357401
return false;
358402
}
359403

360404
mpdu->payload = NULL;
361405
} else {
362-
if (!validate_mac_command(mpdu, p_buf, payload_length)) {
406+
if (!validate_mac_command(mpdu, p_buf, length)) {
363407
return false;
364408
}
365409
}
366410

367-
mpdu->mfr = (struct ieee802154_mfr *)(p_buf + payload_length);
411+
if (*length) {
412+
mpdu->mfr = (struct ieee802154_mfr *)(p_buf + *length);
413+
} else {
414+
mpdu->mfr = NULL;
415+
}
368416

369417
return true;
370418
}
@@ -379,7 +427,7 @@ bool ieee802154_validate_frame(u8_t *buf, u8_t length,
379427
return false;
380428
}
381429

382-
mpdu->mhr.fs = ieee802154_validate_fc_seq(buf, &p_buf);
430+
mpdu->mhr.fs = ieee802154_validate_fc_seq(buf, &p_buf, &length);
383431
if (!mpdu->mhr.fs) {
384432
return false;
385433
}
@@ -389,25 +437,26 @@ bool ieee802154_validate_frame(u8_t *buf, u8_t length,
389437
return false;
390438
}
391439

392-
mpdu->mhr.dst_addr = validate_addr(p_buf, &p_buf,
440+
mpdu->mhr.dst_addr = validate_addr(p_buf, &p_buf, &length,
393441
mpdu->mhr.fs->fc.dst_addr_mode,
394442
false);
395443

396-
mpdu->mhr.src_addr = validate_addr(p_buf, &p_buf,
444+
mpdu->mhr.src_addr = validate_addr(p_buf, &p_buf, &length,
397445
mpdu->mhr.fs->fc.src_addr_mode,
398446
(mpdu->mhr.fs->fc.pan_id_comp));
399447

400448
#ifdef CONFIG_NET_L2_IEEE802154_SECURITY
401449
if (mpdu->mhr.fs->fc.security_enabled) {
402450
mpdu->mhr.aux_sec =
403-
ieee802154_validate_aux_security_hdr(p_buf, &p_buf);
451+
ieee802154_validate_aux_security_hdr(p_buf, &p_buf,
452+
&length);
404453
if (!mpdu->mhr.aux_sec) {
405454
return false;
406455
}
407456
}
408457
#endif
409458

410-
return validate_payload_and_mfr(mpdu, buf, p_buf, length);
459+
return validate_payload_and_mfr(mpdu, buf, p_buf, &length);
411460
}
412461

413462
u8_t ieee802154_compute_header_size(struct net_if *iface,

0 commit comments

Comments
 (0)