History

libperf evsel: Make use of FD robust.

FD uses xyarray__entry that may return NULL if an index is out of bounds. If NULL is returned then a segv happens as FD unconditionally dereferences the pointer. This was happening in a case of with perf iostat as shown below. The fix is to make FD an "int*" rather than an int and handle the NULL case as either invalid input or a closed fd. $ sudo gdb --args perf stat --iostat list ... Breakpoint 1, perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50 50 { (gdb) bt #0 perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50 #1 0x000055555585c188 in evsel__open_cpu (evsel=0x5555560951a0, cpus=0x555556093410, threads=0x555556086fb0, start_cpu=0, end_cpu=1) at util/evsel.c:1792 #2 0x000055555585cfb2 in evsel__open (evsel=0x5555560951a0, cpus=0x0, threads=0x555556086fb0) at util/evsel.c:2045 #3 0x000055555585d0db in evsel__open_per_thread (evsel=0x5555560951a0, threads=0x555556086fb0) at util/evsel.c:2065 #4 0x00005555558ece64 in create_perf_stat_counter (evsel=0x5555560951a0, config=0x555555c34700 <stat_config>, target=0x555555c2f1c0 <target>, cpu=0) at util/stat.c:590 #5 0x000055555578e927 in __run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0) at builtin-stat.c:833 #6 0x000055555578f3c6 in run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0) at builtin-stat.c:1048 #7 0x0000555555792ee5 in cmd_stat (argc=1, argv=0x7fffffffe4a0) at builtin-stat.c:2534 #8 0x0000555555835ed3 in run_builtin (p=0x555555c3f540 <commands+288>, argc=3, argv=0x7fffffffe4a0) at perf.c:313 #9 0x0000555555836154 in handle_internal_command (argc=3, argv=0x7fffffffe4a0) at perf.c:365 #10 0x000055555583629f in run_argv (argcp=0x7fffffffe2ec, argv=0x7fffffffe2e0) at perf.c:409 #11 0x0000555555836692 in main (argc=3, argv=0x7fffffffe4a0) at perf.c:539 ... (gdb) c Continuing. Error: The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (uncore_iio_0/event=0x83,umask=0x04,ch_mask=0xF,fc_mask=0x07/). /bin/dmesg | grep -i perf may provide additional information. Program received signal SIGSEGV, Segmentation fault. 0x00005555559b03ea in perf_evsel__close_fd_cpu (evsel=0x5555560951a0, cpu=1) at evsel.c:166 166 if (FD(evsel, cpu, thread) >= 0) v3. fixes a bug in perf_evsel__run_ioctl where the sense of a branch was backward.

Ian Rogers committed 5 years ago

Commit aba5dae1 parent 57f0ff01 file · +41 −23Browse files

Unified · Split

tools/lib/perf/evsel.c+41−23
@@ -43,7 +43,7 @@ void perf_evsel__delete(struct perf_evsel *evsel) · 42 unmodified lines
4343 free(evsel);
4444 }
4545
46−#define FD(e, x, y) (*(int *) xyarray__entry(e->fd, x, y))
46+#define FD(e, x, y) ((int *) xyarray__entry(e->fd, x, y))
4747 #define MMAP(e, x, y) (e->mmap ? ((struct perf_mmap *) xyarray__entry(e->mmap, x, y)) : NULL)
4848
4949 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
@@ -54,7 +54,10 @@ int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) · 4 unmodified lines
5454 int cpu, thread;
5555 for (cpu = 0; cpu < ncpus; cpu++) {
5656 for (thread = 0; thread < nthreads; thread++) {
57− FD(evsel, cpu, thread) = -1;
57+ int *fd = FD(evsel, cpu, thread);
58+
59+ if (fd)
60+ *fd = -1;
5861 }
5962 }
6063 }
@@ -80,7 +83,7 @@ sys_perf_event_open(struct perf_event_attr *attr, · 19 unmodified lines
8083 static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread, int *group_fd)
8184 {
8285 struct perf_evsel *leader = evsel->leader;
83− int fd;
86+ int *fd;
8487
8588 if (evsel == leader) {
8689 *group_fd = -1;
@@ -95,10 +98,10 @@ static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread, int *grou · 8 unmodified lines
9598 return -ENOTCONN;
9699
97100 fd = FD(leader, cpu, thread);
98− if (fd == -1)
101+ if (fd == NULL || *fd == -1)
99102 return -EBADF;
100103
101− *group_fd = fd;
104+ *group_fd = *fd;
102105
103106 return 0;
104107 }
@@ -138,7 +141,11 @@ int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus, · 33 unmodified lines
138141
139142 for (cpu = 0; cpu < cpus->nr; cpu++) {
140143 for (thread = 0; thread < threads->nr; thread++) {
141− int fd, group_fd;
144+ int fd, group_fd, *evsel_fd;
145+
146+ evsel_fd = FD(evsel, cpu, thread);
147+ if (evsel_fd == NULL)
148+ return -EINVAL;
142149
143150 err = get_group_fd(evsel, cpu, thread, &group_fd);
144151 if (err < 0)
@@ -151,7 +158,7 @@ int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus, · 6 unmodified lines
151158 if (fd < 0)
152159 return -errno;
153160
154− FD(evsel, cpu, thread) = fd;
161+ *evsel_fd = fd;
155162 }
156163 }
157164
@@ -163,9 +170,12 @@ static void perf_evsel__close_fd_cpu(struct perf_evsel *evsel, int cpu) · 5 unmodified lines
163170 int thread;
164171
165172 for (thread = 0; thread < xyarray__max_y(evsel->fd); ++thread) {
166− if (FD(evsel, cpu, thread) >= 0)
167− close(FD(evsel, cpu, thread));
168− FD(evsel, cpu, thread) = -1;
173+ int *fd = FD(evsel, cpu, thread);
174+
175+ if (fd && *fd >= 0) {
176+ close(*fd);
177+ *fd = -1;
178+ }
169179 }
170180 }
171181
@@ -209,13 +219,12 @@ void perf_evsel__munmap(struct perf_evsel *evsel) · 37 unmodified lines
209219
210220 for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) {
211221 for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
212− int fd = FD(evsel, cpu, thread);
213− struct perf_mmap *map = MMAP(evsel, cpu, thread);
222+ int *fd = FD(evsel, cpu, thread);
214223
215− if (fd < 0)
224+ if (fd == NULL || *fd < 0)
216225 continue;
217226
218− perf_mmap__munmap(map);
227+ perf_mmap__munmap(MMAP(evsel, cpu, thread));
219228 }
220229 }
221230
@@ -239,15 +248,16 @@ int perf_evsel__mmap(struct perf_evsel *evsel, int pages) · 17 unmodified lines
239248
240249 for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) {
241250 for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
242− int fd = FD(evsel, cpu, thread);
243− struct perf_mmap *map = MMAP(evsel, cpu, thread);
251+ int *fd = FD(evsel, cpu, thread);
252+ struct perf_mmap *map;
244253
245− if (fd < 0)
254+ if (fd == NULL || *fd < 0)
246255 continue;
247256
257+ map = MMAP(evsel, cpu, thread);
248258 perf_mmap__init(map, NULL, false, NULL);
249259
250− ret = perf_mmap__mmap(map, &mp, fd, cpu);
260+ ret = perf_mmap__mmap(map, &mp, *fd, cpu);
251261 if (ret) {
252262 perf_evsel__munmap(evsel);
253263 return ret;
@@ -260,7 +270,9 @@ int perf_evsel__mmap(struct perf_evsel *evsel, int pages) · 6 unmodified lines
260270
261271 void *perf_evsel__mmap_base(struct perf_evsel *evsel, int cpu, int thread)
262272 {
263− if (FD(evsel, cpu, thread) < 0 || MMAP(evsel, cpu, thread) == NULL)
273+ int *fd = FD(evsel, cpu, thread);
274+
275+ if (fd == NULL || *fd < 0 || MMAP(evsel, cpu, thread) == NULL)
264276 return NULL;
265277
266278 return MMAP(evsel, cpu, thread)->base;
@@ -295,17 +307,18 @@ int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread, · 28 unmodified lines
295307 struct perf_counts_values *count)
296308 {
297309 size_t size = perf_evsel__read_size(evsel);
310+ int *fd = FD(evsel, cpu, thread);
298311
299312 memset(count, 0, sizeof(*count));
300313
301− if (FD(evsel, cpu, thread) < 0)
314+ if (fd == NULL || *fd < 0)
302315 return -EINVAL;
303316
304317 if (MMAP(evsel, cpu, thread) &&
305318 !perf_mmap__read_self(MMAP(evsel, cpu, thread), count))
306319 return 0;
307320
308− if (readn(FD(evsel, cpu, thread), count->values, size) <= 0)
321+ if (readn(*fd, count->values, size) <= 0)
309322 return -errno;
310323
311324 return 0;
@@ -318,8 +331,13 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel, · 6 unmodified lines
318331 int thread;
319332
320333 for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
321− int fd = FD(evsel, cpu, thread),
322− err = ioctl(fd, ioc, arg);
334+ int err;
335+ int *fd = FD(evsel, cpu, thread);
336+
337+ if (fd == NULL || *fd < 0)
338+ return -1;
339+
340+ err = ioctl(*fd, ioc, arg);
323341
324342 if (err)
325343 return err;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t