/* 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 && len) {
+ while (argv != NULL) {
if (__stp_get_user (vstr, argv))
- break;
+ break;
if (vstr == NULL)
break;
*str++='\"';
len--;
}
-
- rc = min(len, (int) strlcpy (str, buf, len));
+
+ rc = strlcpy (str, buf, len);
str += rc;
len -= rc;
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;
if (THIS->first && argv)
argv++;
- while (argv != NULL && len) {
+ while (argv != NULL) {
if (__stp_get_user (vstr, argv))
- break;
+ break;
if (vstr == NULL)
break;
*str++='\"';
len--;
}
-
- rc = min(len, (int) strlcpy (str, buf, len));
+
+ rc = strlcpy (str, buf, len);
str += rc;
len -= rc;
argv++;
}
- if (!len)
- --str;
*str = 0;
#endif
%}
+++ /dev/null
-# PR11234: __get_argv can overflow its return buffer
-
-set test "overflow-get_argv"
-
-stap_run $srcdir/$subdir/$test.stp no_load $all_pass_string -g -c "/bin/true /usr/bin/*"
+++ /dev/null
-// PR11234: __get_argv can overflow its return buffer
-
-// __get_argv has a signature like this:
-// struct function___get_argv_locals {
-// int64_t a;
-// int64_t first;
-// string_t __retvalue;
-// } function___get_argv;
-//
-// These functions are meant to have an overlap such that we can tell if
-// __get_argv overran its __retvalue.
-//
-// int64_t x;
-// int64_t y;
-// string_t z;
-// string_t __retvalue;
-//
-// NB: __retvalue[0] always gets cleared on call, but the rest should be
-// untouched, so we can use it as a sentinal.
-
-function clear:string(x:long, y:long, z:string) %{
- memset(THIS->__retvalue, 0, MAXSTRINGLEN);
-%}
-
-function check:string(x:long, y:long, z:string) %{
- int i, bad = 0;
- for (i=1; i<MAXSTRINGLEN; ++i)
- if (THIS->__retvalue[i])
- ++bad;
-
- if (bad)
- snprintf(THIS->__retvalue, MAXSTRINGLEN, "%d non-zero bytes", bad);
- else
- strlcpy(THIS->__retvalue, "ok", MAXSTRINGLEN);
-%}
-
-global result = "untested"
-
-probe syscall.execve {
- if (pid() != target())
- next
-
- clear(0, 0, "")
- foo = __get_argv($argv, 0)
- result = check(0, 0, "")
-
- // ensure that foo isn't optimized away
- if (foo == "foo")
- next
-}
-
-probe begin {
- println("systemtap starting probe")
-}
-
-probe end {
- println("systemtap ending probe")
- if (result == "ok")
- println("systemtap test success")
- else
- println("systemtap test failure: ", result)
-}