Skip to content

Commit

Permalink
kernel/*: switch to memdup_user_nul()
Browse files Browse the repository at this point in the history
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
  • Loading branch information
Al Viro committed Jan 4, 2016
1 parent e4e85bb commit 70f6cbb
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 95 deletions.
79 changes: 28 additions & 51 deletions kernel/sysctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -2078,27 +2077,21 @@ 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) {
unsigned long lval;
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)
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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)
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand All @@ -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;

Expand Down
28 changes: 8 additions & 20 deletions kernel/trace/trace_events.c
Original file line number Diff line number Diff line change
Expand Up @@ -1340,23 +1340,17 @@ 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);
if (file)
err = apply_event_filter(file, buf);
mutex_unlock(&event_mutex);

free_page((unsigned long) buf);
kfree(buf);
if (err < 0)
return err;

Expand Down Expand Up @@ -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;

Expand Down
15 changes: 5 additions & 10 deletions kernel/trace/trace_events_trigger.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
21 changes: 7 additions & 14 deletions kernel/user_namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/*
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down

0 comments on commit 70f6cbb

Please sign in to comment.