Commit 304b44f0 authored by Antony Antony's avatar Antony Antony Committed by Steffen Klassert
Browse files

xfrm: Add dir validation to "in" data path lookup



Introduces validation for the x->dir attribute within the XFRM input
data lookup path. If the configured direction does not match the
expected direction, input, increment the XfrmInStateDirError counter
and drop the packet to ensure data integrity and correct flow handling.

grep -vw 0 /proc/net/xfrm_stat
XfrmInStateDirError     	1

Signed-off-by: default avatarAntony Antony <antony.antony@secunet.com>
Reviewed-by: default avatarSabrina Dubroca <sd@queasysnail.net>
Reviewed-by: default avatarNicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent 601a0867
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -73,6 +73,9 @@ XfrmAcquireError:
XfrmFwdHdrError:
	Forward routing of a packet is not allowed

XfrmInStateDirError:
        State direction mismatch (lookup found an output state on the input path, expected input or no direction)

Outbound errors
~~~~~~~~~~~~~~~
XfrmOutError:
+1 −0
Original line number Diff line number Diff line
@@ -338,6 +338,7 @@ enum
	LINUX_MIB_XFRMOUTSTATEINVALID,		/* XfrmOutStateInvalid */
	LINUX_MIB_XFRMACQUIREERROR,		/* XfrmAcquireError */
	LINUX_MIB_XFRMOUTSTATEDIRERROR,		/* XfrmOutStateDirError */
	LINUX_MIB_XFRMINSTATEDIRERROR,		/* XfrmInStateDirError */
	__LINUX_MIB_XFRMMAX
};

+7 −0
Original line number Diff line number Diff line
@@ -266,6 +266,13 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
		if (!x)
			continue;

		if (unlikely(x->dir && x->dir != XFRM_SA_DIR_IN)) {
			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEDIRERROR);
			xfrm_state_put(x);
			x = NULL;
			continue;
		}

		spin_lock(&x->lock);

		if ((!i || (x->props.flags & XFRM_STATE_WILDRECV)) &&
+11 −0
Original line number Diff line number Diff line
@@ -466,6 +466,11 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
	if (encap_type < 0 || (xo && xo->flags & XFRM_GRO)) {
		x = xfrm_input_state(skb);

		if (unlikely(x->dir && x->dir != XFRM_SA_DIR_IN)) {
			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEDIRERROR);
			goto drop;
		}

		if (unlikely(x->km.state != XFRM_STATE_VALID)) {
			if (x->km.state == XFRM_STATE_ACQ)
				XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR);
@@ -571,6 +576,12 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
			goto drop;
		}

		if (unlikely(x->dir && x->dir != XFRM_SA_DIR_IN)) {
			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEDIRERROR);
			xfrm_state_put(x);
			goto drop;
		}

		skb->mark = xfrm_smark_get(skb->mark, x);

		sp->xvec[sp->len++] = x;
+1 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ static const struct snmp_mib xfrm_mib_list[] = {
	SNMP_MIB_ITEM("XfrmOutStateInvalid", LINUX_MIB_XFRMOUTSTATEINVALID),
	SNMP_MIB_ITEM("XfrmAcquireError", LINUX_MIB_XFRMACQUIREERROR),
	SNMP_MIB_ITEM("XfrmOutStateDirError", LINUX_MIB_XFRMOUTSTATEDIRERROR),
	SNMP_MIB_ITEM("XfrmInStateDirError", LINUX_MIB_XFRMINSTATEDIRERROR),
	SNMP_MIB_SENTINEL
};