1 /*
2 * Check decoding of mq_open, mq_timedsend, mq_notify, mq_timedreceive and
3 * mq_unlink syscalls.
4 *
5 * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
6 * Copyright (c) 2016-2018 The strace developers.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "tests.h"
33
34 #include <asm/unistd.h>
35
36 #if defined __NR_mq_open && __NR_mq_timedsend && __NR_mq_timedreceive && \
37 __NR_mq_notify && __NR_mq_unlink
38
39 # include <assert.h>
40 # include <errno.h>
41 # include <fcntl.h>
42 # include <inttypes.h>
43 # include <signal.h>
44 # include <stdio.h>
45 # include <stdlib.h>
46 # include <string.h>
47 # include <time.h>
48 # include <unistd.h>
49
50 # include "sigevent.h"
51
52 # ifndef DUMPIO_READ
53 # define DUMPIO_READ 0
54 # endif
55
56 # ifndef DUMPIO_WRITE
57 # define DUMPIO_WRITE 0
58 # endif
59
60 static char *mq_name;
61
62 enum {
63 NUM_ATTRS = 8,
64 MSG_CUT = 8,
65 MSG_MAX_UNCUT = 32,
66 MSG_SIZE = 64,
67 MSG_START = 0x80,
68 };
69
70
71 static void
printstr(unsigned char start,unsigned int count)72 printstr(unsigned char start, unsigned int count)
73 {
74 unsigned int i;
75
76 printf("\"");
77 for (i = 0; i < count; i++) {
78 printf("\\%hho", (unsigned char) (start + i));
79 }
80 printf("\"");
81 }
82
83 #if DUMPIO_READ || DUMPIO_WRITE
84 static void
dumpstr(unsigned char start,unsigned int count)85 dumpstr(unsigned char start, unsigned int count)
86 {
87 unsigned int i;
88 unsigned int j;
89
90 for (i = 0; i < count; i++) {
91 if (i < count) {
92 if (!(i % 16))
93 printf(" | %05x ", i);
94 if (!(i % 8))
95 printf(" ");
96
97 printf("%02hhx ", (unsigned char) (start + i));
98 }
99
100 if ((i % 16 == 15) || (i == (count - 1))) {
101 if (i % 16 != 15)
102 printf("%*s", 3 * (15 - i % 16) +
103 ((i + 8) % 16) / 8, " ");
104
105 printf(" ");
106
107 for (j = 0; j <= (i % 16); j++)
108 printf(".");
109 for (j = i % 16; j < 15; j++)
110 printf(" ");
111
112 printf(" |\n");
113
114 }
115 }
116 }
117 #endif /* DUMPIO_READ || DUMPIO_WRITE */
118
119 static void
cleanup(void)120 cleanup(void)
121 {
122 long rc;
123
124 rc = syscall(__NR_mq_unlink, mq_name);
125 printf("mq_unlink(\"%s\") = %s\n", mq_name, sprintrc(rc));
126
127 puts("+++ exited with 0 +++");
128 }
129
130 static void
do_send(int fd,char * msg,unsigned int msg_size,struct timespec * tmout,bool cropped)131 do_send(int fd, char *msg, unsigned int msg_size, struct timespec *tmout,
132 bool cropped)
133 {
134 long rc;
135 long saved_errno;
136
137 do {
138 rc = syscall(__NR_mq_timedsend, fd, msg, msg_size, 42,
139 tmout);
140 saved_errno = errno;
141 printf("mq_timedsend(%d, ", fd);
142 printstr(MSG_START, msg_size > MSG_MAX_UNCUT ? MSG_MAX_UNCUT :
143 msg_size);
144 if (cropped)
145 printf("...");
146 errno = saved_errno;
147 printf(", %u, 42, {tv_sec=%lld, tv_nsec=%llu}) = %s\n", msg_size,
148 (long long) tmout->tv_sec,
149 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
150 errno = saved_errno;
151
152 if (rc == -1) {
153 if (errno == EINTR)
154 continue;
155 perror_msg_and_skip("mq_timedsend");
156 }
157 # if DUMPIO_WRITE
158 dumpstr(MSG_START, msg_size);
159 # endif
160 } while (rc);
161 }
162
163 static void
do_recv(int fd,char * msg,unsigned int msg_size,struct timespec * tmout,bool cropped)164 do_recv(int fd, char *msg, unsigned int msg_size, struct timespec *tmout,
165 bool cropped)
166 {
167 long rc;
168 long saved_errno;
169 unsigned prio;
170
171 do {
172 rc = syscall(__NR_mq_timedreceive, fd, msg, MSG_SIZE, &prio,
173 tmout);
174 saved_errno = errno;
175 printf("mq_timedreceive(%d, ", fd);
176 if (rc >= 0) {
177 printstr(MSG_START, rc > MSG_MAX_UNCUT ? MSG_MAX_UNCUT :
178 rc);
179 if (cropped)
180 printf("...");
181 } else {
182 printf("%p", msg);
183 }
184 errno = saved_errno;
185 printf(", %u, [42], {tv_sec=%lld, tv_nsec=%llu}) = %s\n", MSG_SIZE,
186 (long long) tmout->tv_sec,
187 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
188 errno = saved_errno;
189
190 if (rc == -1) {
191 if (errno == EINTR)
192 continue;
193 perror_msg_and_skip("mq_timedreceive");
194 }
195 if ((rc >= 0) && ((unsigned long) rc != msg_size))
196 error_msg_and_skip("mq_timedreceive size mismatch"
197 ": expected %u, got %ld",
198 msg_size, rc);
199 # if DUMPIO_READ
200 dumpstr(MSG_START, rc);
201 # endif
202 } while (rc < 0);
203 }
204
205 int
main(void)206 main(void)
207 {
208 static const kernel_ulong_t bogus_zero =
209 (kernel_ulong_t) 0x8765432100000000ULL;
210 static const kernel_ulong_t bogus_oflags =
211 (kernel_ulong_t) 0xdefaced100000003ULL;
212 static const kernel_ulong_t bogus_mode =
213 (kernel_ulong_t) 0xdec0deadfacefeedULL;
214 static const kernel_ulong_t bogus_fd =
215 (kernel_ulong_t) 0xfeedfacedeadba5eULL;
216 static const kernel_ulong_t bogus_zero_size =
217 (sizeof(kernel_ulong_t) > sizeof(int)) ? (kernel_ulong_t) 0 :
218 (kernel_ulong_t) 0xface1e5500000000ULL;
219 static const kernel_ulong_t bogus_size =
220 (kernel_ulong_t) 0xbadc0dedda7a1057ULL;
221 static const kernel_ulong_t bogus_prio =
222 (kernel_ulong_t) 0xdec0ded1defaced3ULL;
223 static const struct timespec bogus_tmout_data = {
224 .tv_sec = (time_t) 0xdeadfacebeeff00dLL,
225 .tv_nsec = (long) 0xfacefee1deadfeedLL,
226 };
227 static const struct timespec future_tmout_data = {
228 .tv_sec = (time_t) 0x7ea1fade7e57faceLL,
229 .tv_nsec = 999999999,
230 };
231 struct_sigevent bogus_sev_data = {
232 .sigev_notify = 0xdefaced,
233 .sigev_signo = 0xfacefeed,
234 .sigev_value.sival_ptr = (unsigned long) 0xdeadbeefbadc0dedULL
235 };
236
237 const char *errstr;
238 long rc;
239 kernel_long_t *bogus_attrs = tail_alloc(sizeof(*bogus_attrs) *
240 NUM_ATTRS);
241 char *msg = tail_alloc(MSG_SIZE);
242 TAIL_ALLOC_OBJECT_CONST_PTR(unsigned, bogus_prio_ptr);
243 struct timespec *bogus_tmout = tail_memdup(&bogus_tmout_data,
244 sizeof(*bogus_tmout));
245 struct timespec *future_tmout = tail_memdup(&future_tmout_data,
246 sizeof(*future_tmout));
247 struct_sigevent *bogus_sev = tail_memdup(&bogus_sev_data,
248 sizeof(*bogus_sev));
249 int fd = -1;
250
251
252 fill_memory_ex(msg, MSG_SIZE, MSG_START, MSG_SIZE);
253 fill_memory_ex(bogus_attrs, sizeof(*bogus_attrs) * NUM_ATTRS,
254 0xbb, 0x70);
255
256
257 /* mq_open */
258
259 /* Zero values, non-O_CREAT mode */
260 rc = syscall(__NR_mq_open, NULL, bogus_zero, bogus_mode, NULL);
261 printf("mq_open(NULL, O_RDONLY) = %s\n", sprintrc(rc));
262
263 /* O_CREAT parsing, other flags, bogs values */
264 rc = syscall(__NR_mq_open, msg, O_CREAT | bogus_oflags, bogus_mode,
265 NULL);
266 printf("mq_open(%p, O_ACCMODE|O_CREAT, %#o, NULL) = %s\n",
267 msg, (unsigned short) bogus_mode, sprintrc(rc));
268
269 /* Partially invalid attributes structure */
270 rc = syscall(__NR_mq_open, msg, O_CREAT | bogus_oflags, bogus_mode,
271 bogus_attrs + 1);
272 printf("mq_open(%p, O_ACCMODE|O_CREAT, %#o, %p) = %s\n",
273 msg, (unsigned short) bogus_mode, bogus_attrs + 1, sprintrc(rc));
274
275 /* Valid attributes structure */
276 rc = syscall(__NR_mq_open, msg, O_CREAT | bogus_oflags, bogus_mode,
277 bogus_attrs);
278 printf("mq_open(%p, O_ACCMODE|O_CREAT, %#o, {mq_flags=%#llx"
279 ", mq_maxmsg=%lld, mq_msgsize=%lld, mq_curmsgs=%lld}) = %s\n",
280 msg, (unsigned short) bogus_mode,
281 (unsigned long long) (kernel_ulong_t) bogus_attrs[0],
282 (long long) bogus_attrs[1],
283 (long long) bogus_attrs[2],
284 (long long) bogus_attrs[3], sprintrc(rc));
285
286
287 /* mq_timedsend */
288
289 /* Zero values*/
290 rc = syscall(__NR_mq_timedsend, bogus_zero, NULL, bogus_zero_size,
291 bogus_zero, NULL);
292 printf("mq_timedsend(0, NULL, 0, 0, NULL) = %s\n", sprintrc(rc));
293
294 /* Invalid pointers */
295 rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_SIZE, bogus_size,
296 bogus_prio, bogus_tmout + 1);
297 printf("mq_timedsend(%d, %p, %llu, %u, %p) = %s\n",
298 (int) bogus_fd, msg + MSG_SIZE, (unsigned long long) bogus_size,
299 (unsigned) bogus_prio, bogus_tmout + 1, sprintrc(rc));
300
301 /* Partially invalid message (memory only partially available) */
302 rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_SIZE - MSG_CUT,
303 MSG_SIZE, bogus_prio, bogus_tmout);
304 printf("mq_timedsend(%d, %p, %llu, %u, {tv_sec=%lld, tv_nsec=%llu})"
305 " = %s\n",
306 (int) bogus_fd, msg + MSG_SIZE - MSG_CUT,
307 (unsigned long long) MSG_SIZE, (unsigned) bogus_prio,
308 (long long) bogus_tmout->tv_sec,
309 zero_extend_signed_to_ull(bogus_tmout->tv_nsec), sprintrc(rc));
310
311 /* Fully valid message, uncut */
312 rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_SIZE - MSG_CUT,
313 MSG_CUT, bogus_prio, bogus_tmout);
314 errstr = sprintrc(rc);
315 printf("mq_timedsend(%d, ", (int) bogus_fd);
316 printstr(MSG_START + MSG_SIZE - MSG_CUT, MSG_CUT);
317 printf(", %llu, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
318 (unsigned long long) MSG_CUT, (unsigned) bogus_prio,
319 (long long) bogus_tmout->tv_sec,
320 zero_extend_signed_to_ull(bogus_tmout->tv_nsec), errstr);
321
322 /* Partially invalid message, cut at maxstrlen */
323 rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_CUT, MSG_SIZE,
324 bogus_prio, bogus_tmout);
325 errstr = sprintrc(rc);
326 printf("mq_timedsend(%d, ", (int) bogus_fd);
327 printstr(MSG_START + MSG_CUT, MSG_MAX_UNCUT);
328 printf("..., %llu, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
329 (unsigned long long) MSG_SIZE, (unsigned) bogus_prio,
330 (long long) bogus_tmout->tv_sec,
331 zero_extend_signed_to_ull(bogus_tmout->tv_nsec), errstr);
332
333
334 /* mq_timedreceive */
335
336 /* Zero values */
337 rc = syscall(__NR_mq_timedreceive, bogus_zero, NULL, bogus_zero_size,
338 NULL, NULL);
339 printf("mq_timedreceive(0, NULL, 0, NULL, NULL) = %s\n", sprintrc(rc));
340
341 /* Invalid addresses */
342 rc = syscall(__NR_mq_timedreceive, bogus_fd, msg + MSG_SIZE, bogus_size,
343 bogus_prio_ptr + 1, bogus_tmout + 1);
344 printf("mq_timedreceive(%d, %p, %llu, %p, %p) = %s\n",
345 (int) bogus_fd, msg + MSG_SIZE, (unsigned long long) bogus_size,
346 bogus_prio_ptr + 1, bogus_tmout + 1, sprintrc(rc));
347
348 /* Invalid fd, valid msg pointer */
349 rc = syscall(__NR_mq_timedreceive, bogus_fd, msg, bogus_size,
350 bogus_prio_ptr, bogus_tmout);
351 printf("mq_timedreceive(%d, %p, %llu, %p, {tv_sec=%lld, tv_nsec=%llu}) "
352 "= %s\n",
353 (int) bogus_fd, msg, (unsigned long long) bogus_size,
354 bogus_prio_ptr, (long long) bogus_tmout->tv_sec,
355 zero_extend_signed_to_ull(bogus_tmout->tv_nsec), sprintrc(rc));
356
357
358 /* mq_notify */
359
360 /* Zero values */
361 rc = syscall(__NR_mq_notify, bogus_zero, NULL);
362 printf("mq_notify(0, NULL) = %s\n", sprintrc(rc));
363
364 /* Invalid pointer */
365 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev + 1);
366 printf("mq_notify(%d, %p) = %s\n",
367 (int) bogus_fd, bogus_sev + 1, sprintrc(rc));
368
369 /* Invalid SIGEV_* */
370 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev);
371 printf("mq_notify(%d, {sigev_value={sival_int=%d, sival_ptr=%#lx}"
372 ", sigev_signo=%u, sigev_notify=%#x /* SIGEV_??? */}) = %s\n",
373 (int) bogus_fd, bogus_sev->sigev_value.sival_int,
374 bogus_sev->sigev_value.sival_ptr,
375 bogus_sev->sigev_signo, bogus_sev->sigev_notify,
376 sprintrc(rc));
377
378 /* SIGEV_NONE */
379 bogus_sev->sigev_notify = SIGEV_NONE;
380 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev);
381 printf("mq_notify(%d, {sigev_value={sival_int=%d, sival_ptr=%#lx}"
382 ", sigev_signo=%u, sigev_notify=SIGEV_NONE}) = %s\n",
383 (int) bogus_fd, bogus_sev->sigev_value.sival_int,
384 bogus_sev->sigev_value.sival_ptr,
385 bogus_sev->sigev_signo, sprintrc(rc));
386
387 /* SIGEV_SIGNAL */
388 bogus_sev->sigev_notify = SIGEV_SIGNAL;
389 bogus_sev->sigev_signo = SIGALRM;
390 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev);
391 printf("mq_notify(%d, {sigev_value={sival_int=%d, sival_ptr=%#lx}"
392 ", sigev_signo=SIGALRM, sigev_notify=SIGEV_SIGNAL}) = %s\n",
393 (int) bogus_fd, bogus_sev->sigev_value.sival_int,
394 bogus_sev->sigev_value.sival_ptr, sprintrc(rc));
395
396 /* SIGEV_THREAD */
397 bogus_sev->sigev_notify = SIGEV_THREAD;
398 bogus_sev->sigev_un.sigev_thread.function =
399 (unsigned long) 0xdeadbeefbadc0dedULL;
400 bogus_sev->sigev_un.sigev_thread.attribute =
401 (unsigned long) 0xcafef00dfacefeedULL;
402 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev);
403 printf("mq_notify(%d, {sigev_value={sival_int=%d, sival_ptr=%#lx}"
404 ", sigev_signo=SIGALRM, sigev_notify=SIGEV_THREAD"
405 ", sigev_notify_function=%#lx, sigev_notify_attributes=%#lx})"
406 " = %s\n",
407 (int) bogus_fd, bogus_sev->sigev_value.sival_int,
408 bogus_sev->sigev_value.sival_ptr,
409 bogus_sev->sigev_un.sigev_thread.function,
410 bogus_sev->sigev_un.sigev_thread.attribute, sprintrc(rc));
411
412 /* mq_unlink */
413
414 /* Zero values */
415 rc = syscall(__NR_mq_unlink, NULL);
416 printf("mq_unlink(NULL) = %s\n", sprintrc(rc));
417
418 /* Invalid ptr */
419 rc = syscall(__NR_mq_unlink, msg + MSG_SIZE);
420 printf("mq_unlink(%p) = %s\n", msg + MSG_SIZE, sprintrc(rc));
421
422 /* Long unterminated string */
423 rc = syscall(__NR_mq_unlink, msg);
424 errstr = sprintrc(rc);
425 printf("mq_unlink(%p) = %s\n", msg, errstr);
426
427
428 /* Sending and receiving test */
429
430 if (asprintf(&mq_name, "strace-mq_sendrecv-%u.sample", getpid()) < 0)
431 perror_msg_and_fail("asprintf");
432
433 # if DUMPIO_READ || DUMPIO_WRITE
434 close(0);
435 # endif
436 bogus_attrs[1] = 2;
437 bogus_attrs[2] = MSG_SIZE;
438 fd = rc = syscall(__NR_mq_open, mq_name,
439 O_CREAT|O_RDWR|O_NONBLOCK, S_IRWXU, bogus_attrs);
440 errstr = sprintrc(rc);
441 if (rc < 0)
442 perror_msg_and_skip("mq_open");
443 else
444 atexit(cleanup);
445 # if DUMPIO_READ || DUMPIO_WRITE
446 if (fd != 0)
447 error_msg_and_skip("mq_open returned fd other than 0");
448 # endif
449 fill_memory_ex(bogus_attrs, sizeof(*bogus_attrs) * NUM_ATTRS,
450 0xbb, 0x70);
451 printf("mq_open(\"%s\", O_RDWR|O_CREAT|O_NONBLOCK, 0700"
452 ", {mq_flags=%#llx, mq_maxmsg=2, mq_msgsize=%u"
453 ", mq_curmsgs=%lld}) = %s\n",
454 mq_name, (unsigned long long) (kernel_ulong_t) bogus_attrs[0],
455 MSG_SIZE, (long long) bogus_attrs[3], errstr);
456
457 rc = syscall(__NR_mq_getsetattr, fd, NULL, bogus_attrs);
458 if (rc < 0)
459 perror_msg_and_skip("mq_getsetattr");
460 if ((bogus_attrs[1] < 2) || (bogus_attrs[2] < MSG_SIZE))
461 error_msg_and_skip("mq too small");
462
463 do_send(fd, msg, MSG_CUT, future_tmout, false);
464 do_send(fd, msg, MSG_SIZE, future_tmout, true);
465
466 memset(msg, '\0', MSG_SIZE);
467 do_recv(fd, msg, MSG_CUT, future_tmout, false);
468
469 memset(msg, '\0', MSG_SIZE);
470 do_recv(fd, msg, MSG_SIZE, future_tmout, true);
471
472 return 0;
473 }
474
475 #else
476
477 SKIP_MAIN_UNDEFINED("__NR_mq_open && __NR_mq_timedsend && "
478 "__NR_mq_timedreceive && __NR_mq_notify && __NR_mq_unlink");
479
480 #endif
481