From: Josh Stone Date: Thu, 31 Oct 2013 22:03:34 +0000 (-0700) Subject: Flip user_string_n_quoted to limit the input count X-Git-Tag: release-2.4~17 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=7bec2c2;p=systemtap.git Flip user_string_n_quoted to limit the input count The documentation of that function implies that it's counting n from the input string, but in fact that limit was being applied to the output, including quotes and escaping. Now _stp_text_str takes two length parameters to limit the input count and output size separately. A new user_string_n2_quoted() lets you specify both of these lengths, and user_string_n_quoted now uses that to limit input length, or output still in compatibility mode. Several syscall tapsets which read user buffers of known length will now use user_string_n2_quoted to fit that. This was seen in syscall.write which may not necessarily have any '\0' at the end of its buffer. --- diff --git a/runtime/stp_string.c b/runtime/stp_string.c index a7392782e..8a20b13ef 100644 --- a/runtime/stp_string.c +++ b/runtime/stp_string.c @@ -58,20 +58,23 @@ static int _stp_vscnprintf(char *buf, size_t size, const char *fmt, va_list args * * @param outstr Output string pointer * @param in Input string pointer - * @param len Maximum length of string to return not including terminating 0. + * @param inlen Maximum length of string to read not including terminating 0. + * @param outlen Maximum length of string to return not including terminating 0. * 0 means MAXSTRINGLEN. * @param quoted Put double quotes around the string. If input string is truncated * in will have "..." after the second quote. * @param user Set this to indicate the input string pointer is a userspace pointer. */ -static int _stp_text_str(char *outstr, char *in, int len, int quoted, int user) +static int _stp_text_str(char *outstr, char *in, int inlen, int outlen, int quoted, int user) { char c = '\0', *out = outstr; - if (len <= 0 || len > MAXSTRINGLEN-1) - len = MAXSTRINGLEN-1; + if (inlen <= 0 || inlen > MAXSTRINGLEN-1) + inlen = MAXSTRINGLEN-1; + if (outlen <= 0 || outlen > MAXSTRINGLEN-1) + outlen = MAXSTRINGLEN-1; if (quoted) { - len = max(len, 5) - 2; + outlen = max(outlen, 5) - 2; *out++ = '"'; } @@ -81,7 +84,7 @@ static int _stp_text_str(char *outstr, char *in, int len, int quoted, int user) } else c = *in; - while (c && len > 0) { + while (c && inlen > 0 && outlen > 0) { int num = 1; if (isprint(c) && isascii(c) && c != '"' && c != '\\') /* quoteworthy characters */ @@ -104,7 +107,7 @@ static int _stp_text_str(char *outstr, char *in, int len, int quoted, int user) break; } - if (len < num) + if (outlen < num) break; *out++ = '\\'; @@ -143,7 +146,8 @@ static int _stp_text_str(char *outstr, char *in, int len, int quoted, int user) break; } } - len -= num; + outlen -= num; + inlen--; in++; if (user) { if (_stp_read_address(c, in, USER_DS)) @@ -153,8 +157,8 @@ static int _stp_text_str(char *outstr, char *in, int len, int quoted, int user) } if (quoted) { - if (c) { - out = out - 3 + len; + if (c && inlen > 0) { + out = out - 3 + outlen; *out++ = '"'; *out++ = '.'; *out++ = '.'; @@ -165,7 +169,7 @@ static int _stp_text_str(char *outstr, char *in, int len, int quoted, int user) *out = '\0'; return 0; bad: - strlcpy (outstr, "", len); + strlcpy (outstr, "", outlen); return -1; // PR15044 } diff --git a/runtime/stp_string.h b/runtime/stp_string.h index e60db237c..054d7da46 100644 --- a/runtime/stp_string.h +++ b/runtime/stp_string.h @@ -10,7 +10,7 @@ #define _STP_STRING_H_ #define to_oct_digit(c) ((c) + '0') -static int _stp_text_str(char *out, char *in, int len, int quoted, int user); +static int _stp_text_str(char *out, char *in, int inlen, int outlen, int quoted, int user); #if defined(__KERNEL__) diff --git a/tapset/linux/nd_syscalls.stp b/tapset/linux/nd_syscalls.stp index 5cb7ac26f..f2daa0116 100644 --- a/tapset/linux/nd_syscalls.stp +++ b/tapset/linux/nd_syscalls.stp @@ -135,7 +135,7 @@ probe nd_syscall.add_key = kprobe.function("sys_add_key") ? argstr = sprintf("%s, %s, %s, %d, %d", user_string_quoted(type_uaddr), user_string_quoted(description_uaddr), - user_string_n_quoted(payload_uaddr, syscall_string_trunc), + user_string_n2_quoted(payload_uaddr, plen, syscall_string_trunc), plen, ringid) } probe nd_syscall.add_key.return = kprobe.function("sys_add_key").return ? diff --git a/tapset/linux/nd_syscalls2.stp b/tapset/linux/nd_syscalls2.stp index 0103f2bbc..667393c15 100644 --- a/tapset/linux/nd_syscalls2.stp +++ b/tapset/linux/nd_syscalls2.stp @@ -709,7 +709,7 @@ probe nd_syscall.pwrite = kprobe.function("sys_pwrite64") ? count = ulong_arg(3) offset = longlong_arg(4) argstr = sprintf("%d, %s, %d, %d", fd, - user_string_n_quoted(buf_uaddr, syscall_string_trunc), + user_string_n2_quoted(buf_uaddr, count, syscall_string_trunc), count, offset) } probe nd_syscall.pwrite.return = kprobe.function("sys_pwrite64").return ? @@ -743,7 +743,7 @@ probe nd_syscall.pwrite32 = kprobe.function("sys32_pwrite64") ? count = ulong_arg(3) offset = (u32_arg(4) << 32) + u32_arg(5) argstr = sprintf("%d, %s, %d, %d", fd, - user_string_n_quoted(buf_uaddr, syscall_string_trunc), + user_string_n2_quoted(buf_uaddr, count, syscall_string_trunc), count, offset) } probe nd_syscall.pwrite32.return = kprobe.function("sys32_pwrite64").return ? @@ -4500,7 +4500,9 @@ probe nd_syscall.write = kprobe.function("sys_write") ? fd = uint_arg(1) buf_uaddr = pointer_arg(2) count = ulong_arg(3) - argstr = sprintf("%d, %s, %d", fd, user_string_n_quoted(buf_uaddr, syscall_string_trunc), count) + argstr = sprintf("%d, %s, %d", fd, + user_string_n2_quoted(buf_uaddr, count, syscall_string_trunc), + count) } probe nd_syscall.write.return = kprobe.function("sys_write").return ? diff --git a/tapset/linux/syscalls.stp b/tapset/linux/syscalls.stp index 5f63f88c7..13fb92fd9 100644 --- a/tapset/linux/syscalls.stp +++ b/tapset/linux/syscalls.stp @@ -107,7 +107,7 @@ probe syscall.add_key = kernel.function("sys_add_key").call ? argstr = sprintf("%s, %s, %s, %d, %d", user_string_quoted($_type), user_string_quoted($_description), - user_string_n_quoted($_payload, syscall_string_trunc), + user_string_n2_quoted($_payload, $plen, syscall_string_trunc), $plen, $ringid) } probe syscall.add_key.return = kernel.function("sys_add_key").return ? diff --git a/tapset/linux/syscalls2.stp b/tapset/linux/syscalls2.stp index 083fa1c29..6770a3eff 100644 --- a/tapset/linux/syscalls2.stp +++ b/tapset/linux/syscalls2.stp @@ -612,7 +612,7 @@ probe syscall.pwrite = kernel.function("sys_pwrite64").call count = $count offset = $pos argstr = sprintf("%d, %s, %d, %d", $fd, - user_string_n_quoted($buf, syscall_string_trunc), + user_string_n2_quoted($buf, $count, syscall_string_trunc), $count, $pos) } probe syscall.pwrite.return = kernel.function("sys_pwrite64").return @@ -631,12 +631,12 @@ probe syscall.pwrite32 = kernel.function("sys32_pwrite64").call ? %( arch == "s390" %? buf_uaddr = $ubuf argstr = sprintf("%d, %s, %d, %d", $fd, - user_string_n_quoted($ubuf, syscall_string_trunc), + user_string_n2_quoted($ubuf, $count, syscall_string_trunc), $count, ($poshi << 32) + $poslo) %: buf_uaddr = $buf argstr = sprintf("%d, %s, %d, %d", $fd, - user_string_n_quoted($buf, syscall_string_trunc), + user_string_n2_quoted($buf, $count, syscall_string_trunc), $count, ($poshi << 32) + $poslo) %) } @@ -3651,7 +3651,9 @@ probe syscall.write = kernel.function("sys_write").call fd = $fd buf_uaddr = $buf count = $count - argstr = sprintf("%d, %s, %d", $fd, user_string_n_quoted($buf, syscall_string_trunc), $count) + argstr = sprintf("%d, %s, %d", $fd, + user_string_n2_quoted($buf, $count, syscall_string_trunc), + $count) } probe syscall.write.return = kernel.function("sys_write").return { diff --git a/tapset/string.stp b/tapset/string.stp index f8376a32f..05dcb4a19 100644 --- a/tapset/string.stp +++ b/tapset/string.stp @@ -85,7 +85,7 @@ function isinstr:long(s1:string,s2:string) %{ /* pure */ /* unprivileged */ */ function text_str:string(input:string) %{ /* pure */ /* unprivileged */ - if (_stp_text_str(STAP_RETVALUE, STAP_ARG_input, 0, 0, 0) < 0) { + if (_stp_text_str(STAP_RETVALUE, STAP_ARG_input, 0, 0, 0, 0) < 0) { STAP_RETVALUE[0] = '\0'; } %} @@ -107,7 +107,7 @@ function text_strn:string(input:string, len:long, quoted:long) %{ /* pure */ /* unprivileged */ int64_t len = clamp_t(int64_t, STAP_ARG_len, 0, MAXSTRINGLEN); if (_stp_text_str( - STAP_RETVALUE, STAP_ARG_input, len, STAP_ARG_quoted, 0) < 0) { + STAP_RETVALUE, STAP_ARG_input, 0, len, STAP_ARG_quoted, 0) < 0) { STAP_RETVALUE[0] = '\0'; } %} diff --git a/tapset/uconversions.stp b/tapset/uconversions.stp index 1850e2b8c..0903b6938 100644 --- a/tapset/uconversions.stp +++ b/tapset/uconversions.stp @@ -104,7 +104,7 @@ function user_string2_warn:string (addr:long, warn_msg:string) { * returned as a string, without double quotes. */ function user_string_quoted:string (addr:long) { - return user_string_n_quoted(addr, @MAXSTRINGLEN) + return user_string_n2_quoted(addr, @MAXSTRINGLEN, @MAXSTRINGLEN) } /** @@ -221,10 +221,35 @@ function user_string2_n_warn:string (addr:long, n:long, warn_msg:string) * On the rare cases when userspace data is not accessible at the given address, * the address itself is returned as a string, without double quotes. */ -function user_string_n_quoted:string (addr:long, n:long) +function user_string_n_quoted:string (addr:long, n:long) { +%(systemtap_v < "2.4" %? + // We used to count n by output characters + return user_string_n2_quoted(addr, @MAXSTRINGLEN, n) +%: + return user_string_n2_quoted(addr, n, @MAXSTRINGLEN) +%) +} + +/** + * sfunction user_string_n2_quoted - Retrieves and quotes string from user space + * + * @addr: the user space address to retrieve the string from + * @inlen: the maximum length of the string to read (if not null terminated) + * @outlen: the maximum length of the output string + * + * Description: Reads up to inlen characters of a C string from the given user + * space memory address, and returns up to outlen characters, where any ASCII + * characters that are not printable are replaced by the corresponding escape + * sequence in the returned string. Note that the string will be surrounded by + * double quotes. On the rare cases when userspace data is not accessible at + * the given address, the address itself is returned as a string, without + * double quotes. + */ +function user_string_n2_quoted:string (addr:long, inlen:long, outlen:long) %{ /* pure */ /* myproc-unprivileged */ // Note the lack of STAP_ARG_n+1 as in other funcs() -- PR15617 - int64_t len = clamp_t(int64_t, STAP_ARG_n, 0, MAXSTRINGLEN); + int64_t inlen = clamp_t(int64_t, STAP_ARG_inlen, 0, MAXSTRINGLEN); + int64_t outlen = clamp_t(int64_t, STAP_ARG_outlen, 0, MAXSTRINGLEN); if (STAP_ARG_addr == 0) #if STAP_COMPAT_VERSION < STAP_VERSION(2,3) // PR15044 strlcpy(STAP_RETVALUE, "NULL", MAXSTRINGLEN); @@ -233,7 +258,7 @@ function user_string_n_quoted:string (addr:long, n:long) #endif else { int rc = _stp_text_str(STAP_RETVALUE, - (char *)(uintptr_t)STAP_ARG_addr, len, 1, 1); + (char *)(uintptr_t)STAP_ARG_addr, inlen, outlen, 1, 1); if (rc < 0) #if STAP_COMPAT_VERSION < STAP_VERSION(2,3) // PR15044 strlcpy(STAP_RETVALUE, "", MAXSTRINGLEN); diff --git a/testsuite/buildok/conversions-embedded.stp b/testsuite/buildok/conversions-embedded.stp index 00a9bccc7..20fd5d3e2 100755 --- a/testsuite/buildok/conversions-embedded.stp +++ b/testsuite/buildok/conversions-embedded.stp @@ -20,6 +20,7 @@ probe begin { print (user_string_n2(0, 5, "foobar")) print (user_string_n_warn(0, 0)) print (user_string_n_quoted(0, 0)) + print (user_string_n2_quoted(0, 0, 0)) print (user_string_utf32 (0)) print (user_string_utf16 (0)) print (user_short(0))