Merge tag 'trace-v6.17-rc2-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull tracing fixes from Steven Rostedt:

- Fix rtla and latency tooling pkg-config errors

If libtraceevent and libtracefs is installed, but their corresponding
'.pc' files are not installed, it reports that the libraries are
missing and confuses the developer. Instead, report that the
pkg-config files are missing and should be installed.

- Fix overflow bug of the parser in trace_get_user()

trace_get_user() uses the parsing functions to parse the user space
strings. If the parser fails due to incorrect processing, it doesn't
terminate the buffer with a nul byte. Add a "failed" flag to the
parser that gets set when parsing fails and is used to know if the
buffer is fine to use or not.

- Remove a semicolon that was at an end of a comment line

- Fix register_ftrace_graph() to unregister the pm notifier on error

The register_ftrace_graph() registers a pm notifier but there's an
error path that can exit the function without unregistering it. Since
the function returns an error, it will never be unregistered.

- Allocate and copy ftrace hash for reader of ftrace filter files

When the set_ftrace_filter or set_ftrace_notrace files are open for
read, an iterator is created and sets its hash pointer to the
associated hash that represents filtering or notrace filtering to it.
The issue is that the hash it points to can change while the
iteration is happening. All the locking used to access the tracer's
hashes are released which means those hashes can change or even be
freed. Using the hash pointed to by the iterator can cause UAF bugs
or similar.

Have the read of these files allocate and copy the corresponding
hashes and use that as that will keep them the same while the
iterator is open. This also simplifies the code as opening it for
write already does an allocate and copy, and now that the read is
doing the same, there's no need to check which way it was opened on
the release of the file, and the iterator hash can always be freed.

- Fix function graph to copy args into temp storage

The output of the function graph tracer shows both the entry and the
exit of a function. When the exit is right after the entry, it
combines the two events into one with the output of "function();",
instead of showing:

function() {
}

In order to do this, the iterator descriptor that reads the events
includes storage that saves the entry event while it peaks at the
next event in the ring buffer. The peek can free the entry event so
the iterator must store the information to use it after the peek.

With the addition of function graph tracer recording the args, where
the args are a dynamic array in the entry event, the temp storage
does not save them. This causes the args to be corrupted or even
cause a read of unsafe memory.

Add space to save the args in the temp storage of the iterator.

- Fix race between ftrace_dump and reading trace_pipe

ftrace_dump() is used when a crash occurs where the ftrace buffer
will be printed to the console. But it can also be triggered by
sysrq-z. If a sysrq-z is triggered while a task is reading trace_pipe
it can cause a race in the ftrace_dump() where it checks if the
buffer has content, then it checks if the next event is available,
and then prints the output (regardless if the next event was
available or not). Reading trace_pipe at the same time can cause it
to not be available, and this triggers a WARN_ON in the print. Move
the printing into the check if the next event exists or not

* tag 'trace-v6.17-rc2-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
ftrace: Also allocate and copy hash for reading of filter files
ftrace: Fix potential warning in trace_printk_seq during ftrace_dump
fgraph: Copy args in intermediate storage with entry
trace/fgraph: Fix the warning caused by missing unregister notifier
ring-buffer: Remove redundant semicolons
tracing: Limit access to parser->buffer when trace_get_user failed
rtla: Check pkg-config install
tools/latency-collector: Check pkg-config install

