perf dso: Hold lock when accessing nsinfo
authorIan Rogers <irogers@google.com>
Fri, 26 Aug 2022 16:42:38 +0000 (09:42 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Tue, 4 Oct 2022 11:55:20 +0000 (08:55 -0300)
There may be threads racing to update dso->nsinfo:

  https://lore.kernel.org/linux-perf-users/CAP-5=fWZH20L4kv-BwVtGLwR=Em3AOOT+Q4QGivvQuYn5AsPRg@mail.gmail.com/

Holding the dso->lock avoids use-after-free, memory leaks and other such
bugs. Apply the fix in:

  https://lore.kernel.org/linux-perf-users/20211118193714.2293728-1-irogers@google.com/

of there being a missing nsinfo__put now that the accesses are data race
free. Fixes test "Lookup mmap thread" when compiled with address
sanitizer.

Signed-off-by: Ian Rogers <irogers@google.com>
Reviewed-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexandre Truong <alexandre.truong@arm.com>
Cc: Alexey Bayduraev <alexey.v.bayduraev@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Andres Freund <andres@anarazel.de>
Cc: Andrii Nakryiko <andrii@kernel.org>
Cc: André Almeida <andrealmeid@igalia.com>
Cc: Athira Jajeev <atrajeev@linux.vnet.ibm.com>
Cc: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
Cc: Colin Ian King <colin.king@intel.com>
Cc: Dario Petrillo <dario.pk1@gmail.com>
Cc: Darren Hart <dvhart@infradead.org>
Cc: Dave Marchevsky <davemarchevsky@fb.com>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Fangrui Song <maskray@google.com>
Cc: Hewenliang <hewenliang4@huawei.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jason Wang <wangborong@cdjrlc.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kajol Jain <kjain@linux.ibm.com>
Cc: Kim Phillips <kim.phillips@amd.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Martin Liška <mliska@suse.cz>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Pavithra Gurushankar <gpavithrasha@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Monnet <quentin@isovalent.com>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Remi Bernon <rbernon@codeweavers.com>
Cc: Riccardo Mancini <rickyman7@gmail.com>
Cc: Song Liu <songliubraving@fb.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Cc: Tom Rix <trix@redhat.com>
Cc: Weiguo Li <liwg06@foxmail.com>
Cc: Wenyu Liu <liuwenyu7@huawei.com>
Cc: William Cohen <wcohen@redhat.com>
Cc: Zechuan Chen <chenzechuan1@huawei.com>
Cc: bpf@vger.kernel.org
Cc: llvm@lists.linux.dev
Cc: yaowenbin <yaowenbin1@huawei.com>
Link: https://lore.kernel.org/r/20220826164242.43412-15-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/builtin-inject.c
tools/perf/util/annotate.c
tools/perf/util/build-id.c
tools/perf/util/dso.c
tools/perf/util/map.c
tools/perf/util/probe-event.c
tools/perf/util/symbol.c

index 8ec9554..e254f18 100644 (file)
@@ -436,8 +436,10 @@ static struct dso *findnew_dso(int pid, int tid, const char *filename,
        }
 
        if (dso) {
+               mutex_lock(&dso->lock);
                nsinfo__put(dso->nsinfo);
                dso->nsinfo = nsi;
+               mutex_unlock(&dso->lock);
        } else
                nsinfo__put(nsi);
 
@@ -620,6 +622,7 @@ static int dso__read_build_id(struct dso *dso)
        if (dso->has_build_id)
                return 0;
 
+       mutex_lock(&dso->lock);
        nsinfo__mountns_enter(dso->nsinfo, &nsc);
        if (filename__read_build_id(dso->long_name, &dso->bid) > 0)
                dso->has_build_id = true;
@@ -633,6 +636,7 @@ static int dso__read_build_id(struct dso *dso)
                free(new_name);
        }
        nsinfo__mountns_exit(&nsc);
+       mutex_unlock(&dso->lock);
 
        return dso->has_build_id ? 0 : -1;
 }
index 9d7dd64..5bc63c9 100644 (file)
@@ -1697,6 +1697,7 @@ fallback:
                 */
                __symbol__join_symfs(filename, filename_size, dso->long_name);
 
+               mutex_lock(&dso->lock);
                if (access(filename, R_OK) && errno == ENOENT && dso->nsinfo) {
                        char *new_name = filename_with_chroot(dso->nsinfo->pid,
                                                              filename);
@@ -1705,6 +1706,7 @@ fallback:
                                free(new_name);
                        }
                }
