Commit 578f3932 authored by David S. Miller's avatar David S. Miller
Browse files

ipsec

Steffen Klassert says:

====================
pull request (net): ipsec 2021-10-07

1) Fix a sysbot reported shift-out-of-bounds in xfrm_get_default.
   From Pavel Skripkin.

2) Fix XFRM_MSG_MAPPING ABI breakage. The new XFRM_MSG_MAPPING
   messages were accidentally not paced at the end.
   Fix by Eugene Syromiatnikov.

3) Fix the uapi for the default policy, use explicit field and macros
   and make it accessible to userland.
   From Nicolas Dichtel.

4) Fix a missing rcu lock in xfrm_notify_userpolicy().
   From Nicolas Dichtel.

Please pull or let me know if there are problems.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 65f280bb 93ec1320
Loading
Loading
Loading
Loading
+9 −6
Original line number Diff line number Diff line
@@ -213,13 +213,13 @@ enum {
	XFRM_MSG_GETSPDINFO,
#define XFRM_MSG_GETSPDINFO XFRM_MSG_GETSPDINFO

	XFRM_MSG_MAPPING,
#define XFRM_MSG_MAPPING XFRM_MSG_MAPPING

	XFRM_MSG_SETDEFAULT,
#define XFRM_MSG_SETDEFAULT XFRM_MSG_SETDEFAULT
	XFRM_MSG_GETDEFAULT,
#define XFRM_MSG_GETDEFAULT XFRM_MSG_GETDEFAULT

	XFRM_MSG_MAPPING,
#define XFRM_MSG_MAPPING XFRM_MSG_MAPPING
	__XFRM_MSG_MAX
};
#define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1)
@@ -514,9 +514,12 @@ struct xfrm_user_offload {
#define XFRM_OFFLOAD_INBOUND	2

struct xfrm_userpolicy_default {
#define XFRM_USERPOLICY_DIRMASK_MAX	(sizeof(__u8) * 8)
	__u8				dirmask;
	__u8				action;
#define XFRM_USERPOLICY_UNSPEC	0
#define XFRM_USERPOLICY_BLOCK	1
#define XFRM_USERPOLICY_ACCEPT	2
	__u8				in;
	__u8				fwd;
	__u8				out;
};

#ifndef __KERNEL__
+55 −12
Original line number Diff line number Diff line
@@ -1961,24 +1961,65 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb,
	return skb;
}

static int xfrm_notify_userpolicy(struct net *net)
{
	struct xfrm_userpolicy_default *up;
	int len = NLMSG_ALIGN(sizeof(*up));
	struct nlmsghdr *nlh;
	struct sk_buff *skb;
	int err;

	skb = nlmsg_new(len, GFP_ATOMIC);
	if (skb == NULL)
		return -ENOMEM;

	nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_GETDEFAULT, sizeof(*up), 0);
	if (nlh == NULL) {
		kfree_skb(skb);
		return -EMSGSIZE;
	}

	up = nlmsg_data(nlh);
	up->in = net->xfrm.policy_default & XFRM_POL_DEFAULT_IN ?
			XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT;
	up->fwd = net->xfrm.policy_default & XFRM_POL_DEFAULT_FWD ?
			XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT;
	up->out = net->xfrm.policy_default & XFRM_POL_DEFAULT_OUT ?
			XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT;

	nlmsg_end(skb, nlh);

	rcu_read_lock();
	err = xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_POLICY);
	rcu_read_unlock();

	return err;
}

static int xfrm_set_default(struct sk_buff *skb, struct nlmsghdr *nlh,
			    struct nlattr **attrs)
{
	struct net *net = sock_net(skb->sk);
	struct xfrm_userpolicy_default *up = nlmsg_data(nlh);
	u8 dirmask;
	u8 old_default = net->xfrm.policy_default;

	if (up->dirmask >= XFRM_USERPOLICY_DIRMASK_MAX)
		return -EINVAL;
	if (up->in == XFRM_USERPOLICY_BLOCK)
		net->xfrm.policy_default |= XFRM_POL_DEFAULT_IN;
	else if (up->in == XFRM_USERPOLICY_ACCEPT)
		net->xfrm.policy_default &= ~XFRM_POL_DEFAULT_IN;

