kernel/*: switch to memdup_user_nul()
authorAl Viro <viro@zeniv.linux.org.uk>
Thu, 24 Dec 2015 05:13:10 +0000 (00:13 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 4 Jan 2016 15:27:55 +0000 (10:27 -0500)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
kernel/sysctl.c
kernel/trace/trace_events.c
kernel/trace/trace_events_trigger.c
kernel/user_namespace.c

index dc6858d..5faf89a 100644 (file)
@@ -2047,9 +2047,8 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
                  void *data)
 {
        int *i, vleft, first = 1, err = 0;
-       unsigned long page = 0;
        size_t left;
-       char *kbuf;
+       char *kbuf = NULL, *p;
        
        if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) {
                *lenp = 0;
@@ -2078,15 +2077,9 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
 
                if (left > PAGE_SIZE - 1)
                        left = PAGE_SIZE - 1;
-               page = __get_free_page(GFP_TEMPORARY);
-               kbuf = (char *) page;
-               if (!kbuf)
-                       return -ENOMEM;
-               if (copy_from_user(kbuf, buffer, left)) {
-                       err = -EFAULT;
-                       goto free;
-               }
-               kbuf[left] = 0;
+               p = kbuf = memdup_user_nul(buffer, left);
+               if (IS_ERR(kbuf))
+                       return PTR_ERR(kbuf);
        }
 
        for (; left && vleft--; i++, first=0) {
@@ -2094,11 +2087,11 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
                bool neg;
 
                if (write) {
-                       left -= proc_skip_spaces(&kbuf);
+                       left -= proc_skip_spaces(&p);
 
                        if (!left)
                                break;
-                       err = proc_get_long(&kbuf, &left, &lval, &neg,
+                       err = proc_get_long(&p, &left, &lval, &neg,
                                             proc_wspace_sep,
                                             sizeof(proc_wspace_sep), NULL);
                        if (err)
@@ -2125,10 +2118,9 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
        if (!write && !first && left && !err)
                err = proc_put_char(&buffer, &left, '\n');
        if (write && !err && left)
-               left -= proc_skip_spaces(&kbuf);
-free:
+               left -= proc_skip_spaces(&p);
        if (write) {
-               free_page(page);
+               kfree(kbuf);
                if (first)
                        return err ? : -EINVAL;
        }
@@ -2310,9 +2302,8 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
 {
        unsigned long *i, *min, *max;
        int vleft, first = 1, err = 0;
-       unsigned long page = 0;
        size_t left;
-       char *kbuf;
+       char *kbuf = NULL, *p;
 
        if (!data || !table->maxlen || !*lenp || (*ppos && !write)) {
                *lenp = 0;
@@ -2340,15 +2331,9 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
 
                if (left > PAGE_SIZE - 1)
                        left = PAGE_SIZE - 1;
-               page = __get_free_page(GFP_TEMPORARY);
-               kbuf = (char *) page;
-               if (!kbuf)
-                       return -ENOMEM;
-               if (copy_from_user(kbuf, buffer, left)) {
-                       err = -EFAULT;
-                       goto free;
-               }
-               kbuf[left] = 0;
+               p = kbuf = memdup_user_nul(buffer, left);
+               if (IS_ERR(kbuf))
+                       return PTR_ERR(kbuf);
        }
 
        for (; left && vleft--; i++, first = 0) {
@@ -2357,9 +2342,9 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
                if (write) {
                        bool neg;
 
-                       left -= proc_skip_spaces(&kbuf);
+                       left -= proc_skip_spaces(&p);
 
-                       err = proc_get_long(&kbuf, &left, &val, &neg,
+                       err = proc_get_long(&p, &left, &val, &neg,
                                             proc_wspace_sep,
                                             sizeof(proc_wspace_sep), NULL);
                        if (err)
@@ -2385,10 +2370,9 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
        if (!write && !first && left && !err)
                err = proc_put_char(&buffer, &left, '\n');
        if (write && !err)
-               left -= proc_skip_spaces(&kbuf);
-free:
+               left -= proc_skip_spaces(&p);
        if (write) {
-               free_page(page);
+               kfree(kbuf);
                if (first)
                        return err ? : -EINVAL;
        }
@@ -2650,34 +2634,27 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,
        }
 
        if (write) {
-               unsigned long page = 0;
-               char *kbuf;
+               char *kbuf, *p;
 
                if (left > PAGE_SIZE - 1)
                        left = PAGE_SIZE - 1;
 
-               page = __get_free_page(GFP_TEMPORARY);
-               kbuf = (char *) page;
-               if (!kbuf)
-                       return -ENOMEM;
-               if (copy_from_user(kbuf, buffer, left)) {
-                       free_page(page);
-                       return -EFAULT;
-                }
-               kbuf[left] = 0;
+               p = kbuf = memdup_user_nul(buffer, left);
+               if (IS_ERR(kbuf))
+                       return PTR_ERR(kbuf);
 
                tmp_bitmap = kzalloc(BITS_TO_LONGS(bitmap_len) * sizeof(unsigned long),
                                     GFP_KERNEL);
                if (!tmp_bitmap) {
-                       free_page(page);
+                       kfree(kbuf);
                        return -ENOMEM;
                }
-               proc_skip_char(&kbuf, &left, '\n');
+               proc_skip_char(&p, &left, '\n');
                while (!err && left) {
                        unsigned long val_a, val_b;
                        bool neg;
 
-                       err = proc_get_long(&kbuf, &left, &val_a, &neg, tr_a,
+                       err = proc_get_long(&p, &left, &val_a, &neg, tr_a,
                                             sizeof(tr_a), &c);
                        if (err)
                                break;
@@ -2688,12 +2665,12 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,
 
                        val_b = val_a;
                        if (left) {
-                               kbuf++;
+                               p++;
                                left--;
                        }
 
                        if (c == '-') {
-                               err = proc_get_long(&kbuf, &left, &val_b,
+                               err = proc_get_long(&p, &left, &val_b,
                                                     &neg, tr_b, sizeof(tr_b),
                                                     &c);
                                if (err)
@@ -2704,16 +2681,16 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,
                                        break;
                                }
                                if (left) {
-                                       kbuf++;
+                                       p++;
                                        left--;
                                }
                        }
 
                        bitmap_set(tmp_bitmap, val_a, val_b - val_a + 1);
                        first = 0;
-                       proc_skip_char(&kbuf, &left, '\n');
+                       proc_skip_char(&p, &left, '\n');
                }
-               free_page(page);
+               kfree(kbuf);
        } else {
                unsigned long bit_a, bit_b = 0;
 
index 4f6ef69..f333e57 100644 (file)
@@ -1340,15 +1340,9 @@ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
        if (cnt >= PAGE_SIZE)
                return -EINVAL;
 
-       buf = (char *)__get_free_page(GFP_TEMPORARY);
-       if (!buf)
-               return -ENOMEM;
-
-       if (copy_from_user(buf, ubuf, cnt)) {
-               free_page((unsigned long) buf);
-               return -EFAULT;
-       }
-       buf[cnt] = '\0';
+       buf = memdup_user_nul(ubuf, cnt);
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
 
        mutex_lock(&event_mutex);
        file = event_file_data(filp);
@@ -1356,7 +1350,7 @@ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
                err = apply_event_filter(file, buf);
        mutex_unlock(&event_mutex);
 
-       free_page((unsigned long) buf);
+       kfree(buf);
        if (err < 0)
                return err;
 
@@ -1507,18 +1501,12 @@ subsystem_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
        if (cnt >= PAGE_SIZE)
                return -EINVAL;
 
-       buf = (char *)__get_free_page(GFP_TEMPORARY);
-       if (!buf)
-               return -ENOMEM;
-
-       if (copy_from_user(buf, ubuf, cnt)) {
-               free_page((unsigned long) buf);
-               return -EFAULT;
-       }
-       buf[cnt] = '\0';
+       buf = memdup_user_nul(ubuf, cnt);
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
 
        err = apply_subsystem_event_filter(dir, buf);
-       free_page((unsigned long) buf);
+       kfree(buf);
        if (err < 0)
                return err;
 
index 42a4009..4b5e8ed 100644 (file)
@@ -237,28 +237,23 @@ static ssize_t event_trigger_regex_write(struct file *file,
        if (cnt >= PAGE_SIZE)
                return -EINVAL;
 
-       buf = (char *)__get_free_page(GFP_TEMPORARY);
-       if (!buf)
-               return -ENOMEM;
+       buf = memdup_user_nul(ubuf, cnt);
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
 
-       if (copy_from_user(buf, ubuf, cnt)) {
-               free_page((unsigned long)buf);
-               return -EFAULT;
-       }
-       buf[cnt] = '\0';
        strim(buf);
 
        mutex_lock(&event_mutex);
        event_file = event_file_data(file);
        if (unlikely(!event_file)) {
                mutex_unlock(&event_mutex);
-               free_page((unsigned long)buf);
+               kfree(buf);
                return -ENODEV;
        }
        ret = trigger_process_regex(event_file, buf);
        mutex_unlock(&event_mutex);
 
-       free_page((unsigned long)buf);
+       kfree(buf);
        if (ret < 0)
                goto out;
 
index 88fefa6..9bafc21 100644 (file)
@@ -602,8 +602,7 @@ static ssize_t map_write(struct file *file, const char __user *buf,
        struct uid_gid_map new_map;
        unsigned idx;
        struct uid_gid_extent *extent = NULL;
-       unsigned long page = 0;
-       char *kbuf, *pos, *next_line;
+       char *kbuf = NULL, *pos, *next_line;
        ssize_t ret = -EINVAL;
 
        /*
@@ -638,23 +637,18 @@ static ssize_t map_write(struct file *file, const char __user *buf,
        if (cap_valid(cap_setid) && !file_ns_capable(file, ns, CAP_SYS_ADMIN))
                goto out;
 
-       /* Get a buffer */
-       ret = -ENOMEM;
-       page = __get_free_page(GFP_TEMPORARY);
-       kbuf = (char *) page;
-       if (!page)
-               goto out;
-
        /* Only allow < page size writes at the beginning of the file */
        ret = -EINVAL;
        if ((*ppos != 0) || (count >= PAGE_SIZE))
                goto out;
 
        /* Slurp in the user data */
-       ret = -EFAULT;
-       if (copy_from_user(kbuf, buf, count))
+       kbuf = memdup_user_nul(buf, count);
+       if (IS_ERR(kbuf)) {
+               ret = PTR_ERR(kbuf);
+               kbuf = NULL;
                goto out;
-       kbuf[count] = '\0';
+       }
 
        /* Parse the user data */
        ret = -EINVAL;
@@ -756,8 +750,7 @@ static ssize_t map_write(struct file *file, const char __user *buf,
        ret = count;
 out:
        mutex_unlock(&userns_state_mutex);
-       if (page)
-               free_page(page);
+       kfree(kbuf);
        return ret;
 }