Commit 047a749d authored by Steffen Klassert's avatar Steffen Klassert
Browse files

Merge branch 'xfrm: fix uapi for the default policy'



Nicolas Dichtel says:

====================
This feature has just been merged after the last release, thus it's still
time to fix the uapi.
As stated in the thread, the uapi is based on some magic values (from the
userland POV).
Here is a proposal to simplify this uapi and make it clear how to use it.
The other problem was the notification: changing the default policy may
radically change the packets flows.

v2 -> v3: rebase on top of ipsec tree

v1 -> v2: fix warnings reported by the kernel test robot
====================

Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parents 844f7eaa 88d0adb5
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -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__
+50 −17
Original line number Diff line number Diff line
@@ -1961,24 +1961,60 @@ 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;

	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);

	return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_POLICY);
}

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 +2024,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;
@@ -2005,15 +2039,14 @@ static int xfrm_get_default(struct sk_buff *skb, struct nlmsghdr *nlh,
		return -EMSGSIZE;
	}

	if (up->dirmask >= XFRM_USERPOLICY_DIRMASK_MAX) {
		kfree_skb(r_skb);
		return -EINVAL;
	}

	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);