}
 
 /* Returns true if the string is safe to dereference from an event */
-static bool trace_safe_str(struct trace_iterator *iter, const char *str,
-                          bool star, int len)
+static bool trace_safe_str(struct trace_iterator *iter, const char *str)
 {
        unsigned long addr = (unsigned long)str;
        struct trace_event *trace_event;
        struct trace_event_call *event;
 
-       /* Ignore strings with no length */
-       if (star && !len)
-               return true;
-
        /* OK if part of the event data */
        if ((addr >= (unsigned long)iter->ent) &&
            (addr < (unsigned long)iter->ent + iter->ent_size))
        return false;
 }
 
-static DEFINE_STATIC_KEY_FALSE(trace_no_verify);
-
-static int test_can_verify_check(const char *fmt, ...)
-{
-       char buf[16];
-       va_list ap;
-       int ret;
-
-       /*
-        * The verifier is dependent on vsnprintf() modifies the va_list
-        * passed to it, where it is sent as a reference. Some architectures
-        * (like x86_32) passes it by value, which means that vsnprintf()
-        * does not modify the va_list passed to it, and the verifier
-        * would then need to be able to understand all the values that
-        * vsnprintf can use. If it is passed by value, then the verifier
-        * is disabled.
-        */
-       va_start(ap, fmt);
-       vsnprintf(buf, 16, "%d", ap);
-       ret = va_arg(ap, int);
-       va_end(ap);
-
-       return ret;
-}
-
-static void test_can_verify(void)
-{
-       if (!test_can_verify_check("%d %d", 0, 1)) {
-               pr_info("trace event string verifier disabled\n");
-               static_branch_inc(&trace_no_verify);
-       }
-}
-
 /**
- * trace_check_vprintf - Check dereferenced strings while writing to the seq buffer
+ * ignore_event - Check dereferenced fields while writing to the seq buffer
  * @iter: The iterator that holds the seq buffer and the event being printed
- * @fmt: The format used to print the event
- * @ap: The va_list holding the data to print from @fmt.
  *
- * This writes the data into the @iter->seq buffer using the data from
- * @fmt and @ap. If the format has a %s, then the source of the string
- * is examined to make sure it is safe to print, otherwise it will
- * warn and print "[UNSAFE MEMORY]" in place of the dereferenced string
- * pointer.
+ * At boot up, test_event_printk() will flag any event that dereferences
+ * a string with "%s" that does exist in the ring buffer. It may still
+ * be valid, as the string may point to a static string in the kernel
+ * rodata that never gets freed. But if the string pointer is pointing
+ * to something that was allocated, there's a chance that it can be freed
+ * by the time the user reads the trace. This would cause a bad memory
+ * access by the kernel and possibly crash the system.
+ *
+ * This function will check if the event has any fields flagged as needing
+ * to be checked at runtime and perform those checks.
+ *
+ * If it is found that a field is unsafe, it will write into the @iter->seq
+ * a message stating what was found to be unsafe.
+ *
+ * @return: true if the event is unsafe and should be ignored,
+ *          false otherwise.
  */