	dirmask = (1 << up->dirmask) & XFRM_POL_DEFAULT_MASK;
	if (up->fwd == XFRM_USERPOLICY_BLOCK)
		net->xfrm.policy_default |= XFRM_POL_DEFAULT_FWD;
	else if (up->fwd == XFRM_USERPOLICY_ACCEPT)
		net->xfrm.policy_default &= ~XFRM_POL_DEFAULT_FWD;

	net->xfrm.policy_default = (old_default & (0xff ^ dirmask))
				    | (up->action << up->dirmask);
	if (up->out == XFRM_USERPOLICY_BLOCK)
		net->xfrm.policy_default |= XFRM_POL_DEFAULT_OUT;
	else if (up->out == XFRM_USERPOLICY_ACCEPT)
		net->xfrm.policy_default &= ~XFRM_POL_DEFAULT_OUT;

	rt_genid_bump_all(net);

	xfrm_notify_userpolicy(net);
	return 0;
}

@@ -1988,13 +2029,11 @@ static int xfrm_get_default(struct sk_buff *skb, struct nlmsghdr *nlh,
	struct sk_buff *r_skb;
	struct nlmsghdr *r_nlh;
	struct net *net = sock_net(skb->sk);
	struct xfrm_userpolicy_default *r_up, *up;
	struct xfrm_userpolicy_default *r_up;
	int len = NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_default));
	u32 portid = NETLINK_CB(skb).portid;
	u32 seq = nlh->nlmsg_seq;

	up = nlmsg_data(nlh);

	r_skb = nlmsg_new(len, GFP_ATOMIC);
	if (!r_skb)
		return -ENOMEM;
@@ -2007,8 +2046,12 @@ static int xfrm_get_default(struct sk_buff *skb, struct nlmsghdr *nlh,

	r_up = nlmsg_data(r_nlh);

	r_up->action = ((net->xfrm.policy_default & (1 << up->dirmask)) >> up->dirmask);
	r_up->dirmask = up->dirmask;
	r_up->in = net->xfrm.policy_default & XFRM_POL_DEFAULT_IN ?
			XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT;
	r_up->fwd = net->xfrm.policy_default & XFRM_POL_DEFAULT_FWD ?
			XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT;
	r_up->out = net->xfrm.policy_default & XFRM_POL_DEFAULT_OUT ?
			XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT;
	nlmsg_end(r_skb, r_nlh);

	return nlmsg_unicast(net->xfrm.nlsk, r_skb, portid);
+3 −1
Original line number Diff line number Diff line
@@ -126,6 +126,8 @@ static const struct nlmsg_perm nlmsg_xfrm_perms[] =
	{ XFRM_MSG_NEWSPDINFO,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
	{ XFRM_MSG_GETSPDINFO,	NETLINK_XFRM_SOCKET__NLMSG_READ  },
	{ XFRM_MSG_MAPPING,	NETLINK_XFRM_SOCKET__NLMSG_READ  },
	{ XFRM_MSG_SETDEFAULT,	NETLINK_XFRM_SOCKET__NLMSG_WRITE },
	{ XFRM_MSG_GETDEFAULT,	NETLINK_XFRM_SOCKET__NLMSG_READ  },
};

static const struct nlmsg_perm nlmsg_audit_perms[] =
@@ -189,7 +191,7 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm)
		 * structures at the top of this file with the new mappings
		 * before updating the BUILD_BUG_ON() macro!
		 */
		BUILD_BUG_ON(XFRM_MSG_MAX != XFRM_MSG_MAPPING);
		BUILD_BUG_ON(XFRM_MSG_MAX != XFRM_MSG_GETDEFAULT);
		err = nlmsg_perm(nlmsg_type, perm, nlmsg_xfrm_perms,
				 sizeof(nlmsg_xfrm_perms));
		break;