xfrm: Try to honor policy index if it's supplied by user
authorFan Du <fan.du@windriver.com>
Thu, 7 Nov 2013 09:47:48 +0000 (17:47 +0800)
committerSteffen Klassert <steffen.klassert@secunet.com>
Fri, 6 Dec 2013 05:45:05 +0000 (06:45 +0100)
xfrm code always searches for unused policy index for
newly created policy regardless whether or not user
space policy index hint supplied.

This patch enables such feature so that using
"ip xfrm ... index=xxx" can be used by user to set
specific policy index.

Currently this beahvior is broken, so this patch make
it happen as expected.

Signed-off-by: Fan Du <fan.du@windriver.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_user.c

index 9a91f7431c411b706810a40bccc3167617c74aec..a5bbdfb2874bef04252da37906337b64fa867276 100644 (file)
@@ -538,7 +538,7 @@ static void xfrm_hash_resize(struct work_struct *work)
 
 /* Generate new index... KAME seems to generate them ordered by cost
  * of an absolute inpredictability of ordering of rules. This will not pass. */
-static u32 xfrm_gen_index(struct net *net, int dir)
+static u32 xfrm_gen_index(struct net *net, int dir, u32 index)
 {
        static u32 idx_generator;
 
@@ -548,8 +548,14 @@ static u32 xfrm_gen_index(struct net *net, int dir)
                u32 idx;
                int found;
 
-               idx = (idx_generator | dir);
-               idx_generator += 8;
+               if (!index) {
+                       idx = (idx_generator | dir);
+                       idx_generator += 8;
+               } else {
+                       idx = index;
+                       index = 0;
+               }
+
                if (idx == 0)
                        idx = 8;
                list = net->xfrm.policy_byidx + idx_hash(net, idx);
@@ -672,7 +678,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
                xfrm_policy_requeue(delpol, policy);
                __xfrm_policy_unlink(delpol, dir);
        }
-       policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir);
+       policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir, policy->index);
        hlist_add_head(&policy->byidx, net->xfrm.policy_byidx+idx_hash(net, policy->index));
        policy->curlft.add_time = get_seconds();
        policy->curlft.use_time = 0;
@@ -1192,7 +1198,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
        sk->sk_policy[dir] = pol;
        if (pol) {
                pol->curlft.add_time = get_seconds();
-               pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir);
+               pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0);
                __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir);
        }
        if (old_pol) {
index f964d4c00ffb53457aa46b24f0225249c1d46b7c..4e0546e9bb0a04c8ec90b14ef70812692662646e 100644 (file)
@@ -1189,6 +1189,8 @@ static int verify_policy_type(u8 type)
 
 static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
 {
+       int ret;
+
        switch (p->share) {
        case XFRM_SHARE_ANY:
        case XFRM_SHARE_SESSION:
@@ -1224,7 +1226,13 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
                return -EINVAL;
        }
 
-       return verify_policy_dir(p->dir);
+       ret = verify_policy_dir(p->dir);
+       if (ret)
+               return ret;
+       if (p->index && ((p->index & XFRM_POLICY_MAX) != p->dir))
+               return -EINVAL;
+
+       return 0;
 }
 
 static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs)