]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
libperf evlist: Avoid out-of-bounds access
authorIan Rogers <irogers@google.com>
Thu, 29 Feb 2024 07:07:57 +0000 (23:07 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 13 Apr 2024 11:01:45 +0000 (13:01 +0200)
[ Upstream commit 1947b92464c3268381604bbe2ac977a3fd78192f ]

Parallel testing appears to show a race between allocating and setting
evsel ids. As there is a bounds check on the xyarray it yields a segv
like:

```
AddressSanitizer:DEADLYSIGNAL

=================================================================

==484408==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000010

==484408==The signal is caused by a WRITE memory access.

==484408==Hint: address points to the zero page.

    #0 0x55cef5d4eff4 in perf_evlist__id_hash tools/lib/perf/evlist.c:256
    #1 0x55cef5d4f132 in perf_evlist__id_add tools/lib/perf/evlist.c:274
    #2 0x55cef5d4f545 in perf_evlist__id_add_fd tools/lib/perf/evlist.c:315
    #3 0x55cef5a1923f in store_evsel_ids util/evsel.c:3130
    #4 0x55cef5a19400 in evsel__store_ids util/evsel.c:3147
    #5 0x55cef5888204 in __run_perf_stat tools/perf/builtin-stat.c:832
    #6 0x55cef5888c06 in run_perf_stat tools/perf/builtin-stat.c:960
    #7 0x55cef58932db in cmd_stat tools/perf/builtin-stat.c:2878
...
```

Avoid this crash by early exiting the perf_evlist__id_add_fd and
perf_evlist__id_add is the access is out-of-bounds.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Yang Jihong <yangjihong1@huawei.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/r/20240229070757.796244-1-irogers@google.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
tools/lib/perf/evlist.c
tools/lib/perf/include/internal/evlist.h

index 5146ff0fa078c5189cc3de503402649d28201fd0..6aa1c35273a182c6f1b5897ddb69c726532b8cb1 100644 (file)
@@ -224,10 +224,10 @@ u64 perf_evlist__read_format(struct perf_evlist *evlist)
 
 static void perf_evlist__id_hash(struct perf_evlist *evlist,
                                 struct perf_evsel *evsel,
-                                int cpu, int thread, u64 id)
+                                int cpu_map_idx, int thread, u64 id)
 {
        int hash;
-       struct perf_sample_id *sid = SID(evsel, cpu, thread);
+       struct perf_sample_id *sid = SID(evsel, cpu_map_idx, thread);
 
        sid->id = id;
        sid->evsel = evsel;
@@ -245,21 +245,27 @@ void perf_evlist__reset_id_hash(struct perf_evlist *evlist)
 
 void perf_evlist__id_add(struct perf_evlist *evlist,
                         struct perf_evsel *evsel,
-                        int cpu, int thread, u64 id)
+                        int cpu_map_idx, int thread, u64 id)
 {
-       perf_evlist__id_hash(evlist, evsel, cpu, thread, id);
+       if (!SID(evsel, cpu_map_idx, thread))
+               return;
+
+       perf_evlist__id_hash(evlist, evsel, cpu_map_idx, thread, id);
        evsel->id[evsel->ids++] = id;
 }
 
 int perf_evlist__id_add_fd(struct perf_evlist *evlist,
                           struct perf_evsel *evsel,
-                          int cpu, int thread, int fd)
+                          int cpu_map_idx, int thread, int fd)
 {
        u64 read_data[4] = { 0, };
        int id_idx = 1; /* The first entry is the counter value */
        u64 id;
        int ret;
 
+       if (!SID(evsel, cpu_map_idx, thread))
+               return -1;
+
        ret = ioctl(fd, PERF_EVENT_IOC_ID, &id);
        if (!ret)
                goto add;
@@ -288,7 +294,7 @@ int perf_evlist__id_add_fd(struct perf_evlist *evlist,
        id = read_data[id_idx];
 
 add:
-       perf_evlist__id_add(evlist, evsel, cpu, thread, id);
+       perf_evlist__id_add(evlist, evsel, cpu_map_idx, thread, id);
        return 0;
 }
 
index f366dbad6a88ca92221980e084360854ae665c18..49b17b2b3923f525d66b3b1d9c471177e1a501ca 100644 (file)
@@ -119,11 +119,11 @@ u64 perf_evlist__read_format(struct perf_evlist *evlist);
 
 void perf_evlist__id_add(struct perf_evlist *evlist,
                         struct perf_evsel *evsel,
-                        int cpu, int thread, u64 id);
+                        int cpu_map_idx, int thread, u64 id);
 
 int perf_evlist__id_add_fd(struct perf_evlist *evlist,
                           struct perf_evsel *evsel,
-                          int cpu, int thread, int fd);
+                          int cpu_map_idx, int thread, int fd);
 
 void perf_evlist__reset_id_hash(struct perf_evlist *evlist);