Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf dso: Hold lock when accessing nsinfo

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>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
e54dea69 d8e40b58

+28 -5
+4
tools/perf/builtin-inject.c
··· 436 436 } 437 437 438 438 if (dso) { 439 + mutex_lock(&dso->lock); 439 440 nsinfo__put(dso->nsinfo); 440 441 dso->nsinfo = nsi; 442 + mutex_unlock(&dso->lock); 441 443 } else 442 444 nsinfo__put(nsi); 443 445 ··· 622 620 if (dso->has_build_id) 623 621 return 0; 624 622 623 + mutex_lock(&dso->lock); 625 624 nsinfo__mountns_enter(dso->nsinfo, &nsc); 626 625 if (filename__read_build_id(dso->long_name, &dso->bid) > 0) 627 626 dso->has_build_id = true; ··· 636 633 free(new_name); 637 634 } 638 635 nsinfo__mountns_exit(&nsc); 636 + mutex_unlock(&dso->lock); 639 637 640 638 return dso->has_build_id ? 0 : -1; 641 639 }
+2
tools/perf/util/annotate.c
··· 1697 1697 */ 1698 1698 __symbol__join_symfs(filename, filename_size, dso->long_name); 1699 1699 1700 + mutex_lock(&dso->lock); 1700 1701 if (access(filename, R_OK) && errno == ENOENT && dso->nsinfo) { 1701 1702 char *new_name = filename_with_chroot(dso->nsinfo->pid, 1702 1703 filename); ··· 1706 1705 free(new_name); 1707 1706 } 1708 1707 } 1708 + mutex_unlock(&dso->lock); 1709 1709 } 1710 1710 1711 1711 free(build_id_path);
+9 -3
tools/perf/util/build-id.c
··· 898 898 static bool dso__build_id_mismatch(struct dso *dso, const char *name) 899 899 { 900 900 struct build_id bid; 901 + bool ret = false; 901 902 902 - if (filename__read_build_id_ns(name, &bid, dso->nsinfo) < 0) 903 - return false; 903 + mutex_lock(&dso->lock); 904 + if (filename__read_build_id_ns(name, &bid, dso->nsinfo) >= 0) 905 + ret = !dso__build_id_equal(dso, &bid); 904 906 905 - return !dso__build_id_equal(dso, &bid); 907 + mutex_unlock(&dso->lock); 908 + 909 + return ret; 906 910 } 907 911 908 912 static int dso__cache_build_id(struct dso *dso, struct machine *machine, ··· 945 941 if (!is_kallsyms && dso__build_id_mismatch(dso, name)) 946 942 goto out_free; 947 943 944 + mutex_lock(&dso->lock); 948 945 ret = build_id_cache__add_b(&dso->bid, name, dso->nsinfo, 949 946 is_kallsyms, is_vdso, proper_name, root_dir); 947 + mutex_unlock(&dso->lock); 950 948 out_free: 951 949 free(allocated_name); 952 950 return ret;
+6 -1
tools/perf/util/dso.c
··· 501 501 if (!name) 502 502 return -ENOMEM; 503 503 504 + mutex_lock(&dso->lock); 504 505 if (machine) 505 506 root_dir = machine->root_dir; 506 507 ··· 542 541 unlink(name); 543 542 544 543 out: 544 + mutex_unlock(&dso->lock); 545 545 free(name); 546 546 return fd; 547 547 } ··· 561 559 int fd; 562 560 struct nscookie nsc; 563 561 564 - if (dso->binary_type != DSO_BINARY_TYPE__BUILD_ID_CACHE) 562 + if (dso->binary_type != DSO_BINARY_TYPE__BUILD_ID_CACHE) { 563 + mutex_lock(&dso->lock); 565 564 nsinfo__mountns_enter(dso->nsinfo, &nsc); 565 + mutex_unlock(&dso->lock); 566 + } 566 567 fd = __open_dso(dso, machine); 567 568 if (dso->binary_type != DSO_BINARY_TYPE__BUILD_ID_CACHE) 568 569 nsinfo__mountns_exit(&nsc);
+3
tools/perf/util/map.c
··· 181 181 if (!(prot & PROT_EXEC)) 182 182 dso__set_loaded(dso); 183 183 } 184 + mutex_lock(&dso->lock); 185 + nsinfo__put(dso->nsinfo); 184 186 dso->nsinfo = nsi; 187 + mutex_unlock(&dso->lock); 185 188 186 189 if (build_id__is_defined(bid)) { 187 190 dso__set_build_id(dso, bid);
+3
tools/perf/util/probe-event.c
··· 29 29 #include "color.h" 30 30 #include "map.h" 31 31 #include "maps.h" 32 + #include "mutex.h" 32 33 #include "symbol.h" 33 34 #include <api/fs/fs.h> 34 35 #include "trace-event.h" /* For __maybe_unused */ ··· 181 180 182 181 map = dso__new_map(target); 183 182 if (map && map->dso) { 183 + mutex_lock(&map->dso->lock); 184 184 nsinfo__put(map->dso->nsinfo); 185 185 map->dso->nsinfo = nsinfo__get(nsi); 186 + mutex_unlock(&map->dso->lock); 186 187 } 187 188 return map; 188 189 } else {
+1 -1
tools/perf/util/symbol.c
··· 1791 1791 char newmapname[PATH_MAX]; 1792 1792 const char *map_path = dso->long_name; 1793 1793 1794 + mutex_lock(&dso->lock); 1794 1795 perfmap = strncmp(dso->name, "/tmp/perf-", 10) == 0; 1795 1796 if (perfmap) { 1796 1797 if (dso->nsinfo && (dso__find_perf_map(newmapname, ··· 1801 1800 } 1802 1801 1803 1802 nsinfo__mountns_enter(dso->nsinfo, &nsc); 1804 - mutex_lock(&dso->lock); 1805 1803 1806 1804 /* check again under the dso->lock */ 1807 1805 if (dso__loaded(dso)) {