+               mutex_unlock(&dso->lock);
        }
 
        free(build_id_path);
index ec18ed5..a839b30 100644 (file)
@@ -898,11 +898,15 @@ static int filename__read_build_id_ns(const char *filename,
 static bool dso__build_id_mismatch(struct dso *dso, const char *name)
 {
        struct build_id bid;
+       bool ret = false;
 
-       if (filename__read_build_id_ns(name, &bid, dso->nsinfo) < 0)
-               return false;
+       mutex_lock(&dso->lock);
+       if (filename__read_build_id_ns(name, &bid, dso->nsinfo) >= 0)
+               ret = !dso__build_id_equal(dso, &bid);
 
-       return !dso__build_id_equal(dso, &bid);
+       mutex_unlock(&dso->lock);
+
+       return ret;
 }
 
 static int dso__cache_build_id(struct dso *dso, struct machine *machine,
@@ -941,8 +945,10 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine,
        if (!is_kallsyms && dso__build_id_mismatch(dso, name))
                goto out_free;
 
+       mutex_lock(&dso->lock);
        ret = build_id_cache__add_b(&dso->bid, name, dso->nsinfo,
                                    is_kallsyms, is_vdso, proper_name, root_dir);
+       mutex_unlock(&dso->lock);
 out_free:
        free(allocated_name);
        return ret;
index a9789a9..f1a14c0 100644 (file)
@@ -501,6 +501,7 @@ static int __open_dso(struct dso *dso, struct machine *machine)
        if (!name)
                return -ENOMEM;
 
+       mutex_lock(&dso->lock);
        if (machine)
                root_dir = machine->root_dir;
 
@@ -541,6 +542,7 @@ static int __open_dso(struct dso *dso, struct machine *machine)
                unlink(name);
 
 out:
+       mutex_unlock(&dso->lock);
        free(name);
        return fd;
 }
@@ -559,8 +561,11 @@ static int open_dso(struct dso *dso, struct machine *machine)
        int fd;
        struct nscookie nsc;
 
-       if (dso->binary_type != DSO_BINARY_TYPE__BUILD_ID_CACHE)
+       if (dso->binary_type != DSO_BINARY_TYPE__BUILD_ID_CACHE) {
+               mutex_lock(&dso->lock);
                nsinfo__mountns_enter(dso->nsinfo, &nsc);
+               mutex_unlock(&dso->lock);
+       }
        fd = __open_dso(dso, machine);
        if (dso->binary_type != DSO_BINARY_TYPE__BUILD_ID_CACHE)
                nsinfo__mountns_exit(&nsc);
index e0aa4a2..f3a3d9b 100644 (file)
@@ -181,7 +181,10 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
                        if (!(prot & PROT_EXEC))
                                dso__set_loaded(dso);
                }
+               mutex_lock(&dso->lock);
+               nsinfo__put(dso->nsinfo);
                dso->nsinfo = nsi;
+               mutex_unlock(&dso->lock);
 
                if (build_id__is_defined(bid)) {
                        dso__set_build_id(dso, bid);
index 785246f..0c24bc7 100644 (file)
@@ -29,6 +29,7 @@
 #include "color.h"
 #include "map.h"
 #include "maps.h"
+#include "mutex.h"
 #include "symbol.h"
 #include <api/fs/fs.h>
 #include "trace-event.h"       /* For __maybe_unused */
@@ -180,8 +181,10 @@ struct map *get_target_map(const char *target, struct nsinfo *nsi, bool user)
 
                map = dso__new_map(target);
                if (map && map->dso) {
+                       mutex_lock(&map->dso->lock);
                        nsinfo__put(map->dso->nsinfo);
                        map->dso->nsinfo = nsinfo__get(nsi);
+                       mutex_unlock(&map->dso->lock);
                }
                return map;
        } else {
index 656d9b4..a3a165a 100644 (file)
@@ -1791,6 +1791,7 @@ int dso__load(struct dso *dso, struct map *map)
        char newmapname[PATH_MAX];
        const char *map_path = dso->long_name;
 
+       mutex_lock(&dso->lock);
        perfmap = strncmp(dso->name, "/tmp/perf-", 10) == 0;
        if (perfmap) {
                if (dso->nsinfo && (dso__find_perf_map(newmapname,
@@ -1800,7 +1801,6 @@ int dso__load(struct dso *dso, struct map *map)
        }
 
        nsinfo__mountns_enter(dso->nsinfo, &nsc);
-       mutex_lock(&dso->lock);
 
        /* check again under the dso->lock */
        if (dso__loaded(dso)) {