sysctl: make sure to terminate strings with a NUL
This is a slightly more complete fix for the previous minimal sysctl string fix. It always terminates the returned string with a NUL, even if the full result wouldn't fit in the user-supplied buffer. The returned length is the full untruncated length, so that you can tell when truncation has occurred. Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
35f349ee08
commit
de9e007d91
1 changed files with 15 additions and 10 deletions
|
@ -2192,27 +2192,32 @@ int sysctl_string(ctl_table *table, int __user *name, int nlen,
|
||||||
void __user *oldval, size_t __user *oldlenp,
|
void __user *oldval, size_t __user *oldlenp,
|
||||||
void __user *newval, size_t newlen, void **context)
|
void __user *newval, size_t newlen, void **context)
|
||||||
{
|
{
|
||||||
size_t l, len;
|
|
||||||
|
|
||||||
if (!table->data || !table->maxlen)
|
if (!table->data || !table->maxlen)
|
||||||
return -ENOTDIR;
|
return -ENOTDIR;
|
||||||
|
|
||||||
if (oldval && oldlenp) {
|
if (oldval && oldlenp) {
|
||||||
if (get_user(len, oldlenp))
|
size_t bufsize;
|
||||||
|
if (get_user(bufsize, oldlenp))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (len) {
|
if (bufsize) {
|
||||||
l = strlen(table->data)+1;
|
size_t len = strlen(table->data), copied;
|
||||||
if (len > l) len = l;
|
|
||||||
if (len >= table->maxlen)
|
/* This shouldn't trigger for a well-formed sysctl */
|
||||||
|
if (len > table->maxlen)
|
||||||
len = table->maxlen;
|
len = table->maxlen;
|
||||||
if(copy_to_user(oldval, table->data, len))
|
|
||||||
|
/* Copy up to a max of bufsize-1 bytes of the string */
|
||||||
|
copied = (len >= bufsize) ? bufsize - 1 : len;
|
||||||
|
|
||||||
|
if (copy_to_user(oldval, table->data, copied) ||
|
||||||
|
put_user(0, (char __user *)(oldval + copied)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (put_user(len, oldlenp))
|
if (put_user(len, oldlenp))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (newval && newlen) {
|
if (newval && newlen) {
|
||||||
len = newlen;
|
size_t len = newlen;
|
||||||
if (len > table->maxlen)
|
if (len > table->maxlen)
|
||||||
len = table->maxlen;
|
len = table->maxlen;
|
||||||
if(copy_from_user(table->data, newval, len))
|
if(copy_from_user(table->data, newval, len))
|
||||||
|
|
Loading…
Reference in a new issue