Merge tag 'trace-v4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 1 Feb 2018 21:15:23 +0000 (13:15 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 1 Feb 2018 21:15:23 +0000 (13:15 -0800)
Pull tracing updates from Steven Rostedt:
 "There's not much changes for the tracing system this release. Mostly
  small clean ups and fixes.

  The biggest change is to how bprintf works. bprintf is used by
  trace_printk() to just save the format and args of a printf call, and
  the formatting is done when the trace buffer is read. This is done to
  keep the formatting out of the fast path (this was recommended by
  you). The issue is when arguments are de-referenced.

  If a pointer is saved, and the format has something like "%*pbl", when
  the buffer is read, it will de-reference the argument then. The
  problem is if the data no longer exists. This can cause the kernel to
  oops.

  The fix for this was to make these de-reference pointes do the
  formatting at the time it is called (the fast path), as this
  guarantees that the data exists (and doesn't change later)"

* tag 'trace-v4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
  vsprintf: Do not have bprintf dereference pointers
  ftrace: Mark function tracer test functions noinline/noclone
  trace_uprobe: Display correct offset in uprobe_events
  tracing: Make sure the parsed string always terminates with '\0'
  tracing: Clear parser->idx if only spaces are read
  tracing: Detect the string nul character when parsing user input string

kernel/trace/ftrace.c
kernel/trace/trace.c
kernel/trace/trace_events.c
kernel/trace/trace_selftest_dynamic.c
kernel/trace/trace_uprobe.c
lib/vsprintf.c

index 554b517c61a04d8f976b7a10975d47327c2f7bee..dabd9d167d425b20d5a8844f4f90af2ff03346ef 100644 (file)
@@ -5015,7 +5015,6 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
 
        parser = &iter->parser;
        if (trace_parser_loaded(parser)) {
-               parser->buffer[parser->idx] = 0;
                ftrace_match_records(iter->hash, parser->buffer, parser->idx);
        }
 
@@ -5329,7 +5328,6 @@ ftrace_graph_release(struct inode *inode, struct file *file)
                parser = &fgd->parser;
 
                if (trace_parser_loaded((parser))) {
-                       parser->buffer[parser->idx] = 0;
                        ret = ftrace_graph_set_hash(fgd->new_hash,
                                                    parser->buffer);
                }
index 32c069bbf41bd8ac73eb05f13484cac254d3e9a7..56608538a4ad61cc56d5a2cdaccfacd2eede4906 100644 (file)
@@ -530,8 +530,6 @@ int trace_pid_write(struct trace_pid_list *filtered_pids,
                ubuf += ret;
                cnt -= ret;
 
-               parser.buffer[parser.idx] = 0;
-
                ret = -EINVAL;
                if (kstrtoul(parser.buffer, 0, &val))
                        break;
@@ -1236,18 +1234,18 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
                        cnt--;
                }
 
+               parser->idx = 0;
+
                /* only spaces were written */
-               if (isspace(ch)) {
+               if (isspace(ch) || !ch) {
                        *ppos += read;
                        ret = read;
                        goto out;
                }
-
-               parser->idx = 0;
        }
 
        /* read the non-space input */
-       while (cnt && !isspace(ch)) {
+       while (cnt && !isspace(ch) && ch) {
                if (parser->idx < parser->size - 1)
                        parser->buffer[parser->idx++] = ch;
                else {
@@ -1262,12 +1260,14 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
        }
 
        /* We either got finished input or we have to wait for another call. */
-       if (isspace(ch)) {
+       if (isspace(ch) || !ch) {
                parser->buffer[parser->idx] = 0;
                parser->cont = false;
        } else if (parser->idx < parser->size - 1) {
                parser->cont = true;
                parser->buffer[parser->idx++] = ch;
+               /* Make sure the parsed string always terminates with '\0'. */
+               parser->buffer[parser->idx] = 0;
        } else {
                ret = -EINVAL;
                goto out;
index 1b87157edbff7c42a0884a3c0f8c0fa46c9d78ee..05c7172c6667d409de1d32f48afa01752f7a30ce 100644 (file)
@@ -885,8 +885,6 @@ ftrace_event_write(struct file *file, const char __user *ubuf,
                if (*parser.buffer == '!')
                        set = 0;
 
-               parser.buffer[parser.idx] = 0;
-
                ret = ftrace_set_clr_event(tr, parser.buffer + !set, set);
                if (ret)
                        goto out_put;
index 8cda06a10d66e4cc5ae264e781f7a593af377eae..c364cf777e1a507036c642c610d8137a09faa8ab 100644 (file)
@@ -1,13 +1,14 @@
 // SPDX-License-Identifier: GPL-2.0
+#include <linux/compiler.h>
 #include "trace.h"
 
-int DYN_FTRACE_TEST_NAME(void)
+noinline __noclone int DYN_FTRACE_TEST_NAME(void)
 {
        /* used to call mcount */
        return 0;
 }
 
-int DYN_FTRACE_TEST_NAME2(void)
+noinline __noclone int DYN_FTRACE_TEST_NAME2(void)
 {
        /* used to call mcount */
        return 0;
index 40592e7b3568bcfd41220f579fc05066e3675b33..268029ae1be685eedfc1c4e659b05c333480d1d7 100644 (file)
@@ -608,7 +608,7 @@ static int probes_seq_show(struct seq_file *m, void *v)
 
        /* Don't print "0x  (null)" when offset is 0 */
        if (tu->offset) {
-               seq_printf(m, "0x%p", (void *)tu->offset);
+               seq_printf(m, "0x%px", (void *)tu->offset);
        } else {
                switch (sizeof(void *)) {
                case 4:
index 2b18135446dcb89c89d4c0875ff504d798f17d9b..8f56cdd52149ba90fb4013a7ebf072a2992a5e05 100644 (file)
@@ -2517,29 +2517,34 @@ int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args)
 {
        struct printf_spec spec = {0};
        char *str, *end;
+       int width;
 
        str = (char *)bin_buf;
        end = (char *)(bin_buf + size);
 
 #define save_arg(type)                                                 \
-do {                                                                   \
+({                                                                     \
+       unsigned long long value;                                       \
        if (sizeof(type) == 8) {                                        \
-               unsigned long long value;                               \
+               unsigned long long val8;                                \
                str = PTR_ALIGN(str, sizeof(u32));                      \
-               value = va_arg(args, unsigned long long);               \
+               val8 = va_arg(args, unsigned long long);                \
                if (str + sizeof(type) <= end) {                        \
-                       *(u32 *)str = *(u32 *)&value;                   \
-                       *(u32 *)(str + 4) = *((u32 *)&value + 1);       \
+                       *(u32 *)str = *(u32 *)&val8;                    \
+                       *(u32 *)(str + 4) = *((u32 *)&val8 + 1);        \
                }                                                       \
+               value = val8;                                           \
        } else {                                                        \
-               unsigned long value;                                    \
+               unsigned int val4;                                      \
                str = PTR_ALIGN(str, sizeof(type));                     \
-               value = va_arg(args, int);                              \
+               val4 = va_arg(args, int);                               \
                if (str + sizeof(type) <= end)                          \
-                       *(typeof(type) *)str = (type)value;             \
+                       *(typeof(type) *)str = (type)(long)val4;        \
+               value = (unsigned long long)val4;                       \
        }                                                               \
        str += sizeof(type);                                            \
-} while (0)
+       value;                                                          \
+})
 
        while (*fmt) {
                int read = format_decode(fmt, &spec);
@@ -2555,7 +2560,10 @@ do {                                                                     \
 
                case FORMAT_TYPE_WIDTH:
                case FORMAT_TYPE_PRECISION:
-                       save_arg(int);
+                       width = (int)save_arg(int);
+                       /* Pointers may require the width */
+                       if (*fmt == 'p')
+                               set_field_width(&spec, width);
                        break;
 
                case FORMAT_TYPE_CHAR:
@@ -2577,7 +2585,27 @@ do {                                                                     \
                }
 
                case FORMAT_TYPE_PTR:
-                       save_arg(void *);
+                       /* Dereferenced pointers must be done now */
+                       switch (*fmt) {
+                       /* Dereference of functions is still OK */
+                       case 'S':
+                       case 's':
+                       case 'F':
+                       case 'f':
+                               save_arg(void *);
+                               break;
+                       default:
+                               if (!isalnum(*fmt)) {
+                                       save_arg(void *);
+                                       break;
+                               }
+                               str = pointer(fmt, str, end, va_arg(args, void *),
+                                             spec);
+                               if (str + 1 < end)
+                                       *str++ = '\0';
+                               else
+                                       end[-1] = '\0'; /* Must be nul terminated */
+                       }
                        /* skip all alphanumeric pointer suffixes */
                        while (isalnum(*fmt))
                                fmt++;
@@ -2729,11 +2757,39 @@ int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf)
                        break;
                }
 
-               case FORMAT_TYPE_PTR:
-                       str = pointer(fmt, str, end, get_arg(void *), spec);
+               case FORMAT_TYPE_PTR: {
+                       bool process = false;
+                       int copy, len;
+                       /* Non function dereferences were already done */
+                       switch (*fmt) {
+                       case 'S':
+                       case 's':
+                       case 'F':
+                       case 'f':
+                               process = true;
+                               break;
+                       default:
+                               if (!isalnum(*fmt)) {
+                                       process = true;
+                                       break;
+                               }
+                               /* Pointer dereference was already processed */
+                               if (str < end) {
+                                       len = copy = strlen(args);
+                                       if (copy > end - str)
+                                               copy = end - str;
+                                       memcpy(str, args, copy);
+                                       str += len;
+                                       args += len;
+                               }
+                       }
+                       if (process)
+                               str = pointer(fmt, str, end, get_arg(void *), spec);
+
                        while (isalnum(*fmt))
                                fmt++;
                        break;
+               }
 
                case FORMAT_TYPE_PERCENT_CHAR:
                        if (str < end)