• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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