Commit f8d858e6 authored by Nicolas Dichtel's avatar Nicolas Dichtel Committed by Steffen Klassert
Browse files

xfrm: make user policy API complete



>From a userland POV, this API was based on some magic values:
 - dirmask and action were bitfields but meaning of bits
   (XFRM_POL_DEFAULT_*) are not exported;
 - action is confusing, if a bit is set, does it mean drop or accept?

Let's try to simplify this uapi by using explicit field and macros.

Fixes: 2d151d39 ("xfrm: Add possibility to set the default to block if we have no policy")
Signed-off-by: default avatarNicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent 844f7eaa
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__
+19 −17
Original line number Diff line number Diff line
@@ -1966,16 +1966,21 @@ static int xfrm_set_default(struct sk_buff *skb, struct nlmsghdr *nlh,
{
	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);

@@ -1988,13 +1993,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 +2008,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);