Commit 6ad85ed0 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files
Steffen Klassert says:

====================
pull request (net): ipsec 2023-05-16

1) Don't check the policy default if we have an allow
   policy. Fix from Sabrina Dubroca.

2) Fix netdevice refount usage on offload.
   From Leon Romanovsky.

3) Use netdev_put instead of dev_puti to correctly release
   the netdev on failure in xfrm_dev_policy_add.
   From Leon Romanovsky.

4) Revert "Fix XFRM-I support for nested ESP tunnels"
   This broke Netfilter policy matching.
   From Martin Willi.

5) Reject optional tunnel/BEET mode templates in outbound policies
   on netlink and pfkey sockets. From Tobias Brunner.

6) Check if_id in inbound policy/secpath match to make
   it symetric to the outbound codepath.
   From Benedict Wong.

* tag 'ipsec-2023-05-16' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec:
  xfrm: Check if_id in inbound policy/secpath match
  af_key: Reject optional tunnel/BEET mode templates in outbound policies
  xfrm: Reject optional tunnel/BEET mode templates in outbound policies
  Revert "Fix XFRM-I support for nested ESP tunnels"
  xfrm: Fix leak of dev tracker
  xfrm: release all offloaded policy memory
  xfrm: don't check the default policy if the policy allows the packet
====================

Link: https://lore.kernel.org/r/20230516052405.2677554-1-steffen.klassert@secunet.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 47d55c62 8680407b
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -1940,7 +1940,8 @@ static u32 gen_reqid(struct net *net)
}

static int
parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_policy *pol,
		   struct sadb_x_ipsecrequest *rq)
{
	struct net *net = xp_net(xp);
	struct xfrm_tmpl *t = xp->xfrm_vec + xp->xfrm_nr;
@@ -1958,9 +1959,12 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
	if ((mode = pfkey_mode_to_xfrm(rq->sadb_x_ipsecrequest_mode)) < 0)
		return -EINVAL;
	t->mode = mode;
	if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_USE)
	if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_USE) {
		if ((mode == XFRM_MODE_TUNNEL || mode == XFRM_MODE_BEET) &&
		    pol->sadb_x_policy_dir == IPSEC_DIR_OUTBOUND)
			return -EINVAL;
		t->optional = 1;
	else if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_UNIQUE) {
	} else if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_UNIQUE) {
		t->reqid = rq->sadb_x_ipsecrequest_reqid;
		if (t->reqid > IPSEC_MANUAL_REQID_MAX)
			t->reqid = 0;
@@ -2002,7 +2006,7 @@ parse_ipsecrequests(struct xfrm_policy *xp, struct sadb_x_policy *pol)
		    rq->sadb_x_ipsecrequest_len < sizeof(*rq))
			return -EINVAL;

		if ((err = parse_ipsecrequest(xp, rq)) < 0)
		if ((err = parse_ipsecrequest(xp, pol, rq)) < 0)
			return err;
		len -= rq->sadb_x_ipsecrequest_len;
		rq = (void*)((u8*)rq + rq->sadb_x_ipsecrequest_len);
+1 −1
Original line number Diff line number Diff line
@@ -378,7 +378,7 @@ int xfrm_dev_policy_add(struct net *net, struct xfrm_policy *xp,
		break;
	default:
		xdo->dev = NULL;
		dev_put(dev);
		netdev_put(dev, &xdo->dev_tracker);
		NL_SET_ERR_MSG(extack, "Unrecognized offload direction");
		return -EINVAL;
	}
+4 −50
Original line number Diff line number Diff line
@@ -310,52 +310,6 @@ static void xfrmi_scrub_packet(struct sk_buff *skb, bool xnet)
	skb->mark = 0;
}

static int xfrmi_input(struct sk_buff *skb, int nexthdr, __be32 spi,
		       int encap_type, unsigned short family)
{
	struct sec_path *sp;

	sp = skb_sec_path(skb);
	if (sp && (sp->len || sp->olen) &&
	    !xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family))
		goto discard;

	XFRM_SPI_SKB_CB(skb)->family = family;
	if (family == AF_INET) {
		XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
		XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
	} else {
		XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr);
		XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
	}

	return xfrm_input(skb, nexthdr, spi, encap_type);
discard:
	kfree_skb(skb);
	return 0;
}

static int xfrmi4_rcv(struct sk_buff *skb)
{
	return xfrmi_input(skb, ip_hdr(skb)->protocol, 0, 0, AF_INET);
}

static int xfrmi6_rcv(struct sk_buff *skb)
{
	return xfrmi_input(skb, skb_network_header(skb)[IP6CB(skb)->nhoff],
			   0, 0, AF_INET6);
}

static int xfrmi4_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
{
	return xfrmi_input(skb, nexthdr, spi, encap_type, AF_INET);
}

static int xfrmi6_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
{
	return xfrmi_input(skb, nexthdr, spi, encap_type, AF_INET6);
}

