Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xfrm: Log input direction mismatch error in one place

Previously, the offload data path decrypted the packet before checking
the direction, leading to error logging and packet dropping. However,
dropped packets wouldn't be visible in tcpdump or audit log.

With this fix, the offload path, upon noticing SA direction mismatch,
will pass the packet to the stack without decrypting it. The L3 layer
will then log the error, audit, and drop ESP without decrypting or
decapsulating it.

This also ensures that the slow path records the error and audit log,
making dropped packets visible in tcpdump.

Fixes: 304b44f0d5a4 ("xfrm: Add dir validation to "in" data path lookup")
Signed-off-by: Antony Antony <antony.antony@secunet.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>

authored by

Antony Antony and committed by
Steffen Klassert
15f5fe9e 54fcc618

+14 -5
+7
net/ipv4/esp4_offload.c
··· 56 56 x = xfrm_state_lookup(dev_net(skb->dev), skb->mark, 57 57 (xfrm_address_t *)&ip_hdr(skb)->daddr, 58 58 spi, IPPROTO_ESP, AF_INET); 59 + 60 + if (unlikely(x && x->dir && x->dir != XFRM_SA_DIR_IN)) { 61 + /* non-offload path will record the error and audit log */ 62 + xfrm_state_put(x); 63 + x = NULL; 64 + } 65 + 59 66 if (!x) 60 67 goto out_reset; 61 68
+7
net/ipv6/esp6_offload.c
··· 83 83 x = xfrm_state_lookup(dev_net(skb->dev), skb->mark, 84 84 (xfrm_address_t *)&ipv6_hdr(skb)->daddr, 85 85 spi, IPPROTO_ESP, AF_INET6); 86 + 87 + if (unlikely(x && x->dir && x->dir != XFRM_SA_DIR_IN)) { 88 + /* non-offload path will record the error and audit log */ 89 + xfrm_state_put(x); 90 + x = NULL; 91 + } 92 + 86 93 if (!x) 87 94 goto out_reset; 88 95
-5
net/xfrm/xfrm_input.c
··· 474 474 if (encap_type < 0 || (xo && xo->flags & XFRM_GRO)) { 475 475 x = xfrm_input_state(skb); 476 476 477 - if (unlikely(x->dir && x->dir != XFRM_SA_DIR_IN)) { 478 - XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEDIRERROR); 479 - goto drop; 480 - } 481 - 482 477 if (unlikely(x->km.state != XFRM_STATE_VALID)) { 483 478 if (x->km.state == XFRM_STATE_ACQ) 484 479 XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR);