Merge tag 'v3.10.57' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / ipc / msgutil.c
index 8f0201735f16c6ceaf6b8eda9b4840c76b5e18bd..7e7095974d54a10e175dd06504cb8dc6ac73adcb 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/ipc_namespace.h>
 #include <linux/utsname.h>
 #include <linux/proc_ns.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #include "util.h"
 
@@ -37,59 +37,70 @@ struct ipc_namespace init_ipc_ns = {
 atomic_t nr_ipc_ns = ATOMIC_INIT(1);
 
 struct msg_msgseg {
-       struct msg_msgsegnext;
+       struct msg_msgseg *next;
        /* the next part of the message follows immediately */
 };
 
-#define DATALEN_MSG    (PAGE_SIZE-sizeof(struct msg_msg))
-#define DATALEN_SEG    (PAGE_SIZE-sizeof(struct msg_msgseg))
+#define DATALEN_MSG    ((size_t)PAGE_SIZE-sizeof(struct msg_msg))
+#define DATALEN_SEG    ((size_t)PAGE_SIZE-sizeof(struct msg_msgseg))
 
-struct msg_msg *load_msg(const void __user *src, int len)
+
+static struct msg_msg *alloc_msg(size_t len)
 {
        struct msg_msg *msg;
        struct msg_msgseg **pseg;
-       int err;
-       int alen;
-
-       alen = len;
-       if (alen > DATALEN_MSG)
-               alen = DATALEN_MSG;
+       size_t alen;
 
+       alen = min(len, DATALEN_MSG);
        msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
        if (msg == NULL)
-               return ERR_PTR(-ENOMEM);
+               return NULL;
 
        msg->next = NULL;
        msg->security = NULL;
 
-       if (copy_from_user(msg + 1, src, alen)) {
-               err = -EFAULT;
-               goto out_err;
-       }
-
        len -= alen;
-       src = ((char __user *)src) + alen;
        pseg = &msg->next;
        while (len > 0) {
                struct msg_msgseg *seg;
-               alen = len;
-               if (alen > DATALEN_SEG)
-                       alen = DATALEN_SEG;
-               seg = kmalloc(sizeof(*seg) + alen,
-                                                GFP_KERNEL);
-               if (seg == NULL) {
-                       err = -ENOMEM;
+               alen = min(len, DATALEN_SEG);
+               seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL);
+               if (seg == NULL)
                        goto out_err;
-               }
                *pseg = seg;
                seg->next = NULL;
-               if (copy_from_user(seg + 1, src, alen)) {
-                       err = -EFAULT;
-                       goto out_err;
-               }
                pseg = &seg->next;
                len -= alen;
-               src = ((char __user *)src) + alen;
+       }
+
+       return msg;
+
+out_err:
+       free_msg(msg);
+       return NULL;
+}
+
+struct msg_msg *load_msg(const void __user *src, size_t len)
+{
+       struct msg_msg *msg;
+       struct msg_msgseg *seg;
+       int err = -EFAULT;
+       size_t alen;
+
+       msg = alloc_msg(len);
+       if (msg == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       alen = min(len, DATALEN_MSG);
+       if (copy_from_user(msg + 1, src, alen))
+               goto out_err;
+
+       for (seg = msg->next; seg != NULL; seg = seg->next) {
+               len -= alen;
+               src = (char __user *)src + alen;
+               alen = min(len, DATALEN_SEG);
+               if (copy_from_user(seg + 1, src, alen))
+                       goto out_err;
        }
 
        err = security_msg_msg_alloc(msg);
@@ -106,30 +117,23 @@ out_err:
 struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
 {
        struct msg_msgseg *dst_pseg, *src_pseg;
-       int len = src->m_ts;
-       int alen;
+       size_t len = src->m_ts;
+       size_t alen;
 
        BUG_ON(dst == NULL);
        if (src->m_ts > dst->m_ts)
                return ERR_PTR(-EINVAL);
 
-       alen = len;
-       if (alen > DATALEN_MSG)
-               alen = DATALEN_MSG;
-
+       alen = min(len, DATALEN_MSG);
        memcpy(dst + 1, src + 1, alen);
 
-       len -= alen;
-       dst_pseg = dst->next;
-       src_pseg = src->next;
-       while (len > 0) {
-               alen = len;
-               if (alen > DATALEN_SEG)
-                       alen = DATALEN_SEG;
-               memcpy(dst_pseg + 1, src_pseg + 1, alen);
-               dst_pseg = dst_pseg->next;
+       for (dst_pseg = dst->next, src_pseg = src->next;
+            src_pseg != NULL;
+            dst_pseg = dst_pseg->next, src_pseg = src_pseg->next) {
+
                len -= alen;
-               src_pseg = src_pseg->next;
+               alen = min(len, DATALEN_SEG);
+               memcpy(dst_pseg + 1, src_pseg + 1, alen);
        }
 
        dst->m_type = src->m_type;
@@ -143,29 +147,21 @@ struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
        return ERR_PTR(-ENOSYS);
 }
 #endif
-int store_msg(void __user *dest, struct msg_msg *msg, int len)
+int store_msg(void __user *dest, struct msg_msg *msg, size_t len)
 {
-       int alen;
+       size_t alen;
        struct msg_msgseg *seg;
 
-       alen = len;
-       if (alen > DATALEN_MSG)
-               alen = DATALEN_MSG;
+       alen = min(len, DATALEN_MSG);
        if (copy_to_user(dest, msg + 1, alen))
                return -1;
 
-       len -= alen;
-       dest = ((char __user *)dest) + alen;
-       seg = msg->next;
-       while (len > 0) {
-               alen = len;
-               if (alen > DATALEN_SEG)
-                       alen = DATALEN_SEG;
+       for (seg = msg->next; seg != NULL; seg = seg->next) {
+               len -= alen;
+               dest = (char __user *)dest + alen;
+               alen = min(len, DATALEN_SEG);
                if (copy_to_user(dest, seg + 1, alen))
                        return -1;
-               len -= alen;
-               dest = ((char __user *)dest) + alen;
-               seg = seg->next;
        }
        return 0;
 }