[KEY]: Fix conversion between IPSEC_MODE_xxx and XFRM_MODE_xxx.
authorKazunori MIYAZAWA <miyazawa@linux-ipv6.org>
Tue, 17 Apr 2007 19:32:20 +0000 (12:32 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Tue, 17 Apr 2007 20:13:21 +0000 (13:13 -0700)
We should not blindly convert between IPSEC_MODE_xxx and XFRM_MODE_xxx just
by incrementing / decrementing because the assumption is not true any longer.

Signed-off-by: Kazunori MIYAZAWA <miyazawa@linux-ipv6.org>
Singed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
net/key/af_key.c

index a4e7e2d..cf77930 100644 (file)
@@ -630,6 +630,35 @@ pfkey_sockaddr_size(sa_family_t family)
        /* NOTREACHED */
 }
 
+static inline int pfkey_mode_from_xfrm(int mode)
+{
+       switch(mode) {
+       case XFRM_MODE_TRANSPORT:
+               return IPSEC_MODE_TRANSPORT;
+       case XFRM_MODE_TUNNEL:
+               return IPSEC_MODE_TUNNEL;
+       case XFRM_MODE_BEET:
+               return IPSEC_MODE_BEET;
+       default:
+               return -1;
+       }
+}
+
+static inline int pfkey_mode_to_xfrm(int mode)
+{
+       switch(mode) {
+       case IPSEC_MODE_ANY:    /*XXX*/
+       case IPSEC_MODE_TRANSPORT:
+               return XFRM_MODE_TRANSPORT;
+       case IPSEC_MODE_TUNNEL:
+               return XFRM_MODE_TUNNEL;
+       case IPSEC_MODE_BEET:
+               return XFRM_MODE_BEET;
+       default:
+               return -1;
+       }
+}
+
 static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, int hsc)
 {
        struct sk_buff *skb;
@@ -651,6 +680,7 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys,
        int encrypt_key_size = 0;
        int sockaddr_size;
        struct xfrm_encap_tmpl *natt = NULL;
+       int mode;
 
        /* address family check */
        sockaddr_size = pfkey_sockaddr_size(x->props.family);
@@ -928,7 +958,11 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys,
        sa2 = (struct sadb_x_sa2 *)  skb_put(skb, sizeof(struct sadb_x_sa2));
        sa2->sadb_x_sa2_len = sizeof(struct sadb_x_sa2)/sizeof(uint64_t);
        sa2->sadb_x_sa2_exttype = SADB_X_EXT_SA2;
-       sa2->sadb_x_sa2_mode = x->props.mode + 1;
+       if ((mode = pfkey_mode_from_xfrm(x->props.mode)) < 0) {
+               kfree_skb(skb);
+               return ERR_PTR(-EINVAL);
+       }
+       sa2->sadb_x_sa2_mode = mode;
        sa2->sadb_x_sa2_reserved1 = 0;
        sa2->sadb_x_sa2_reserved2 = 0;
        sa2->sadb_x_sa2_sequence = 0;
@@ -1155,9 +1189,12 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr,
 
        if (ext_hdrs[SADB_X_EXT_SA2-1]) {
                struct sadb_x_sa2 *sa2 = (void*)ext_hdrs[SADB_X_EXT_SA2-1];
-               x->props.mode = sa2->sadb_x_sa2_mode;
-               if (x->props.mode)
-                       x->props.mode--;
+               int mode = pfkey_mode_to_xfrm(sa2->sadb_x_sa2_mode);
+               if (mode < 0) {
+                       err = -EINVAL;
+                       goto out;
+               }
+               x->props.mode = mode;
                x->props.reqid = sa2->sadb_x_sa2_reqid;
        }
 
@@ -1218,7 +1255,7 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
        struct sadb_address *saddr, *daddr;
        struct sadb_msg *out_hdr;
        struct xfrm_state *x = NULL;
-       u8 mode;
+       int mode;
        u32 reqid;
        u8 proto;
        unsigned short family;
@@ -1233,7 +1270,9 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
                return -EINVAL;
 
        if ((sa2 = ext_hdrs[SADB_X_EXT_SA2-1]) != NULL) {
-               mode = sa2->sadb_x_sa2_mode - 1;
+               mode = pfkey_mode_to_xfrm(sa2->sadb_x_sa2_mode);
+               if (mode < 0)
+                       return -EINVAL;
                reqid = sa2->sadb_x_sa2_reqid;
        } else {
                mode = 0;
@@ -1756,6 +1795,7 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
        struct sockaddr_in6 *sin6;
 #endif
+       int mode;
 
        if (xp->xfrm_nr >= XFRM_MAX_DEPTH)
                return -ELOOP;
@@ -1764,7 +1804,9 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
                return -EINVAL;
 
        t->id.proto = rq->sadb_x_ipsecrequest_proto; /* XXX check proto */
-       t->mode = rq->sadb_x_ipsecrequest_mode-1;
+       if ((mode = pfkey_mode_to_xfrm(rq->sadb_x_ipsecrequest_mode)) < 0)
+               return -EINVAL;
+       t->mode = mode;
        if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_USE)
                t->optional = 1;
        else if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_UNIQUE) {
@@ -1877,7 +1919,7 @@ static struct sk_buff * pfkey_xfrm_policy2msg_prep(struct xfrm_policy *xp)
        return skb;
 }
 
