static enum net_verdict ieee802154_recv(struct net_if *iface,
struct net_pkt *pkt)
{
struct ieee802154_mpdu mpdu;
size_t hdr_len;
// TS: Frame validation called here
if (!ieee802154_validate_frame(net_pkt_data(pkt),
net_pkt_get_len(pkt), &mpdu)) {
return NET_DROP;
}
if (mpdu.mhr.fs->fc.frame_type == IEEE802154_FRAME_TYPE_BEACON) {
return ieee802154_handle_beacon(iface, &mpdu,
net_pkt_ieee802154_lqi(pkt));
}
if (ieee802154_is_scanning(iface)) {
return NET_DROP;
}
if (mpdu.mhr.fs->fc.frame_type == IEEE802154_FRAME_TYPE_MAC_COMMAND) {
return ieee802154_handle_mac_command(iface, &mpdu);
}
// BUG: No case handling mpdu.mhr.fs->fc.frame_type == IEEE802154_FRAME_TYPE_ACK
// BUG: Also, no fallback "return NET_DROP;" here
// BUG: At this point, IEEE802154_FRAME_TYPE_ACK frame is handled as data frame
/* At this point the frame has to be a DATA one */
...
// BUG Result: mpdu.payload == 0 used here
// -> hdr_len = -net_pkt_data(pkt)
hdr_len = (uint8_t *)mpdu.payload - net_pkt_data(pkt);
// -> this sets pkt->buffer = pkt->buffer + (- net_pkt_data(pkt)) = 0
net_buf_pull(pkt->buffer, hdr_len);
// -> pkt->buffer is set to NULL now
// BUG Result: Using pkt->buffer->data later during processing crashes
return ieee802154_manage_recv_packet(iface, pkt, hdr_len);
}
bool ieee802154_validate_frame(uint8_t *buf, uint8_t length,
struct ieee802154_mpdu *mpdu)
{
...
return validate_payload_and_mfr(mpdu, buf, p_buf, &length);
}
static inline bool
validate_payload_and_mfr(struct ieee802154_mpdu *mpdu,
uint8_t *buf, uint8_t *p_buf, uint8_t *length)
{
...
// BUG Description: Validation recognizes ACK frame type, which processing does not
} else if (type == IEEE802154_FRAME_TYPE_ACK) {
/** An ACK frame has no payload */
if (*length) {
return false;
}
// BUG Result: payload pointer set to NULL here
mpdu->payload = NULL;
}
...
return true;
}
Add explicit check for DATA frame type, return NET_DROP in the default case, and initialize address struct explicitly for the IEEE802154_ADDR_MODE_NONE case.
diff --git a/subsys/net/l2/ieee802154/ieee802154.c b/subsys/net/l2/ieee802154/ieee802154.c
index da03e31b32..9d4908ed37 100644
--- a/subsys/net/l2/ieee802154/ieee802154.c
+++ b/subsys/net/l2/ieee802154/ieee802154.c
@@ -98,6 +98,8 @@ static inline void set_pkt_ll_addr(struct net_linkaddr *addr, bool comp,
struct ieee802154_address_field *ll)
{
if (mode == IEEE802154_ADDR_MODE_NONE) {
+ addr->len = 0;
+ addr->addr = NULL;
return;
}
@@ -202,27 +204,30 @@ static enum net_verdict ieee802154_recv(struct net_if *iface,
return ieee802154_handle_mac_command(iface, &mpdu);
}
- /* At this point the frame has to be a DATA one */
-
- ieee802154_acknowledge(iface, &mpdu);
+ // Proposed fix: Make the correct data type explicit
+ if (mpdu.mhr.fs->fc.frame_type == IEEE802154_FRAME_TYPE_DATA) {
+ ieee802154_acknowledge(iface, &mpdu);
- set_pkt_ll_addr(net_pkt_lladdr_src(pkt), mpdu.mhr.fs->fc.pan_id_comp,
- mpdu.mhr.fs->fc.src_addr_mode, mpdu.mhr.src_addr);
+ set_pkt_ll_addr(net_pkt_lladdr_src(pkt), mpdu.mhr.fs->fc.pan_id_comp,
+ mpdu.mhr.fs->fc.src_addr_mode, mpdu.mhr.src_addr);
- set_pkt_ll_addr(net_pkt_lladdr_dst(pkt), false,
- mpdu.mhr.fs->fc.dst_addr_mode, mpdu.mhr.dst_addr);
+ set_pkt_ll_addr(net_pkt_lladdr_dst(pkt), false,
+ mpdu.mhr.fs->fc.dst_addr_mode, mpdu.mhr.dst_addr);
- if (!ieee802154_decipher_data_frame(iface, pkt, &mpdu)) {
- return NET_DROP;
- }
+ if (!ieee802154_decipher_data_frame(iface, pkt, &mpdu)) {
+ return NET_DROP;
+ }
- pkt_hexdump(RX_PKT_TITLE " (with ll)", pkt, true);
+ pkt_hexdump(RX_PKT_TITLE " (with ll)", pkt, true);
- hdr_len = (uint8_t *)mpdu.payload - net_pkt_data(pkt);
- net_buf_pull(pkt->buffer, hdr_len);
+ hdr_len = (uint8_t *)mpdu.payload - net_pkt_data(pkt);
+ net_buf_pull(pkt->buffer, hdr_len);
- return ieee802154_manage_recv_packet(iface, pkt, hdr_len);
+ return ieee802154_manage_recv_packet(iface, pkt, hdr_len);
+ }
+ // Unsupported frame type
+ return NET_DROP;
}
static int ieee802154_send(struct net_if *iface, struct net_pkt *pkt)
2. Type Confusion in 802154 ACK Frames Handling
Source Code Snippets
Propsed Fix
Add explicit check for DATA frame type, return NET_DROP in the default case, and initialize address struct explicitly for the IEEE802154_ADDR_MODE_NONE case.
zephyr/subsys/net/l2/ieee802154/ieee802154.c
Line 205 in d969ace
Patches
This has been fixed in:
For more information
If you have any questions or comments about this advisory:
embargo: 2021-04-14
zepsec: ZEPSEC-113