| From stable-bounces@linux.kernel.org Fri Dec 30 22:13:55 2005 |
| Date: Fri, 30 Dec 2005 21:59:41 -0800 |
| Message-Id: <200512310559.jBV5xfr2026442@hera.kernel.org> |
| From: Linux Kernel Mailing List <linux-kernel@vger.kernel.org> |
| To: git-commits-head@vger.kernel.org |
| Cc: |
| Subject: sysctl: make sure to terminate strings with a NUL |
| |
| From: Linus Torvalds <torvalds@osdl.org> |
| |
| 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> |
| [chrisw: inclusive of minimal fix so it's same as upstream] |
| Signed-off-by: Chris Wright <chrisw@sous-sol.org> |
| --- |
| kernel/sysctl.c | 29 ++++++++++++++++------------- |
| 1 file changed, 16 insertions(+), 13 deletions(-) |
| |
| --- linux-2.6.14.5.orig/kernel/sysctl.c |
| +++ linux-2.6.14.5/kernel/sysctl.c |
| @@ -2191,29 +2191,32 @@ int sysctl_string(ctl_table *table, int |
| void __user *oldval, size_t __user *oldlenp, |
| void __user *newval, size_t newlen, void **context) |
| { |
| - size_t l, len; |
| - |
| if (!table->data || !table->maxlen) |
| return -ENOTDIR; |
| |
| if (oldval && oldlenp) { |
| - if (get_user(len, oldlenp)) |
| + size_t bufsize; |
| + if (get_user(bufsize, oldlenp)) |
| return -EFAULT; |
| - if (len) { |
| - l = strlen(table->data); |
| - if (len > l) len = l; |
| - if (len >= table->maxlen) |
| + if (bufsize) { |
| + size_t len = strlen(table->data), copied; |
| + |
| + /* This shouldn't trigger for a well-formed sysctl */ |
| + if (len > table->maxlen) |
| len = table->maxlen; |
| - if(copy_to_user(oldval, table->data, len)) |
| - return -EFAULT; |
| - if(put_user(0, ((char __user *) oldval) + 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; |
| - if(put_user(len, oldlenp)) |
| + if (put_user(len, oldlenp)) |
| return -EFAULT; |
| } |
| } |
| if (newval && newlen) { |
| - len = newlen; |
| + size_t len = newlen; |
| if (len > table->maxlen) |
| len = table->maxlen; |
| if(copy_from_user(table->data, newval, len)) |
| @@ -2222,7 +2225,7 @@ int sysctl_string(ctl_table *table, int |
| len--; |
| ((char *) table->data)[len] = 0; |
| } |
| - return 0; |
| + return 1; |
| } |
| |
| /* |