-static void pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, int dir)
+static int pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, int dir)
 {
        struct sadb_msg *hdr;
        struct sadb_address *addr;
@@ -2014,6 +2056,7 @@ static void pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, i
                struct sadb_x_ipsecrequest *rq;
                struct xfrm_tmpl *t = xp->xfrm_vec + i;
                int req_size;
+               int mode;
 
                req_size = sizeof(struct sadb_x_ipsecrequest);
                if (t->mode == XFRM_MODE_TUNNEL)
@@ -2027,7 +2070,9 @@ static void pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, i
                memset(rq, 0, sizeof(*rq));
                rq->sadb_x_ipsecrequest_len = req_size;
                rq->sadb_x_ipsecrequest_proto = t->id.proto;
-               rq->sadb_x_ipsecrequest_mode = t->mode+1;
+               if ((mode = pfkey_mode_from_xfrm(t->mode)) < 0)
+                       return -EINVAL;
+               mode = pfkey_mode_from_xfrm(t->mode);
                rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_REQUIRE;
                if (t->reqid)
                        rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_UNIQUE;
@@ -2089,6 +2134,8 @@ static void pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, i
 
        hdr->sadb_msg_len = size / sizeof(uint64_t);
        hdr->sadb_msg_reserved = atomic_read(&xp->refcnt);
+
+       return 0;
 }
 
 static int key_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c)
@@ -2102,7 +2149,9 @@ static int key_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c
                err = PTR_ERR(out_skb);
                goto out;
        }
-       pfkey_xfrm_policy2msg(out_skb, xp, dir);
+       err = pfkey_xfrm_policy2msg(out_skb, xp, dir);
+       if (err < 0)
+               return err;
 
        out_hdr = (struct sadb_msg *) out_skb->data;
        out_hdr->sadb_msg_version = PF_KEY_V2;
@@ -2327,7 +2376,9 @@ static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, struct sadb
                err =  PTR_ERR(out_skb);
                goto out;
        }
-       pfkey_xfrm_policy2msg(out_skb, xp, dir);
+       err = pfkey_xfrm_policy2msg(out_skb, xp, dir);
+       if (err < 0)
+               goto out;
 
        out_hdr = (struct sadb_msg *) out_skb->data;
        out_hdr->sadb_msg_version = hdr->sadb_msg_version;
@@ -2409,6 +2460,7 @@ static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len,
 {
        int err;
        struct sadb_x_ipsecrequest *rq2;
+       int mode;
 
        if (len <= sizeof(struct sadb_x_ipsecrequest) ||
            len < rq1->sadb_x_ipsecrequest_len)
@@ -2439,7 +2491,9 @@ static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len,
                return -EINVAL;
 
        m->proto = rq1->sadb_x_ipsecrequest_proto;
-       m->mode = rq1->sadb_x_ipsecrequest_mode - 1;
+       if ((mode = pfkey_mode_to_xfrm(rq1->sadb_x_ipsecrequest_mode)) < 0)
+               return -EINVAL;
+       m->mode = mode;
        m->reqid = rq1->sadb_x_ipsecrequest_reqid;
 
        return ((int)(rq1->sadb_x_ipsecrequest_len +
@@ -2579,12 +2633,15 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr)
        struct pfkey_dump_data *data = ptr;
        struct sk_buff *out_skb;
        struct sadb_msg *out_hdr;
+       int err;
 
        out_skb = pfkey_xfrm_policy2msg_prep(xp);
        if (IS_ERR(out_skb))
                return PTR_ERR(out_skb);
 
-       pfkey_xfrm_policy2msg(out_skb, xp, dir);
+       err = pfkey_xfrm_policy2msg(out_skb, xp, dir);
+       if (err < 0)
+               return err;
 
        out_hdr = (struct sadb_msg *) out_skb->data;
        out_hdr->sadb_msg_version = data->hdr->sadb_msg_version;
@@ -3513,7 +3570,10 @@ static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
 
        for (i = 0, mp = m; i < num_bundles; i++, mp++) {
                /* old ipsecrequest */
-               if (set_ipsecrequest(skb, mp->proto, mp->mode + 1,
+               int mode = pfkey_mode_from_xfrm(mp->mode);
+               if (mode < 0)
+                       return -EINVAL;
+               if (set_ipsecrequest(skb, mp->proto, mode,
                                     (mp->reqid ?  IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE),
                                     mp->reqid, mp->old_family,
                                     &mp->old_saddr, &mp->old_daddr) < 0) {
@@ -3521,7 +3581,7 @@ static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
                }
 
                /* new ipsecrequest */
-               if (set_ipsecrequest(skb, mp->proto, mp->mode + 1,
+               if (set_ipsecrequest(skb, mp->proto, mode,
                                     (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE),
                                     mp->reqid, mp->new_family,
                                     &mp->new_saddr, &mp->new_daddr) < 0) {