]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
tracing: Fix memleak due to race between current_tracer and trace
authorZheng Yejian <zhengyejian1@huawei.com>
Thu, 17 Aug 2023 12:55:39 +0000 (20:55 +0800)
committerStefan Bader <stefan.bader@canonical.com>
Mon, 30 Oct 2023 11:00:23 +0000 (12:00 +0100)
BugLink: https://bugs.launchpad.net/bugs/2039742
[ Upstream commit eecb91b9f98d6427d4af5fdb8f108f52572a39e7 ]

Kmemleak report a leak in graph_trace_open():

  unreferenced object 0xffff0040b95f4a00 (size 128):
    comm "cat", pid 204981, jiffies 4301155872 (age 99771.964s)
    hex dump (first 32 bytes):
      e0 05 e7 b4 ab 7d 00 00 0b 00 01 00 00 00 00 00 .....}..........
      f4 00 01 10 00 a0 ff ff 00 00 00 00 65 00 10 00 ............e...
    backtrace:
      [<000000005db27c8b>] kmem_cache_alloc_trace+0x348/0x5f0
      [<000000007df90faa>] graph_trace_open+0xb0/0x344
      [<00000000737524cd>] __tracing_open+0x450/0xb10
      [<0000000098043327>] tracing_open+0x1a0/0x2a0
      [<00000000291c3876>] do_dentry_open+0x3c0/0xdc0
      [<000000004015bcd6>] vfs_open+0x98/0xd0
      [<000000002b5f60c9>] do_open+0x520/0x8d0
      [<00000000376c7820>] path_openat+0x1c0/0x3e0
      [<00000000336a54b5>] do_filp_open+0x14c/0x324
      [<000000002802df13>] do_sys_openat2+0x2c4/0x530
      [<0000000094eea458>] __arm64_sys_openat+0x130/0x1c4
      [<00000000a71d7881>] el0_svc_common.constprop.0+0xfc/0x394
      [<00000000313647bf>] do_el0_svc+0xac/0xec
      [<000000002ef1c651>] el0_svc+0x20/0x30
      [<000000002fd4692a>] el0_sync_handler+0xb0/0xb4
      [<000000000c309c35>] el0_sync+0x160/0x180

The root cause is descripted as follows:

  __tracing_open() {  // 1. File 'trace' is being opened;
    ...
    *iter->trace = *tr->current_trace;  // 2. Tracer 'function_graph' is
                                        //    currently set;
    ...
    iter->trace->open(iter);  // 3. Call graph_trace_open() here,
                              //    and memory are allocated in it;
    ...
  }

  s_start() {  // 4. The opened file is being read;
    ...
    *iter->trace = *tr->current_trace;  // 5. If tracer is switched to
                                        //    'nop' or others, then memory
                                        //    in step 3 are leaked!!!
    ...
  }

To fix it, in s_start(), close tracer before switching then reopen the
new tracer after switching. And some tracers like 'wakeup' may not update
'iter->private' in some cases when reopen, then it should be cleared
to avoid being mistakenly closed again.

Link: https://lore.kernel.org/linux-trace-kernel/20230817125539.1646321-1-zhengyejian1@huawei.com
Fixes: d7350c3f4569 ("tracing/core: make the read callbacks reentrants")
Signed-off-by: Zheng Yejian <zhengyejian1@huawei.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
kernel/trace/trace.c
kernel/trace/trace_irqsoff.c
kernel/trace/trace_sched_wakeup.c

index 6aeb5a19205cc823d1d01f50306bf47e8d10b368..155a47c8ab6a3428d426d7c13d8b510f31b0adff 100644 (file)
@@ -4127,8 +4127,15 @@ static void *s_start(struct seq_file *m, loff_t *pos)
         * will point to the same string as current_trace->name.
         */
        mutex_lock(&trace_types_lock);
-       if (unlikely(tr->current_trace && iter->trace->name != tr->current_trace->name))
+       if (unlikely(tr->current_trace && iter->trace->name != tr->current_trace->name)) {
+               /* Close iter->trace before switching to the new current tracer */
+               if (iter->trace->close)
+                       iter->trace->close(iter);
                *iter->trace = *tr->current_trace;
+               /* Reopen the new current tracer */
+               if (iter->trace->open)
+                       iter->trace->open(iter);
+       }
        mutex_unlock(&trace_types_lock);
 
 #ifdef CONFIG_TRACER_MAX_TRACE
index 590b3d51afae987acd0c3ee989a616b672dafa43..ba37f768e2f273e748d84270f0ff1dc9e5ba79f2 100644 (file)
@@ -231,7 +231,8 @@ static void irqsoff_trace_open(struct trace_iterator *iter)
 {
        if (is_graph(iter->tr))
                graph_trace_open(iter);
-
+       else
+               iter->private = NULL;
 }
 
 static void irqsoff_trace_close(struct trace_iterator *iter)
index 330aee1c1a49e6804df4c4ce7389282c126f4922..0469a04a355f2c3a7206bf0b733a50a37013f6e1 100644 (file)
@@ -168,6 +168,8 @@ static void wakeup_trace_open(struct trace_iterator *iter)
 {
        if (is_graph(iter->tr))
                graph_trace_open(iter);
+       else
+               iter->private = NULL;
 }
 
 static void wakeup_trace_close(struct trace_iterator *iter)