-void trace_check_vprintf(struct trace_iterator *iter, const char *fmt,
-                        va_list ap)
+bool ignore_event(struct trace_iterator *iter)
 {
-       long text_delta = 0;
-       long data_delta = 0;
-       const char *p = fmt;
-       const char *str;
-       bool good;
-       int i, j;
+       struct ftrace_event_field *field;
+       struct trace_event *trace_event;
+       struct trace_event_call *event;
+       struct list_head *head;
+       struct trace_seq *seq;
+       const void *ptr;
 
-       if (WARN_ON_ONCE(!fmt))
-               return;
+       trace_event = ftrace_find_event(iter->ent->type);
 
-       if (static_branch_unlikely(&trace_no_verify))
-               goto print;
+       seq = &iter->seq;
 
-       /*
-        * When the kernel is booted with the tp_printk command line
-        * parameter, trace events go directly through to printk().
-        * It also is checked by this function, but it does not
-        * have an associated trace_array (tr) for it.
-        */
-       if (iter->tr) {
-               text_delta = iter->tr->text_delta;
-               data_delta = iter->tr->data_delta;
+       if (!trace_event) {
+               trace_seq_printf(seq, "EVENT ID %d NOT FOUND?\n", iter->ent->type);
+               return true;
        }
 
-       /* Don't bother checking when doing a ftrace_dump() */
-       if (iter->fmt == static_fmt_buf)
-               goto print;
-
-       while (*p) {
-               bool star = false;
-               int len = 0;
-
-               j = 0;
-
-               /*
-                * We only care about %s and variants
-                * as well as %p[sS] if delta is non-zero
-                */
-               for (i = 0; p[i]; i++) {
-                       if (i + 1 >= iter->fmt_size) {
-                               /*
-                                * If we can't expand the copy buffer,
-                                * just print it.
-                                */
-                               if (!trace_iter_expand_format(iter))
-                                       goto print;
-                       }
-
-                       if (p[i] == '\\' && p[i+1]) {
-                               i++;
-                               continue;
-                       }
-                       if (p[i] == '%') {
-                               /* Need to test cases like %08.*s */
-                               for (j = 1; p[i+j]; j++) {
-                                       if (isdigit(p[i+j]) ||
-                                           p[i+j] == '.')
-                                               continue;
-                                       if (p[i+j] == '*') {
-                                               star = true;
-                                               continue;
-                                       }
-                                       break;
-                               }
-                               if (p[i+j] == 's')
-                                       break;
-
-                               if (text_delta && p[i+1] == 'p' &&
-                                   ((p[i+2] == 's' || p[i+2] == 'S')))
-                                       break;
-
-                               star = false;
-                       }
-                       j = 0;
-               }
-               /* If no %s found then just print normally */
-               if (!p[i])
-                       break;
-
-               /* Copy up to the %s, and print that */
-               strncpy(iter->fmt, p, i);
-               iter->fmt[i] = '\0';
-               trace_seq_vprintf(&iter->seq, iter->fmt, ap);
+       event = container_of(trace_event, struct trace_event_call, event);
+       if (!(event->flags & TRACE_EVENT_FL_TEST_STR))
+               return false;
 
-               /* Add delta to %pS pointers */
-               if (p[i+1] == 'p') {
-                       unsigned long addr;
-                       char fmt[4];
+       head = trace_get_fields(event);
+       if (!head) {
+               trace_seq_printf(seq, "FIELDS FOR EVENT '%s' NOT FOUND?\n",
+                                trace_event_name(event));
+               return true;
+       }
 
-                       fmt[0] = '%';
-                       fmt[1] = 'p';
-                       fmt[2] = p[i+2]; /* Either %ps or %pS */
-                       fmt[3] = '\0';
+       /* Offsets are from the iter->ent that points to the raw event */
+       ptr = iter->ent;
 
-                       addr = va_arg(ap, unsigned long);
-                       addr += text_delta;
-                       trace_seq_printf(&iter->seq, fmt, (void *)addr);
+       list_for_each_entry(field, head, link) {
+               const char *str;
+               bool good;
 
-                       p += i + 3;
+               if (!field->needs_test)
                        continue;
-               }
 
-               /*
-                * If iter->seq is full, the above call no longer guarantees
-                * that ap is in sync with fmt processing, and further calls
-                * to va_arg() can return wrong positional arguments.
-                *
-                * Ensure that ap is no longer used in this case.
-                */
-               if (iter->seq.full) {
-                       p = "";
-                       break;
-               }
-
-               if (star)
-                       len = va_arg(ap, int);
-
-               /* The ap now points to the string data of the %s */
-               str = va_arg(ap, const char *);
+               str = *(const char **)(ptr + field->offset);
 
-               good = trace_safe_str(iter, str, star, len);
-
-               /* Could be from the last boot */
-               if (data_delta && !good) {
-                       str += data_delta;
-                       good = trace_safe_str(iter, str, star, len);
-               }
+               good = trace_safe_str(iter, str);
 
                /*
                 * If you hit this warning, it is likely that the
                 * instead. See samples/trace_events/trace-events-sample.h
                 * for reference.
                 */
-               if (WARN_ONCE(!good, "fmt: '%s' current_buffer: '%s'",
-                             fmt, seq_buf_str(&iter->seq.seq))) {
-                       int ret;
-
-                       /* Try to safely read the string */
-                       if (star) {
-                               if (len + 1 > iter->fmt_size)
-                                       len = iter->fmt_size - 1;
-                               if (len < 0)
-                                       len = 0;
-                               ret = copy_from_kernel_nofault(iter->fmt, str, len);
-                               iter->fmt[len] = 0;
-                               star = false;
-                       } else {
-                               ret = strncpy_from_kernel_nofault(iter->fmt, str,
-                                                                 iter->fmt_size);
-                       }
-                       if (ret < 0)
-                               trace_seq_printf(&iter->seq, "(0x%px)", str);
-                       else
-                               trace_seq_printf(&iter->seq, "(0x%px:%s)",
-                                                str, iter->fmt);
-                       str = "[UNSAFE-MEMORY]";
-                       strcpy(iter->fmt, "%s");
-               } else {
-                       strncpy(iter->fmt, p + i, j + 1);
-                       iter->fmt[j+1] = '\0';
+               if (WARN_ONCE(!good, "event '%s' has unsafe pointer field '%s'",
+                             trace_event_name(event), field->name)) {
+                       trace_seq_printf(seq, "EVENT %s: HAS UNSAFE POINTER FIELD '%s'\n",
+                                        trace_event_name(event), field->name);
+                       return true;
                }
-               if (star)
-                       trace_seq_printf(&iter->seq, iter->fmt, len, str);
-               else
-                       trace_seq_printf(&iter->seq, iter->fmt, str);
-
-               p += i + j + 1;
        }
- print:
-       if (*p)
-               trace_seq_vprintf(&iter->seq, p, ap);
+       return false;
 }
 
 const char *trace_event_format(struct trace_iterator *iter, const char *fmt)
 
        register_snapshot_cmd();
 
-       test_can_verify();
-
        return 0;
 
 out_free_pipe_cpumask:
 
        }
 
 static struct ftrace_event_field *
-__find_event_field(struct list_head *head, char *name)
+__find_event_field(struct list_head *head, const char *name)
 {
        struct ftrace_event_field *field;
 
 
 static int __trace_define_field(struct list_head *head, const char *type,
                                const char *name, int offset, int size,
-                               int is_signed, int filter_type, int len)
+                               int is_signed, int filter_type, int len,
+                               int need_test)
 {
        struct ftrace_event_field *field;
 
        field->offset = offset;
        field->size = size;
        field->is_signed = is_signed;
+       field->needs_test = need_test;
        field->len = len;
 
        list_add(&field->link, head);
 
        head = trace_get_fields(call);
        return __trace_define_field(head, type, name, offset, size,
-                                   is_signed, filter_type, 0);
+                                   is_signed, filter_type, 0, 0);
 }
 EXPORT_SYMBOL_GPL(trace_define_field);
 
 static int trace_define_field_ext(struct trace_event_call *call, const char *type,
                       const char *name, int offset, int size, int is_signed,
-                      int filter_type, int len)
+                      int filter_type, int len, int need_test)
 {
        struct list_head *head;
 
 
        head = trace_get_fields(call);
        return __trace_define_field(head, type, name, offset, size,
-                                   is_signed, filter_type, len);
+                                   is_signed, filter_type, len, need_test);
 }
 
 #define __generic_field(type, item, filter_type)                       \
        ret = __trace_define_field(&ftrace_generic_fields, #type,       \
                                   #item, 0, 0, is_signed_type(type),   \
-                                  filter_type, 0);                     \
+                                  filter_type, 0, 0);                  \
        if (ret)                                                        \
                return ret;
 
                                   "common_" #item,                     \
                                   offsetof(typeof(ent), item),         \
                                   sizeof(ent.item),                    \
-                                  is_signed_type(type), FILTER_OTHER, 0);      \
+                                  is_signed_type(type), FILTER_OTHER,  \
+                                  0, 0);                               \
        if (ret)                                                        \
                return ret;
 
 /* Return true if the string is safe */
 static bool process_string(const char *fmt, int len, struct trace_event_call *call)
 {
+       struct trace_event_fields *field;
        const char *r, *e, *s;
 
        e = fmt + len;
        if (process_pointer(fmt, len, call))
                return true;
 
-       /* Make sure the field is found, and consider it OK for now if it is */
-       return find_event_field(fmt, call) != NULL;
+       /* Make sure the field is found */
+       field = find_event_field(fmt, call);
+       if (!field)
+               return false;
+
+       /* Test this field's string before printing the event */
+       call->flags |= TRACE_EVENT_FL_TEST_STR;
+       field->needs_test = 1;
+
+       return true;
 }
 
 /*
                        ret = trace_define_field_ext(call, field->type, field->name,
                                                 offset, field->size,
                                                 field->is_signed, field->filter_type,
-                                                field->len);
+                                                field->len, field->needs_test);
                        if (WARN_ON_ONCE(ret)) {
                                pr_err("error code is %d\n", ret);
                                break;