OSDN Git Service

Merge android-4.4.187 (8eb3d65) into msm-4.4
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / net / key / af_key.c
index 15150b4..0b14707 100644 (file)
@@ -196,30 +196,22 @@ static int pfkey_release(struct socket *sock)
        return 0;
 }
 
-static int pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2,
-                              gfp_t allocation, struct sock *sk)
+static int pfkey_broadcast_one(struct sk_buff *skb, gfp_t allocation,
+                              struct sock *sk)
 {
        int err = -ENOBUFS;
 
-       sock_hold(sk);
-       if (*skb2 == NULL) {
-               if (atomic_read(&skb->users) != 1) {
-                       *skb2 = skb_clone(skb, allocation);
-               } else {
-                       *skb2 = skb;
-                       atomic_inc(&skb->users);
-               }
-       }
-       if (*skb2 != NULL) {
-               if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) {
-                       skb_set_owner_r(*skb2, sk);
-                       skb_queue_tail(&sk->sk_receive_queue, *skb2);
-                       sk->sk_data_ready(sk);
-                       *skb2 = NULL;
-                       err = 0;
-               }
+       if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf)
+               return err;
+
+       skb = skb_clone(skb, allocation);
+
+       if (skb) {
+               skb_set_owner_r(skb, sk);
+               skb_queue_tail(&sk->sk_receive_queue, skb);
+               sk->sk_data_ready(sk);
+               err = 0;
        }
-       sock_put(sk);
        return err;
 }
 
@@ -234,7 +226,6 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
 {
        struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
        struct sock *sk;
-       struct sk_buff *skb2 = NULL;
        int err = -ESRCH;
 
        /* XXX Do we need something like netlink_overrun?  I think
@@ -253,7 +244,7 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
                 * socket.
                 */
                if (pfk->promisc)
-                       pfkey_broadcast_one(skb, &skb2, GFP_ATOMIC, sk);
+                       pfkey_broadcast_one(skb, GFP_ATOMIC, sk);
 
                /* the exact target will be processed later */
                if (sk == one_sk)
@@ -268,7 +259,7 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
                                continue;
                }
 
-               err2 = pfkey_broadcast_one(skb, &skb2, GFP_ATOMIC, sk);
+               err2 = pfkey_broadcast_one(skb, GFP_ATOMIC, sk);
 
                /* Error is cleared after successful sending to at least one
                 * registered KM */
@@ -278,9 +269,8 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
        rcu_read_unlock();
 
        if (one_sk != NULL)
-               err = pfkey_broadcast_one(skb, &skb2, allocation, one_sk);
+               err = pfkey_broadcast_one(skb, allocation, one_sk);
 
-       kfree_skb(skb2);
        kfree_skb(skb);
        return err;
 }
@@ -437,6 +427,24 @@ static int verify_address_len(const void *p)
        return 0;
 }
 
+static inline int sadb_key_len(const struct sadb_key *key)
+{
+       int key_bytes = DIV_ROUND_UP(key->sadb_key_bits, 8);
+
+       return DIV_ROUND_UP(sizeof(struct sadb_key) + key_bytes,
+                           sizeof(uint64_t));
+}
+
+static int verify_key_len(const void *p)
+{
+       const struct sadb_key *key = p;
+
+       if (sadb_key_len(key) > key->sadb_key_len)
+               return -EINVAL;
+
+       return 0;
+}
+
 static inline int pfkey_sec_ctx_len(const struct sadb_x_sec_ctx *sec_ctx)
 {
        return DIV_ROUND_UP(sizeof(struct sadb_x_sec_ctx) +
@@ -533,16 +541,25 @@ static int parse_exthdrs(struct sk_buff *skb, const struct sadb_msg *hdr, void *
                                return -EINVAL;
                        if (ext_hdrs[ext_type-1] != NULL)
                                return -EINVAL;
-                       if (ext_type == SADB_EXT_ADDRESS_SRC ||
-                           ext_type == SADB_EXT_ADDRESS_DST ||
-                           ext_type == SADB_EXT_ADDRESS_PROXY ||
-                           ext_type == SADB_X_EXT_NAT_T_OA) {
+                       switch (ext_type) {
+                       case SADB_EXT_ADDRESS_SRC:
+                       case SADB_EXT_ADDRESS_DST:
+                       case SADB_EXT_ADDRESS_PROXY:
+                       case SADB_X_EXT_NAT_T_OA:
                                if (verify_address_len(p))
                                        return -EINVAL;
-                       }
-                       if (ext_type == SADB_X_EXT_SEC_CTX) {
+                               break;
+                       case SADB_X_EXT_SEC_CTX:
                                if (verify_sec_ctx_len(p))
                                        return -EINVAL;
+                               break;
+                       case SADB_EXT_KEY_AUTH:
+                       case SADB_EXT_KEY_ENCRYPT:
+                               if (verify_key_len(p))
+                                       return -EINVAL;
+                               break;
+                       default:
+                               break;
                        }
                        ext_hdrs[ext_type-1] = (void *) p;
                }
@@ -1111,14 +1128,12 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net,
        key = ext_hdrs[SADB_EXT_KEY_AUTH - 1];
        if (key != NULL &&
            sa->sadb_sa_auth != SADB_X_AALG_NULL &&
-           ((key->sadb_key_bits+7) / 8 == 0 ||
-            (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t)))
+           key->sadb_key_bits == 0)
                return ERR_PTR(-EINVAL);
        key = ext_hdrs[SADB_EXT_KEY_ENCRYPT-1];
        if (key != NULL &&
            sa->sadb_sa_encrypt != SADB_EALG_NULL &&
-           ((key->sadb_key_bits+7) / 8 == 0 ||
-            (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t)))
+           key->sadb_key_bits == 0)
                return ERR_PTR(-EINVAL);
 
        x = xfrm_state_alloc(net);
@@ -2438,8 +2453,10 @@ static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, const struc
                goto out;
        }
        err = pfkey_xfrm_policy2msg(out_skb, xp, dir);
-       if (err < 0)
+       if (err < 0) {
+               kfree_skb(out_skb);
                goto out;
+       }
 
        out_hdr = (struct sadb_msg *) out_skb->data;
        out_hdr->sadb_msg_version = hdr->sadb_msg_version;
@@ -2692,8 +2709,10 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr)
                return PTR_ERR(out_skb);
 
        err = pfkey_xfrm_policy2msg(out_skb, xp, dir);
-       if (err < 0)
+       if (err < 0) {
+               kfree_skb(out_skb);
                return err;
+       }
 
        out_hdr = (struct sadb_msg *) out_skb->data;
        out_hdr->sadb_msg_version = pfk->dump.msg_version;