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
43 free(evsel);43 free(evsel);
44}44}
45 45
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))
47#define MMAP(e, x, y) (e->mmap ? ((struct perf_mmap *) xyarray__entry(e->mmap, x, y)) : NULL)47#define MMAP(e, x, y) (e->mmap ? ((struct perf_mmap *) xyarray__entry(e->mmap, x, y)) : NULL)
48 48
49int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)49int 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
54 int cpu, thread;54 int cpu, thread;
55 for (cpu = 0; cpu < ncpus; cpu++) {55 for (cpu = 0; cpu < ncpus; cpu++) {
56 for (thread = 0; thread < nthreads; thread++) {56 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;
58 }61 }
59 }62 }
60 }63 }
@@ -80,7 +83,7 @@ sys_perf_event_open(struct perf_event_attr *attr, · 19 unmodified lines
80static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread, int *group_fd)83static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread, int *group_fd)
81{84{
82 struct perf_evsel *leader = evsel->leader;85 struct perf_evsel *leader = evsel->leader;
83 int fd;86 int *fd;
84 87
85 if (evsel == leader) {88 if (evsel == leader) {
86 *group_fd = -1;89 *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
95 return -ENOTCONN;98 return -ENOTCONN;
96 99
97 fd = FD(leader, cpu, thread);100 fd = FD(leader, cpu, thread);
98 if (fd == -1)101 if (fd == NULL || *fd == -1)
99 return -EBADF;102 return -EBADF;
100 103
101 *group_fd = fd;104 *group_fd = *fd;
102 105
103 return 0;106 return 0;
104}107}
@@ -138,7 +141,11 @@ int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus, · 33 unmodified lines
138 141
139 for (cpu = 0; cpu < cpus->nr; cpu++) {142 for (cpu = 0; cpu < cpus->nr; cpu++) {
140 for (thread = 0; thread < threads->nr; thread++) {143 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;
142 149
143 err = get_group_fd(evsel, cpu, thread, &group_fd);150 err = get_group_fd(evsel, cpu, thread, &group_fd);
144 if (err < 0)151 if (err < 0)
@@ -151,7 +158,7 @@ int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus, · 6 unmodified lines
151 if (fd < 0)158 if (fd < 0)
152 return -errno;159 return -errno;
153 160
154 FD(evsel, cpu, thread) = fd;161 *evsel_fd = fd;
155 }162 }
156 }163 }
157 164
@@ -163,9 +170,12 @@ static void perf_evsel__close_fd_cpu(struct perf_evsel *evsel, int cpu) · 5 unmodified lines
163 int thread;170 int thread;
164 171
165 for (thread = 0; thread < xyarray__max_y(evsel->fd); ++thread) {172 for (thread = 0; thread < xyarray__max_y(evsel->fd); ++thread) {
166 if (FD(evsel, cpu, thread) >= 0)173 int *fd = FD(evsel, cpu, thread);
167 close(FD(evsel, cpu, thread));174
168 FD(evsel, cpu, thread) = -1;175 if (fd && *fd >= 0) {
176 close(*fd);
177 *fd = -1;
178 }
169 }179 }
170}180}
171 181
@@ -209,13 +219,12 @@ void perf_evsel__munmap(struct perf_evsel *evsel) · 37 unmodified lines
209 219
210 for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) {220 for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) {
211 for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {221 for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
212 int fd = FD(evsel, cpu, thread);222 int *fd = FD(evsel, cpu, thread);
213 struct perf_mmap *map = MMAP(evsel, cpu, thread);
214 223
215 if (fd < 0)224 if (fd == NULL || *fd < 0)
216 continue;225 continue;
217 226
218 perf_mmap__munmap(map);227 perf_mmap__munmap(MMAP(evsel, cpu, thread));
219 }228 }
220 }229 }
221 230
@@ -239,15 +248,16 @@ int perf_evsel__mmap(struct perf_evsel *evsel, int pages) · 17 unmodified lines
239 248
240 for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) {249 for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) {
241 for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {250 for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
242 int fd = FD(evsel, cpu, thread);251 int *fd = FD(evsel, cpu, thread);
243 struct perf_mmap *map = MMAP(evsel, cpu, thread);252 struct perf_mmap *map;
244 253
245 if (fd < 0)254 if (fd == NULL || *fd < 0)
246 continue;255 continue;
247 256
257 map = MMAP(evsel, cpu, thread);
248 perf_mmap__init(map, NULL, false, NULL);258 perf_mmap__init(map, NULL, false, NULL);
249 259
250 ret = perf_mmap__mmap(map, &mp, fd, cpu);260 ret = perf_mmap__mmap(map, &mp, *fd, cpu);
251 if (ret) {261 if (ret) {
252 perf_evsel__munmap(evsel);262 perf_evsel__munmap(evsel);
253 return ret;263 return ret;
@@ -260,7 +270,9 @@ int perf_evsel__mmap(struct perf_evsel *evsel, int pages) · 6 unmodified lines
260 270
261void *perf_evsel__mmap_base(struct perf_evsel *evsel, int cpu, int thread)271void *perf_evsel__mmap_base(struct perf_evsel *evsel, int cpu, int thread)
262{272{
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)
264 return NULL;276 return NULL;
265 277
266 return MMAP(evsel, cpu, thread)->base;278 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
295 struct perf_counts_values *count)307 struct perf_counts_values *count)
296{308{
297 size_t size = perf_evsel__read_size(evsel);309 size_t size = perf_evsel__read_size(evsel);
310 int *fd = FD(evsel, cpu, thread);
298 311
299 memset(count, 0, sizeof(*count));312 memset(count, 0, sizeof(*count));
300 313
301 if (FD(evsel, cpu, thread) < 0)314 if (fd == NULL || *fd < 0)
302 return -EINVAL;315 return -EINVAL;
303 316
304 if (MMAP(evsel, cpu, thread) &&317 if (MMAP(evsel, cpu, thread) &&
305 !perf_mmap__read_self(MMAP(evsel, cpu, thread), count))318 !perf_mmap__read_self(MMAP(evsel, cpu, thread), count))
306 return 0;319 return 0;
307 320
308 if (readn(FD(evsel, cpu, thread), count->values, size) <= 0)321 if (readn(*fd, count->values, size) <= 0)
309 return -errno;322 return -errno;
310 323
311 return 0;324 return 0;
@@ -318,8 +331,13 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel, · 6 unmodified lines
318 int thread;331 int thread;
319 332
320 for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {333 for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
321 int fd = FD(evsel, cpu, thread),334 int err;
322 err = ioctl(fd, ioc, arg);335 int *fd = FD(evsel, cpu, thread);
336
337 if (fd == NULL || *fd < 0)
338 return -1;
339
340 err = ioctl(*fd, ioc, arg);
323 341
324 if (err)342 if (err)
325 return err;343 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