workqueue/tracing: Copy workqueue name to buffer in trace event
authorSteven Rostedt (VMware) <rostedt@goodmis.org>
Thu, 18 Mar 2021 15:44:08 +0000 (11:44 -0400)
committerSteven Rostedt (VMware) <rostedt@goodmis.org>
Thu, 18 Mar 2021 16:57:37 +0000 (12:57 -0400)
The trace event "workqueue_queue_work" references an unsafe string in
dereferencing the name of the workqueue. As the name is allocated, it
could later be freed, and the pointer to that string could stay on the
tracing buffer. If the trace buffer is read after the string is freed, it
will reference an unsafe pointer.

I added a new verifier to make sure that all strings referenced in the
output of the trace buffer is safe to read and this triggered on the
workqueue_queue_work trace event:

workqueue_queue_work: work struct=00000000b2b235c7 function=gc_worker workqueue=(0xffff888100051160:events_power_efficient)[UNSAFE-MEMORY] req_cpu=256 cpu=1
workqueue_queue_work: work struct=00000000c344caec function=flush_to_ldisc workqueue=(0xffff888100054d60:events_unbound)[UNSAFE-MEMORY] req_cpu=256 cpu=4294967295
workqueue_queue_work: work struct=00000000b2b235c7 function=gc_worker workqueue=(0xffff888100051160:events_power_efficient)[UNSAFE-MEMORY] req_cpu=256 cpu=1
workqueue_queue_work: work struct=000000000b238b3f function=vmstat_update workqueue=(0xffff8881000c3760:mm_percpu_wq)[UNSAFE-MEMORY] req_cpu=1 cpu=1

Also, if this event is read via a user space application like perf or
trace-cmd, the name would only be an address and useless information:

workqueue_queue_work: work struct=0xffff953f80b4b918 function=disk_events_workfn workqueue=ffff953f8005d378 req_cpu=8192 cpu=5

Cc: Zqiang <qiang.zhang@windriver.com>
Cc: Tejun Heo <tj@kernel.org>
Fixes: 7bf9c4a88e3e3 ("workqueue: tracing the name of the workqueue instead of it's address")
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
include/trace/events/workqueue.h

index 970cc2e..6154a2e 100644 (file)
@@ -30,7 +30,7 @@ TRACE_EVENT(workqueue_queue_work,
        TP_STRUCT__entry(
                __field( void *,        work    )
                __field( void *,        function)
-               __field( const char *,  workqueue)
+               __string( workqueue,    pwq->wq->name)
                __field( unsigned int,  req_cpu )
                __field( unsigned int,  cpu     )
        ),
@@ -38,13 +38,13 @@ TRACE_EVENT(workqueue_queue_work,
        TP_fast_assign(
                __entry->work           = work;
                __entry->function       = work->func;
-               __entry->workqueue      = pwq->wq->name;
+               __assign_str(workqueue, pwq->wq->name);
                __entry->req_cpu        = req_cpu;
                __entry->cpu            = pwq->pool->cpu;
        ),
 
        TP_printk("work struct=%p function=%ps workqueue=%s req_cpu=%u cpu=%u",
-                 __entry->work, __entry->function, __entry->workqueue,
+                 __entry->work, __entry->function, __get_str(workqueue),
                  __entry->req_cpu, __entry->cpu)
 );