xfrm: make user policy API complete
authorNicolas Dichtel <nicolas.dichtel@6wind.com>
Tue, 14 Sep 2021 14:46:33 +0000 (16:46 +0200)
committerSteffen Klassert <steffen.klassert@secunet.com>
Wed, 15 Sep 2021 11:41:36 +0000 (13:41 +0200)
>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: 2d151d39073a ("xfrm: Add possibility to set the default to block if we have no policy")
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
include/uapi/linux/xfrm.h
net/xfrm/xfrm_user.c

index 26f456b..eda0426 100644 (file)
@@ -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__
index 4719a6d..90c8839 100644 (file)
@@ -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);