+65 -25
+1
kernel/trace/fgraph.c
··· 1397 ftrace_graph_active--; 1398 gops->saved_func = NULL; 1399 fgraph_lru_release_index(i); 1400 } 1401 return ret; 1402 }
··· 1397 ftrace_graph_active--; 1398 gops->saved_func = NULL; 1399 fgraph_lru_release_index(i); 1400 + unregister_pm_notifier(&ftrace_suspend_notifier); 1401 } 1402 return ret; 1403 }
+10 -9
kernel/trace/ftrace.c
··· 4661 } else { 4662 iter->hash = alloc_and_copy_ftrace_hash(size_bits, hash); 4663 } 4664 4665 - if (!iter->hash) { 4666 - trace_parser_put(&iter->parser); 4667 - goto out_unlock; 4668 - } 4669 - } else 4670 - iter->hash = hash; 4671 4672 ret = 0; 4673 ··· 6547 ftrace_hash_move_and_update_ops(iter->ops, orig_hash, 6548 iter->hash, filter_hash); 6549 mutex_unlock(&ftrace_lock); 6550 - } else { 6551 - /* For read only, the hash is the ops hash */ 6552 - iter->hash = NULL; 6553 } 6554 6555 mutex_unlock(&iter->ops->func_hash->regex_lock);
··· 4661 } else { 4662 iter->hash = alloc_and_copy_ftrace_hash(size_bits, hash); 4663 } 4664 + } else { 4665 + if (hash) 4666 + iter->hash = alloc_and_copy_ftrace_hash(hash->size_bits, hash); 4667 + else 4668 + iter->hash = EMPTY_HASH; 4669 + } 4670 4671 + if (!iter->hash) { 4672 + trace_parser_put(&iter->parser); 4673 + goto out_unlock; 4674 + } 4675 4676 ret = 0; 4677 ··· 6543 ftrace_hash_move_and_update_ops(iter->ops, orig_hash, 6544 iter->hash, filter_hash); 6545 mutex_unlock(&ftrace_lock); 6546 } 6547 6548 mutex_unlock(&iter->ops->func_hash->regex_lock);
+1 -1
kernel/trace/ring_buffer.c
··· 7666 rb_test_started = true; 7667 7668 set_current_state(TASK_INTERRUPTIBLE); 7669 - /* Just run for 10 seconds */; 7670 schedule_timeout(10 * HZ); 7671 7672 kthread_stop(rb_hammer);
··· 7666 rb_test_started = true; 7667 7668 set_current_state(TASK_INTERRUPTIBLE); 7669 + /* Just run for 10 seconds */ 7670 schedule_timeout(10 * HZ); 7671 7672 kthread_stop(rb_hammer);
+14 -8
kernel/trace/trace.c
··· 1816 1817 ret = get_user(ch, ubuf++); 1818 if (ret) 1819 - return ret; 1820 1821 read++; 1822 cnt--; ··· 1830 while (cnt && isspace(ch)) { 1831 ret = get_user(ch, ubuf++); 1832 if (ret) 1833 - return ret; 1834 read++; 1835 cnt--; 1836 } ··· 1848 while (cnt && !isspace(ch) && ch) { 1849 if (parser->idx < parser->size - 1) 1850 parser->buffer[parser->idx++] = ch; 1851 - else 1852 - return -EINVAL; 1853 1854 ret = get_user(ch, ubuf++); 1855 if (ret) 1856 - return ret; 1857 read++; 1858 cnt--; 1859 } ··· 1870 /* Make sure the parsed string always terminates with '\0'. */ 1871 parser->buffer[parser->idx] = 0; 1872 } else { 1873 - return -EINVAL; 1874 } 1875 1876 *ppos += read; 1877 return read; 1878 } 1879 1880 /* TODO add a seq_buf_to_buffer() */ ··· 10638 ret = print_trace_line(&iter); 10639 if (ret != TRACE_TYPE_NO_CONSUME) 10640 trace_consume(&iter); 10641 } 10642 touch_nmi_watchdog(); 10643 - 10644 - trace_printk_seq(&iter.seq); 10645 } 10646 10647 if (!cnt)
··· 1816 1817 ret = get_user(ch, ubuf++); 1818 if (ret) 1819 + goto fail; 1820 1821 read++; 1822 cnt--; ··· 1830 while (cnt && isspace(ch)) { 1831 ret = get_user(ch, ubuf++); 1832 if (ret) 1833 + goto fail; 1834 read++; 1835 cnt--; 1836 } ··· 1848 while (cnt && !isspace(ch) && ch) { 1849 if (parser->idx < parser->size - 1) 1850 parser->buffer[parser->idx++] = ch; 1851 + else { 1852 + ret = -EINVAL; 1853 + goto fail; 1854 + } 1855 1856 ret = get_user(ch, ubuf++); 1857 if (ret) 1858 + goto fail; 1859 read++; 1860 cnt--; 1861 } ··· 1868 /* Make sure the parsed string always terminates with '\0'. */ 1869 parser->buffer[parser->idx] = 0; 1870 } else { 1871 + ret = -EINVAL; 1872 + goto fail; 1873 } 1874 1875 *ppos += read; 1876 return read; 1877 + fail: 1878 + trace_parser_fail(parser); 1879 + return ret; 1880 } 1881 1882 /* TODO add a seq_buf_to_buffer() */ ··· 10632 ret = print_trace_line(&iter); 10633 if (ret != TRACE_TYPE_NO_CONSUME) 10634 trace_consume(&iter); 10635 + 10636 + trace_printk_seq(&iter.seq); 10637 } 10638 touch_nmi_watchdog(); 10639 } 10640 10641 if (!cnt)
+7 -1
kernel/trace/trace.h
··· 1292 */ 1293 struct trace_parser { 1294 bool cont; 1295 char *buffer; 1296 unsigned idx; 1297 unsigned size; ··· 1300 1301 static inline bool trace_parser_loaded(struct trace_parser *parser) 1302 { 1303 - return (parser->idx != 0); 1304 } 1305 1306 static inline bool trace_parser_cont(struct trace_parser *parser) ··· 1312 { 1313 parser->cont = false; 1314 parser->idx = 0; 1315 } 1316 1317 extern int trace_parser_get_init(struct trace_parser *parser, int size);
··· 1292 */ 1293 struct trace_parser { 1294 bool cont; 1295 + bool fail; 1296 char *buffer; 1297 unsigned idx; 1298 unsigned size; ··· 1299 1300 static inline bool trace_parser_loaded(struct trace_parser *parser) 1301 { 1302 + return !parser->fail && parser->idx != 0; 1303 } 1304 1305 static inline bool trace_parser_cont(struct trace_parser *parser) ··· 1311 { 1312 parser->cont = false; 1313 parser->idx = 0; 1314 + } 1315 + 1316 + static inline void trace_parser_fail(struct trace_parser *parser) 1317 + { 1318 + parser->fail = true; 1319 } 1320 1321 extern int trace_parser_get_init(struct trace_parser *parser, int size);
+16 -6
kernel/trace/trace_functions_graph.c
··· 27 unsigned long enter_funcs[FTRACE_RETFUNC_DEPTH]; 28 }; 29 30 struct fgraph_data { 31 struct fgraph_cpu_data __percpu *cpu_data; 32 33 /* Place to preserve last processed entry. */ 34 union { 35 - struct ftrace_graph_ent_entry ent; 36 struct fgraph_retaddr_ent_entry rent; 37 - } ent; 38 struct ftrace_graph_ret_entry ret; 39 int failed; 40 int cpu; ··· 634 * Save current and next entries for later reference 635 * if the output fails. 636 */ 637 - if (unlikely(curr->ent.type == TRACE_GRAPH_RETADDR_ENT)) 638 - data->ent.rent = *(struct fgraph_retaddr_ent_entry *)curr; 639 - else 640 - data->ent.ent = *curr; 641 /* 642 * If the next event is not a return type, then 643 * we only care about what type it is. Otherwise we can
··· 27 unsigned long enter_funcs[FTRACE_RETFUNC_DEPTH]; 28 }; 29 30 + struct fgraph_ent_args { 31 + struct ftrace_graph_ent_entry ent; 32 + /* Force the sizeof of args[] to have FTRACE_REGS_MAX_ARGS entries */ 33 + unsigned long args[FTRACE_REGS_MAX_ARGS]; 34 + }; 35 + 36 struct fgraph_data { 37 struct fgraph_cpu_data __percpu *cpu_data; 38 39 /* Place to preserve last processed entry. */ 40 union { 41 + struct fgraph_ent_args ent; 42 + /* TODO allow retaddr to have args */ 43 struct fgraph_retaddr_ent_entry rent; 44 + }; 45 struct ftrace_graph_ret_entry ret; 46 int failed; 47 int cpu; ··· 627 * Save current and next entries for later reference 628 * if the output fails. 629 */ 630 + if (unlikely(curr->ent.type == TRACE_GRAPH_RETADDR_ENT)) { 631 + data->rent = *(struct fgraph_retaddr_ent_entry *)curr; 632 + } else { 633 + int size = min((int)sizeof(data->ent), (int)iter->ent_size); 634 + 635 + memcpy(&data->ent, curr, size); 636 + } 637 /* 638 * If the next event is not a return type, then 639 * we only care about what type it is. Otherwise we can
+8
tools/tracing/latency/Makefile.config
··· 1 # SPDX-License-Identifier: GPL-2.0-only 2 3 STOP_ERROR := 4 5 define lib_setup 6 $(eval LIB_INCLUDES += $(shell sh -c "$(PKG_CONFIG) --cflags lib$(1)"))
··· 1 # SPDX-License-Identifier: GPL-2.0-only 2 3 + include $(srctree)/tools/scripts/utilities.mak 4 + 5 STOP_ERROR := 6 + 7 + ifndef ($(NO_LIBTRACEEVENT),1) 8 + ifeq ($(call get-executable,$(PKG_CONFIG)),) 9 + $(error Error: $(PKG_CONFIG) needed by libtraceevent/libtracefs is missing on this system, please install it) 10 + endif 11 + endif 12 13 define lib_setup 14 $(eval LIB_INCLUDES += $(shell sh -c "$(PKG_CONFIG) --cflags lib$(1)"))
+8
tools/tracing/rtla/Makefile.config
··· 1 # SPDX-License-Identifier: GPL-2.0-only 2 3 STOP_ERROR := 4 5 LIBTRACEEVENT_MIN_VERSION = 1.5 6 LIBTRACEFS_MIN_VERSION = 1.6 7 8 define lib_setup 9 $(eval LIB_INCLUDES += $(shell sh -c "$(PKG_CONFIG) --cflags lib$(1)"))
··· 1 # SPDX-License-Identifier: GPL-2.0-only 2 3 + include $(srctree)/tools/scripts/utilities.mak 4 + 5 STOP_ERROR := 6 7 LIBTRACEEVENT_MIN_VERSION = 1.5 8 LIBTRACEFS_MIN_VERSION = 1.6 9 + 10 + ifndef ($(NO_LIBTRACEEVENT),1) 11 + ifeq ($(call get-executable,$(PKG_CONFIG)),) 12 + $(error Error: $(PKG_CONFIG) needed by libtraceevent/libtracefs is missing on this system, please install it) 13 + endif 14 + endif 15 16 define lib_setup 17 $(eval LIB_INCLUDES += $(shell sh -c "$(PKG_CONFIG) --cflags lib$(1)"))