diff options
author | Josh Stone <jistone@redhat.com> | 2010-01-28 21:00:58 -0800 |
---|---|---|
committer | Josh Stone <jistone@redhat.com> | 2010-01-28 21:00:58 -0800 |
commit | f75409719f120a3dbee66d761cf23a64092d1414 (patch) | |
tree | a35e8f9c3d1cf317b2a989df10e5835dcc461670 /tapset/aux_syscalls.stp | |
parent | 15b2e969f0f67b2259e0345a446001ac80179968 (diff) | |
download | systemtap-steved-f75409719f120a3dbee66d761cf23a64092d1414.tar.gz systemtap-steved-f75409719f120a3dbee66d761cf23a64092d1414.tar.xz systemtap-steved-f75409719f120a3dbee66d761cf23a64092d1414.zip |
PR11234: Ensure __get_argv doesn't overflow
That function was calling strlcpy as if the return value was the number
of bytes copied, but strlcpy actually returns the length of the input
string. We now use min() to handle the case when it's bigger than the
buffer length, and drop out of the loop when that happens.
Diffstat (limited to 'tapset/aux_syscalls.stp')
-rw-r--r-- | tapset/aux_syscalls.stp | 26 |
1 files changed, 15 insertions, 11 deletions
diff --git a/tapset/aux_syscalls.stp b/tapset/aux_syscalls.stp index 4577d64e..a0ab557b 100644 --- a/tapset/aux_syscalls.stp +++ b/tapset/aux_syscalls.stp @@ -401,20 +401,20 @@ function __sem_flags:string(semflg:long) /* This function copies an argv from userspace. */ function __get_argv:string(a:long, first:long) %{ /* pure */ - char __user *__user *argv = (char __user *__user *)(long)THIS->a; + char __user *__user *argv = (char __user *__user *)(long)THIS->a; char __user *vstr; int space, rc, len = MAXSTRINGLEN; char *str = THIS->__retvalue; char buf[80]; char *ptr = buf; - + if (THIS->first && argv) argv++; - while (argv != NULL) { + while (argv != NULL && len) { if (__stp_get_user (vstr, argv)) - break; + break; if (vstr == NULL) break; @@ -443,8 +443,8 @@ function __get_argv:string(a:long, first:long) *str++='\"'; len--; } - - rc = strlcpy (str, buf, len); + + rc = min(len, (int) strlcpy (str, buf, len)); str += rc; len -= rc; @@ -455,13 +455,15 @@ function __get_argv:string(a:long, first:long) argv++; } + if (!len) + --str; *str = 0; %} /* This function copies an argv from userspace. */ function __get_compat_argv:string(a:long, first:long) %{ /* pure */ #ifdef CONFIG_COMPAT - compat_uptr_t __user *__user *argv = (compat_uptr_t __user *__user *)(long)THIS->a; + compat_uptr_t __user *__user *argv = (compat_uptr_t __user *__user *)(long)THIS->a; compat_uptr_t __user *vstr; int space, rc, len = MAXSTRINGLEN; char *str = THIS->__retvalue; @@ -471,9 +473,9 @@ function __get_compat_argv:string(a:long, first:long) if (THIS->first && argv) argv++; - while (argv != NULL) { + while (argv != NULL && len) { if (__stp_get_user (vstr, argv)) - break; + break; if (vstr == NULL) break; @@ -502,8 +504,8 @@ function __get_compat_argv:string(a:long, first:long) *str++='\"'; len--; } - - rc = strlcpy (str, buf, len); + + rc = min(len, (int) strlcpy (str, buf, len)); str += rc; len -= rc; @@ -514,6 +516,8 @@ function __get_compat_argv:string(a:long, first:long) argv++; } + if (!len) + --str; *str = 0; #endif %} |