1 /*
2 * Check decoding of PERF_EVENT_IOC_* commands of ioctl syscall.
3 *
4 * Copyright (c) 2018 The strace developers.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "tests.h"
31
32 #ifdef HAVE_LINUX_PERF_EVENT_H
33
34 # include <inttypes.h>
35 # include <stdio.h>
36 # include <string.h>
37 # include <unistd.h>
38 # include <sys/ioctl.h>
39 # include <asm/unistd.h>
40 # include <linux/perf_event.h>
41
42 /*
43 * Workaround the bug in kernel UAPI that was fixed
44 * in Linux commit v2.6.33-rc1~48^2~288^2~19.
45 */
46 # ifndef u64
47 # define u64 uint64_t
48 # endif
49
50 # define XLAT_MACROS_ONLY
51 # include "xlat/perf_ioctl_cmds.h"
52 # undef XLAT_MACROS_ONLY
53
54 # define STR16 "0123456789abcdef"
55
56 static long
sys_ioctl(kernel_long_t fd,kernel_ulong_t cmd,kernel_ulong_t arg)57 sys_ioctl(kernel_long_t fd, kernel_ulong_t cmd, kernel_ulong_t arg)
58 {
59 return syscall(__NR_ioctl, fd, cmd, arg);
60 }
61
62 int
main(void)63 main(void)
64 {
65 static const kernel_ulong_t unknown_perf_cmd =
66 (kernel_ulong_t) 0xbadc0dedfeed24edULL;
67 static const kernel_ulong_t magic =
68 (kernel_ulong_t) 0xdeadbeefbadc0dedULL;
69 static const uint64_t magic64 = 0xfacefeeddeadc0deULL;
70 static const char str[] = STR16 STR16 STR16 STR16;
71
72 static struct {
73 unsigned int cmd;
74 const char *str;
75 } flag_iocs[] = {
76 { ARG_STR(PERF_EVENT_IOC_ENABLE) },
77 { ARG_STR(PERF_EVENT_IOC_DISABLE) },
78 { ARG_STR(PERF_EVENT_IOC_RESET) },
79 };
80
81 TAIL_ALLOC_OBJECT_CONST_PTR(uint64_t, u64_ptr);
82 uint64_t *const u64_efault = u64_ptr + 1;
83 uint32_t *const u32_arr = tail_alloc(sizeof(uint32_t) * 4);
84 uint32_t *const u32_efault = u32_arr + 4;
85 char *const str_ptr = tail_memdup(str, sizeof(str));
86 char *const str_efault = str_ptr + sizeof(str);
87 TAIL_ALLOC_OBJECT_CONST_PTR(struct perf_event_attr, pea_ptr);
88
89 *u64_ptr = magic64;
90 fill_memory_ex(pea_ptr, sizeof(*pea_ptr), 0xaa, 0x55);
91
92 /* Unknown perf commands */
93 sys_ioctl(-1, unknown_perf_cmd, magic);
94 printf("ioctl(-1, _IOC(%s_IOC_READ|_IOC_WRITE, 0x24, %#x, %#x), "
95 "%#lx) = -1 EBADF (%m)\n",
96 _IOC_DIR((unsigned int) unknown_perf_cmd) & _IOC_NONE ?
97 "_IOC_NONE|" : "",
98 _IOC_NR((unsigned int) unknown_perf_cmd),
99 _IOC_SIZE((unsigned int) unknown_perf_cmd),
100 (unsigned long) magic);
101
102 sys_ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES + 1, magic);
103 printf("ioctl(-1, _IOC(_IOC_WRITE, 0x24, %#x, %#x), %#lx)"
104 " = -1 EBADF (%m)\n",
105 (unsigned int) _IOC_NR(PERF_EVENT_IOC_MODIFY_ATTRIBUTES + 1),
106 (unsigned int) _IOC_SIZE(PERF_EVENT_IOC_MODIFY_ATTRIBUTES + 1),
107 (unsigned long) magic);
108
109 /* PERF_EVENT_IOC_{ENABLE,DISABLE,RESET} */
110 for (unsigned i = 0; i < ARRAY_SIZE(flag_iocs); i++) {
111 ioctl(-1, flag_iocs[i].cmd, 0);
112 printf("ioctl(-1, %s, 0) = -1 EBADF (%m)\n", flag_iocs[i].str);
113
114 ioctl(-1, flag_iocs[i].cmd, 1);
115 printf("ioctl(-1, %s, PERF_IOC_FLAG_GROUP) = -1 EBADF (%m)\n",
116 flag_iocs[i].str);
117
118 ioctl(-1, flag_iocs[i].cmd, 2);
119 printf("ioctl(-1, %s, 0x2 /* PERF_IOC_FLAG_??? */) "
120 "= -1 EBADF (%m)\n",
121 flag_iocs[i].str);
122
123 sys_ioctl(-1, flag_iocs[i].cmd, magic);
124 printf("ioctl(-1, %s, PERF_IOC_FLAG_GROUP|%#x) "
125 "= -1 EBADF (%m)\n",
126 flag_iocs[i].str, (unsigned int) magic & ~1U);
127 }
128
129 /* PERF_EVENT_IOC_REFRESH */
130 sys_ioctl(-1, PERF_EVENT_IOC_REFRESH, magic);
131 printf("ioctl(-1, PERF_EVENT_IOC_REFRESH, %d) = -1 EBADF (%m)\n",
132 (int) magic);
133
134 /* PERF_EVENT_IOC_PERIOD */
135 ioctl(-1, PERF_EVENT_IOC_PERIOD, NULL);
136 printf("ioctl(-1, PERF_EVENT_IOC_PERIOD, NULL) = -1 EBADF (%m)\n");
137
138 ioctl(-1, PERF_EVENT_IOC_PERIOD, u64_efault);
139 printf("ioctl(-1, PERF_EVENT_IOC_PERIOD, %p) = -1 EBADF (%m)\n",
140 u64_efault);
141
142 ioctl(-1, PERF_EVENT_IOC_PERIOD, u64_ptr);
143 printf("ioctl(-1, PERF_EVENT_IOC_PERIOD, [%" PRIu64 "])"
144 " = -1 EBADF (%m)\n",
145 magic64);
146
147 /* PERF_EVENT_IOC_SET_OUTPUT */
148 sys_ioctl(-1, PERF_EVENT_IOC_SET_OUTPUT, magic);
149 printf("ioctl(-1, PERF_EVENT_IOC_SET_OUTPUT, %d) = -1 EBADF (%m)\n",
150 (int) magic);
151
152 /* PERF_EVENT_IOC_SET_FILTER */
153 ioctl(-1, PERF_EVENT_IOC_SET_FILTER, NULL);
154 printf("ioctl(-1, PERF_EVENT_IOC_SET_FILTER, NULL) = -1 EBADF (%m)\n");
155
156 ioctl(-1, PERF_EVENT_IOC_SET_FILTER, str_efault);
157 printf("ioctl(-1, PERF_EVENT_IOC_SET_FILTER, %p) = -1 EBADF (%m)\n",
158 str_efault);
159
160 ioctl(-1, PERF_EVENT_IOC_SET_FILTER, str_ptr);
161 printf("ioctl(-1, PERF_EVENT_IOC_SET_FILTER, \"%.32s\"...)"
162 " = -1 EBADF (%m)\n",
163 str_ptr);
164
165 ioctl(-1, PERF_EVENT_IOC_SET_FILTER, str_ptr + 40);
166 printf("ioctl(-1, PERF_EVENT_IOC_SET_FILTER, \"%.32s\")"
167 " = -1 EBADF (%m)\n",
168 str_ptr + 40);
169
170 str_ptr[sizeof(str) - 1] = '0';
171 ioctl(-1, PERF_EVENT_IOC_SET_FILTER, str_ptr + 40);
172 printf("ioctl(-1, PERF_EVENT_IOC_SET_FILTER, %p)"
173 " = -1 EBADF (%m)\n",
174 str_ptr + 40);
175
176 /* PERF_EVENT_IOC_ID */
177 ioctl(-1, PERF_EVENT_IOC_ID, NULL);
178 printf("ioctl(-1, PERF_EVENT_IOC_ID, NULL) = -1 EBADF (%m)\n");
179
180 ioctl(-1, PERF_EVENT_IOC_ID, u64_efault);
181 printf("ioctl(-1, PERF_EVENT_IOC_ID, %p) = -1 EBADF (%m)\n",
182 u64_efault);
183
184 ioctl(-1, PERF_EVENT_IOC_ID, u64_ptr);
185 printf("ioctl(-1, PERF_EVENT_IOC_ID, %p) = -1 EBADF (%m)\n",
186 u64_ptr);
187
188 /* PERF_EVENT_IOC_SET_BPF */
189 sys_ioctl(-1, PERF_EVENT_IOC_SET_BPF, magic);
190 printf("ioctl(-1, PERF_EVENT_IOC_SET_BPF, %d) = -1 EBADF (%m)\n",
191 (int) magic);
192
193 /* PERF_EVENT_IOC_PAUSE_OUTPUT */
194 sys_ioctl(-1, PERF_EVENT_IOC_PAUSE_OUTPUT, magic);
195 printf("ioctl(-1, PERF_EVENT_IOC_PAUSE_OUTPUT, %lu) = -1 EBADF (%m)\n",
196 (unsigned long) magic);
197
198 /* PERF_EVENT_IOC_QUERY_BPF */
199 ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, NULL);
200 printf("ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, NULL) = -1 EBADF (%m)\n");
201
202 ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, u32_efault);
203 printf("ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, %p) = -1 EBADF (%m)\n",
204 u32_efault);
205
206 u32_arr[0] = 0xbadc0ded;
207 ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, u32_arr);
208 printf("ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, {ids_len=3134983661, ...})"
209 " = -1 EBADF (%m)\n");
210
211 /* PERF_EVENT_IOC_MODIFY_ATTRIBUTES */
212 ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, NULL);
213 printf("ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, NULL)"
214 " = -1 EBADF (%m)\n");
215
216 ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, pea_ptr + 1);
217 printf("ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, %p)"
218 " = -1 EBADF (%m)\n",
219 pea_ptr + 1);
220
221 printf("ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES"
222 ", {type=%#x /* PERF_TYPE_??? */"
223 ", size=%#x /* PERF_ATTR_SIZE_??? */"
224 ", config=%#llx, ...}) = -1 EBADF (%m)\n",
225 (unsigned int) pea_ptr->type,
226 (unsigned int) pea_ptr->size,
227 (unsigned long long) pea_ptr->config);
228 ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, pea_ptr);
229
230 puts("+++ exited with 0 +++");
231 return 0;
232 }
233
234 #else
235
236 SKIP_MAIN_UNDEFINED("HAVE_LINUX_PERF_EVENT_H");
237
238 #endif
239