Commit 025c65e1 authored by Martin Willi's avatar Martin Willi Committed by Steffen Klassert
Browse files

xfrm: Honor original L3 slave device in xfrmi policy lookup



If an xfrmi is associated to a vrf layer 3 master device,
xfrm_policy_check() fails after traffic decapsulation. The input
interface is replaced by the layer 3 master device, and hence
xfrmi_decode_session() can't match the xfrmi anymore to satisfy
policy checking.

Extend ingress xfrmi lookup to honor the original layer 3 slave
device, allowing xfrm interfaces to operate within a vrf domain.

Fixes: f203b76d ("xfrm: Add virtual xfrm interfaces")
Signed-off-by: default avatarMartin Willi <martin@strongswan.org>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent 8dfb4eba
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -295,7 +295,8 @@ struct xfrm_replay {
};

struct xfrm_if_cb {
	struct xfrm_if	*(*decode_session)(struct sk_buff *skb);
	struct xfrm_if	*(*decode_session)(struct sk_buff *skb,
					   unsigned short family);
};

void xfrm_if_register_cb(const struct xfrm_if_cb *ifcb);
+14 −3
Original line number Diff line number Diff line
@@ -70,18 +70,29 @@ static struct xfrm_if *xfrmi_lookup(struct net *net, struct xfrm_state *x)
	return NULL;
}

static struct xfrm_if *xfrmi_decode_session(struct sk_buff *skb)
static struct xfrm_if *xfrmi_decode_session(struct sk_buff *skb,
					    unsigned short family)
{
	struct xfrmi_net *xfrmn;
	int ifindex;
	struct xfrm_if *xi;
	int ifindex = 0;

	if (!secpath_exists(skb) || !skb->dev)
		return NULL;

	xfrmn = net_generic(xs_net(xfrm_input_state(skb)), xfrmi_net_id);
	switch (family) {
	case AF_INET6:
		ifindex = inet6_sdif(skb);
		break;
	case AF_INET:
		ifindex = inet_sdif(skb);
		break;
	}
	if (!ifindex)
		ifindex = skb->dev->ifindex;

	xfrmn = net_generic(xs_net(xfrm_input_state(skb)), xfrmi_net_id);

	for_each_xfrmi_rcu(xfrmn->xfrmi[0], xi) {
		if (ifindex == xi->dev->ifindex &&
			(xi->dev->flags & IFF_UP))
+1 −1
Original line number Diff line number Diff line
@@ -3313,7 +3313,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
	ifcb = xfrm_if_get_cb();

	if (ifcb) {
		xi = ifcb->decode_session(skb);
		xi = ifcb->decode_session(skb, family);
		if (xi) {
			if_id = xi->p.if_id;
			net = xi->net;