static int xfrmi_rcv_cb(struct sk_buff *skb, int err)
{
	const struct xfrm_mode *inner_mode;
@@ -991,8 +945,8 @@ static struct pernet_operations xfrmi_net_ops = {
};

static struct xfrm6_protocol xfrmi_esp6_protocol __read_mostly = {
	.handler	=	xfrmi6_rcv,
	.input_handler	=	xfrmi6_input,
	.handler	=	xfrm6_rcv,
	.input_handler	=	xfrm_input,
	.cb_handler	=	xfrmi_rcv_cb,
	.err_handler	=	xfrmi6_err,
	.priority	=	10,
@@ -1042,8 +996,8 @@ static struct xfrm6_tunnel xfrmi_ip6ip_handler __read_mostly = {
#endif

static struct xfrm4_protocol xfrmi_esp4_protocol __read_mostly = {
	.handler	=	xfrmi4_rcv,
	.input_handler	=	xfrmi4_input,
	.handler	=	xfrm4_rcv,
	.input_handler	=	xfrm_input,
	.cb_handler	=	xfrmi_rcv_cb,
	.err_handler	=	xfrmi4_err,
	.priority	=	10,
+6 −14
Original line number Diff line number Diff line
@@ -3312,7 +3312,7 @@ xfrm_secpath_reject(int idx, struct sk_buff *skb, const struct flowi *fl)

static inline int
xfrm_state_ok(const struct xfrm_tmpl *tmpl, const struct xfrm_state *x,
	      unsigned short family)
	      unsigned short family, u32 if_id)
{
	if (xfrm_state_kern(x))
		return tmpl->optional && !xfrm_state_addr_cmp(tmpl, x, tmpl->encap_family);
@@ -3323,7 +3323,8 @@ xfrm_state_ok(const struct xfrm_tmpl *tmpl, const struct xfrm_state *x,
		(tmpl->allalgs || (tmpl->aalgos & (1<<x->props.aalgo)) ||
		 !(xfrm_id_proto_match(tmpl->id.proto, IPSEC_PROTO_ANY))) &&
		!(x->props.mode != XFRM_MODE_TRANSPORT &&
		  xfrm_state_addr_cmp(tmpl, x, family));
		  xfrm_state_addr_cmp(tmpl, x, family)) &&
		(if_id == 0 || if_id == x->if_id);
}

/*
@@ -3335,7 +3336,7 @@ xfrm_state_ok(const struct xfrm_tmpl *tmpl, const struct xfrm_state *x,
 */
static inline int
xfrm_policy_ok(const struct xfrm_tmpl *tmpl, const struct sec_path *sp, int start,
	       unsigned short family)
	       unsigned short family, u32 if_id)
{
	int idx = start;

@@ -3345,7 +3346,7 @@ xfrm_policy_ok(const struct xfrm_tmpl *tmpl, const struct sec_path *sp, int star
	} else
		start = -1;
	for (; idx < sp->len; idx++) {
		if (xfrm_state_ok(tmpl, sp->xvec[idx], family))
		if (xfrm_state_ok(tmpl, sp->xvec[idx], family, if_id))
			return ++idx;
		if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) {
			if (start == -1)
@@ -3712,12 +3713,6 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
		}
		xfrm_nr = ti;

		if (net->xfrm.policy_default[dir] == XFRM_USERPOLICY_BLOCK &&
		    !xfrm_nr) {
			XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
			goto reject;
		}

		if (npols > 1) {
			xfrm_tmpl_sort(stp, tpp, xfrm_nr, family);
			tpp = stp;
@@ -3730,7 +3725,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
		 * are implied between each two transformations.
		 */
		for (i = xfrm_nr-1, k = 0; i >= 0; i--) {
			k = xfrm_policy_ok(tpp[i], sp, k, family);
			k = xfrm_policy_ok(tpp[i], sp, k, family, if_id);
			if (k < 0) {
				if (k < -1)
					/* "-2 - errored_index" returned */
@@ -3745,9 +3740,6 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
			goto reject;
		}

		if (if_id)
			secpath_reset(skb);

		xfrm_pols_put(pols, npols);
		return 1;
	}
+10 −5
Original line number Diff line number Diff line
@@ -1770,7 +1770,7 @@ static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut,
}

static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family,
			 struct netlink_ext_ack *extack)
			 int dir, struct netlink_ext_ack *extack)
{
	u16 prev_family;
	int i;
@@ -1796,6 +1796,10 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family,
		switch (ut[i].mode) {
		case XFRM_MODE_TUNNEL:
		case XFRM_MODE_BEET:
			if (ut[i].optional && dir == XFRM_POLICY_OUT) {
				NL_SET_ERR_MSG(extack, "Mode in optional template not allowed in outbound policy");
				return -EINVAL;
			}
			break;
		default:
			if (ut[i].family != prev_family) {
@@ -1833,7 +1837,7 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family,
}

static int copy_from_user_tmpl(struct xfrm_policy *pol, struct nlattr **attrs,
			       struct netlink_ext_ack *extack)
			       int dir, struct netlink_ext_ack *extack)
{
	struct nlattr *rt = attrs[XFRMA_TMPL];

@@ -1844,7 +1848,7 @@ static int copy_from_user_tmpl(struct xfrm_policy *pol, struct nlattr **attrs,
		int nr = nla_len(rt) / sizeof(*utmpl);
		int err;

		err = validate_tmpl(nr, utmpl, pol->family, extack);
		err = validate_tmpl(nr, utmpl, pol->family, dir, extack);
		if (err)
			return err;

@@ -1921,7 +1925,7 @@ static struct xfrm_policy *xfrm_policy_construct(struct net *net,
	if (err)
		goto error;

	if (!(err = copy_from_user_tmpl(xp, attrs, extack)))
	if (!(err = copy_from_user_tmpl(xp, attrs, p->dir, extack)))
		err = copy_from_user_sec_ctx(xp, attrs);
	if (err)
		goto error;
@@ -1980,6 +1984,7 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh,

	if (err) {
		xfrm_dev_policy_delete(xp);
		xfrm_dev_policy_free(xp);
		security_xfrm_policy_free(xp->security);
		kfree(xp);
		return err;
@@ -3499,7 +3504,7 @@ static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt,
		return NULL;

	nr = ((len - sizeof(*p)) / sizeof(*ut));
	if (validate_tmpl(nr, ut, p->sel.family, NULL))
	if (validate_tmpl(nr, ut, p->sel.family, p->dir, NULL))
		return NULL;

	if (p->dir > XFRM_POLICY_OUT)