Skip to content

Commit

Permalink
Merge branch 'xfrm: fix uapi for the default policy'
Browse files Browse the repository at this point in the history
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: Steffen Klassert <steffen.klassert@secunet.com>
  • Loading branch information
klassert committed Sep 17, 2021
2 parents 844f7ea + 88d0adb commit 047a749
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 20 deletions.
9 changes: 6 additions & 3 deletions include/uapi/linux/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__
Expand Down
67 changes: 50 additions & 17 deletions net/xfrm/xfrm_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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;
Expand All @@ -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);
Expand Down

0 comments on commit 047a749

Please sign in to comment.