[PATCH] macsec: reject frames that decapsulate into runt Ethernet frames
flat view
WARM2d
From: Kyle Zeng <hidden>
Date: 2026-10-30 04:22:40
Also in:
lkml
Subsystem:
networking drivers, networking [macsec], the rest · Maintainers:
Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Sabrina Dubroca, Linus Torvalds
When an SCI is unknown and the C bit is clear, macsec_handle_frame() removes the SecTAG and the default ICV without checking how much of the frame remains. A short frame can therefore become an skb shorter than ETH_HLEN. eth_type_trans() cannot pull its Ethernet header, and a second stacked MACsec device can copy stale skb headroom into a packet delivered to a packet socket. The matched-SCI path has a related hole: macsec_validate_skb() accepts a short_length of one, so a frame that passes the existing length check can still become a 13-byte Ethernet frame. Require enough bytes for the MACsec overhead and a complete Ethernet header before decapsulating an unknown-SCI frame. Apply the same bound in macsec_validate_skb(), using the selected SecY's ICV length, to cover the no-SA, synchronous-decrypt and asynchronous-decrypt delivery paths. Leave other unknown-SCI handling unchanged. Fixes: c09440f7dcb3 ("macsec: introduce IEEE 802.1AE driver") Cc: <redacted> Signed-off-by: Kyle Zeng <redacted> --- I have a reproducer for this issue and can share via DM drivers/net/macsec.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 87f3f4bdb026..240ba0ae07d1 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c@@ -408,8 +408,10 @@ static bool macsec_validate_skb(struct sk_buff *skb, u16 icv_len, bool xpn) int len = skb->len - 2 * ETH_ALEN; int extra_len = macsec_extra_len(!!(h->tci_an & MACSEC_TCI_SC)) + icv_len; - /* a) It comprises at least 17 octets */ - if (skb->len <= 16) + /* a) It comprises at least 17 octets. The SecTAG and ICV must + * also leave a complete Ethernet header. + */ + if (skb->len < ETH_HLEN + extra_len) return false; /* b) MACsec EtherType: already checked */
@@ -1331,9 +1333,12 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb) nosci: /* 10.6.1 if the SC is not found */ cbit = !!(hdr->tci_an & MACSEC_TCI_C); - if (!cbit) - macsec_finalize_skb(skb, MACSEC_DEFAULT_ICV_LEN, - macsec_extra_len(macsec_skb_cb(skb)->has_sci)); + if (!cbit) { + len = macsec_extra_len(macsec_skb_cb(skb)->has_sci); + if (skb->len < ETH_HLEN + len + MACSEC_DEFAULT_ICV_LEN) + goto drop_nosc; + macsec_finalize_skb(skb, MACSEC_DEFAULT_ICV_LEN, len); + } list_for_each_entry_rcu(macsec, &rxd->secys, secys) { struct sk_buff *nskb;
base-commit: d89e1d186ec9271bf78e62771779e9fc03bf0fc3 -- 2.56.0