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-2023 The strace developers.
7 * All rights reserved.
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12 #include "tests.h"
13 #include "scno.h"
14
15 #if defined __NR_mq_timedsend && defined __NR_mq_timedreceive
16
17 # include <assert.h>
18 # include <errno.h>
19 # include <inttypes.h>
20 # include <signal.h>
21 # include <stdio.h>
22 # include <stdlib.h>
23 # include <string.h>
24 # include <time.h>
25 # include <unistd.h>
26
27 # include "xmalloc.h"
28 # include "kernel_fcntl.h"
29 # include "sigevent.h"
30
31 # ifndef DUMPIO_READ
32 # define DUMPIO_READ 0
33 # endif
34
35 # ifndef DUMPIO_WRITE
36 # define DUMPIO_WRITE 0
37 # endif
38
39 static char *mq_name;
40
41 enum {
42 NUM_ATTRS = 8,
43 MSG_CUT = 8,
44 MSG_MAX_UNCUT = 32,
45 MSG_SIZE = 64,
46 MSG_START = 0x80,
47 };
48
49
50 static void
51 printstr(unsigned char start, unsigned int count)
52 {
53 printf("\"");
54 for (unsigned int i = 0; i < count; ++i) {
55 printf("\\%hho", (unsigned char) (start + i));
56 }
57 printf("\"");
58 }
59
60 # if DUMPIO_READ || DUMPIO_WRITE
61 static void
62 dumpstr(unsigned char start, unsigned int count)
63 {
64 for (unsigned int i = 0; i < count; ++i) {
65 if (i < count) {
66 if (!(i % 16))
67 printf(" | %05x ", i);
68 if (!(i % 8))
69 printf(" ");
70
71 printf("%02hhx ", (unsigned char) (start + i));
72 }
73
74 if ((i % 16 == 15) || (i == (count - 1))) {
75 if (i % 16 != 15)
76 printf("%*s", 3 * (15 - i % 16) +
77 ((i + 8) % 16) / 8, " ");
78
79 printf(" ");
80
81 for (unsigned int j = 0; j <= (i % 16); ++j)
82 printf(".");
83 for (unsigned int j = i % 16; j < 15; ++j)
84 printf(" ");
85
86 printf(" |\n");
87
88 }
89 }
90 }
91 # endif /* DUMPIO_READ || DUMPIO_WRITE */
92
93 static void
94 cleanup(void)
95 {
96 long rc;
97
98 rc = syscall(__NR_mq_unlink, mq_name);
99 printf("mq_unlink(\"%s\") = %s\n", mq_name, sprintrc(rc));
100
101 puts("+++ exited with 0 +++");
102 }
103
104 static void
105 do_send(int fd, char *msg, unsigned int msg_size, kernel_old_timespec_t *tmout,
106 bool cropped)
107 {
108 long rc;
109 long saved_errno;
110
111 do {
112 rc = syscall(__NR_mq_timedsend, fd, msg, msg_size, 42,
113 tmout);
114 saved_errno = errno;
115 printf("mq_timedsend(%d, ", fd);
116 printstr(MSG_START, msg_size > MSG_MAX_UNCUT ? MSG_MAX_UNCUT :
117 msg_size);
118 if (cropped)
119 printf("...");
120 errno = saved_errno;
121 printf(", %u, 42, {tv_sec=%lld, tv_nsec=%llu}) = %s\n", msg_size,
122 (long long) tmout->tv_sec,
123 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
124 errno = saved_errno;
125
126 if (rc == -1) {
127 if (errno == EINTR)
128 continue;
129 perror_msg_and_skip("mq_timedsend");
130 }
131 # if DUMPIO_WRITE
132 dumpstr(MSG_START, msg_size);
133 # endif
134 } while (rc);
135 }
136
137 static void
138 do_recv(int fd, char *msg, unsigned int msg_size, kernel_old_timespec_t *tmout,
139 bool cropped)
140 {
141 long rc;
142 long saved_errno;
143 unsigned prio;
144
145 do {
146 rc = syscall(__NR_mq_timedreceive, fd, msg, MSG_SIZE, &prio,
147 tmout);
148 saved_errno = errno;
149 printf("mq_timedreceive(%d, ", fd);
150 if (rc >= 0) {
151 printstr(MSG_START, rc > MSG_MAX_UNCUT ? MSG_MAX_UNCUT :
152 rc);
153 if (cropped)
154 printf("...");
155 } else {
156 printf("%p", msg);
157 }
158 errno = saved_errno;
159 printf(", %u, [42], {tv_sec=%lld, tv_nsec=%llu}) = %s\n", MSG_SIZE,
160 (long long) tmout->tv_sec,
161 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc));
162 errno = saved_errno;
163
164 if (rc == -1) {
165 if (errno == EINTR)
166 continue;
167 perror_msg_and_skip("mq_timedreceive");
168 }
169 if ((rc >= 0) && ((unsigned long) rc != msg_size))
170 error_msg_and_skip("mq_timedreceive size mismatch"
171 ": expected %u, got %ld",
172 msg_size, rc);
173 # if DUMPIO_READ
174 dumpstr(MSG_START, rc);
175 # endif
176 } while (rc < 0);
177 }
178
179 int
180 main(void)
181 {
182 static const kernel_ulong_t bogus_zero =
183 (kernel_ulong_t) 0x8765432100000000ULL;
184 static const kernel_ulong_t bogus_oflags =
185 (kernel_ulong_t) 0xdefaced100000003ULL;
186 static const kernel_ulong_t bogus_mode =
187 (kernel_ulong_t) 0xdec0deadfacefeedULL;
188 static const kernel_ulong_t bogus_fd =
189 (kernel_ulong_t) 0xfeedfacedeadba5eULL;
190 static const kernel_ulong_t bogus_zero_size =
191 (sizeof(kernel_ulong_t) > sizeof(int)) ? (kernel_ulong_t) 0 :
192 (kernel_ulong_t) 0xface1e5500000000ULL;
193 static const kernel_ulong_t bogus_size =
194 (kernel_ulong_t) 0xbadc0dedda7a1057ULL;
195 static const kernel_ulong_t bogus_prio =
196 (kernel_ulong_t) 0xdec0ded1defaced3ULL;
197 static const kernel_old_timespec_t bogus_tmout_data = {
198 .tv_sec = (time_t) 0xdeadfacebeeff00dLL,
199 .tv_nsec = (long) 0xfacefee1deadfeedLL,
200 };
201 static const kernel_old_timespec_t future_tmout_data = {
202 .tv_sec = (time_t) 0x7ea1fade7e57faceLL,
203 .tv_nsec = 999999999,
204 };
205 struct_sigevent bogus_sev_data = {
206 .sigev_notify = 0xdefaced,
207 .sigev_signo = 0xfacefeed,
208 .sigev_value.sival_ptr =
209 (void *) (unsigned long) 0xdeadbeefbadc0dedULL
210 };
211
212 const char *errstr;
213 long rc;
214 kernel_long_t *bogus_attrs = tail_alloc(sizeof(*bogus_attrs) *
215 NUM_ATTRS);
216 char *msg = tail_alloc(MSG_SIZE);
217 TAIL_ALLOC_OBJECT_CONST_PTR(unsigned, bogus_prio_ptr);
218 kernel_old_timespec_t *bogus_tmout = tail_memdup(&bogus_tmout_data,
219 sizeof(*bogus_tmout));
220 kernel_old_timespec_t *future_tmout = tail_memdup(&future_tmout_data,
221 sizeof(*future_tmout));
222 struct_sigevent *bogus_sev = tail_memdup(&bogus_sev_data,
223 sizeof(*bogus_sev));
224 int fd = -1;
225
226
227 fill_memory_ex(msg, MSG_SIZE, MSG_START, MSG_SIZE);
228 fill_memory_ex(bogus_attrs, sizeof(*bogus_attrs) * NUM_ATTRS,
229 0xbb, 0x70);
230
231
232 /* mq_open */
233
234 /* Zero values, non-O_CREAT mode */
235 rc = syscall(__NR_mq_open, NULL, bogus_zero, bogus_mode, NULL);
236 printf("mq_open(NULL, O_RDONLY) = %s\n", sprintrc(rc));
237
238 /* O_CREAT parsing, other flags, bogs values */
239 rc = syscall(__NR_mq_open, msg, O_CREAT | bogus_oflags, bogus_mode,
240 NULL);
241 printf("mq_open(%p, O_ACCMODE|O_CREAT, %#o, NULL) = %s\n",
242 msg, (unsigned short) bogus_mode, sprintrc(rc));
243
244 /* Partially invalid attributes structure */
245 rc = syscall(__NR_mq_open, msg, O_CREAT | bogus_oflags, bogus_mode,
246 bogus_attrs + 1);
247 printf("mq_open(%p, O_ACCMODE|O_CREAT, %#o, %p) = %s\n",
248 msg, (unsigned short) bogus_mode, bogus_attrs + 1, sprintrc(rc));
249
250 /* Valid attributes structure */
251 rc = syscall(__NR_mq_open, msg, O_CREAT | bogus_oflags, bogus_mode,
252 bogus_attrs);
253 printf("mq_open(%p, O_ACCMODE|O_CREAT, %#o, {mq_flags=%#llx"
254 ", mq_maxmsg=%lld, mq_msgsize=%lld, mq_curmsgs=%lld}) = %s\n",
255 msg, (unsigned short) bogus_mode,
256 (unsigned long long) (kernel_ulong_t) bogus_attrs[0],
257 (long long) bogus_attrs[1],
258 (long long) bogus_attrs[2],
259 (long long) bogus_attrs[3], sprintrc(rc));
260
261
262 /* mq_timedsend */
263
264 /* Zero values*/
265 rc = syscall(__NR_mq_timedsend, bogus_zero, NULL, bogus_zero_size,
266 bogus_zero, NULL);
267 printf("mq_timedsend(0, NULL, 0, 0, NULL) = %s\n", sprintrc(rc));
268
269 /* Invalid pointers */
270 rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_SIZE, bogus_size,
271 bogus_prio, bogus_tmout + 1);
272 printf("mq_timedsend(%d, %p, %llu, %u, %p) = %s\n",
273 (int) bogus_fd, msg + MSG_SIZE, (unsigned long long) bogus_size,
274 (unsigned) bogus_prio, bogus_tmout + 1, sprintrc(rc));
275
276 /* Partially invalid message (memory only partially available) */
277 rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_SIZE - MSG_CUT,
278 MSG_SIZE, bogus_prio, bogus_tmout);
279 printf("mq_timedsend(%d, %p, %llu, %u, {tv_sec=%lld, tv_nsec=%llu})"
280 " = %s\n",
281 (int) bogus_fd, msg + MSG_SIZE - MSG_CUT,
282 (unsigned long long) MSG_SIZE, (unsigned) bogus_prio,
283 (long long) bogus_tmout->tv_sec,
284 zero_extend_signed_to_ull(bogus_tmout->tv_nsec), sprintrc(rc));
285
286 /* Fully valid message, uncut */
287 rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_SIZE - MSG_CUT,
288 MSG_CUT, bogus_prio, bogus_tmout);
289 errstr = sprintrc(rc);
290 printf("mq_timedsend(%d, ", (int) bogus_fd);
291 printstr(MSG_START + MSG_SIZE - MSG_CUT, MSG_CUT);
292 printf(", %llu, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
293 (unsigned long long) MSG_CUT, (unsigned) bogus_prio,
294 (long long) bogus_tmout->tv_sec,
295 zero_extend_signed_to_ull(bogus_tmout->tv_nsec), errstr);
296
297 /* Partially invalid message, cut at maxstrlen */
298 rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_CUT, MSG_SIZE,
299 bogus_prio, bogus_tmout);
300 errstr = sprintrc(rc);
301 printf("mq_timedsend(%d, ", (int) bogus_fd);
302 printstr(MSG_START + MSG_CUT, MSG_MAX_UNCUT);
303 printf("..., %llu, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n",
304 (unsigned long long) MSG_SIZE, (unsigned) bogus_prio,
305 (long long) bogus_tmout->tv_sec,
306 zero_extend_signed_to_ull(bogus_tmout->tv_nsec), errstr);
307
308
309 /* mq_timedreceive */
310
311 /* Zero values */
312 rc = syscall(__NR_mq_timedreceive, bogus_zero, NULL, bogus_zero_size,
313 NULL, NULL);
314 printf("mq_timedreceive(0, NULL, 0, NULL, NULL) = %s\n", sprintrc(rc));
315
316 /* Invalid addresses */
317 rc = syscall(__NR_mq_timedreceive, bogus_fd, msg + MSG_SIZE, bogus_size,
318 bogus_prio_ptr + 1, bogus_tmout + 1);
319 printf("mq_timedreceive(%d, %p, %llu, %p, %p) = %s\n",
320 (int) bogus_fd, msg + MSG_SIZE, (unsigned long long) bogus_size,
321 bogus_prio_ptr + 1, bogus_tmout + 1, sprintrc(rc));
322
323 /* Invalid fd, valid msg pointer */
324 rc = syscall(__NR_mq_timedreceive, bogus_fd, msg, bogus_size,
325 bogus_prio_ptr, bogus_tmout);
326 printf("mq_timedreceive(%d, %p, %llu, %p, {tv_sec=%lld, tv_nsec=%llu}) "
327 "= %s\n",
328 (int) bogus_fd, msg, (unsigned long long) bogus_size,
329 bogus_prio_ptr, (long long) bogus_tmout->tv_sec,
330 zero_extend_signed_to_ull(bogus_tmout->tv_nsec), sprintrc(rc));
331
332
333 /* mq_notify */
334
335 /* Zero values */
336 rc = syscall(__NR_mq_notify, bogus_zero, NULL);
337 printf("mq_notify(0, NULL) = %s\n", sprintrc(rc));
338
339 /* Invalid pointer */
340 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev + 1);
341 printf("mq_notify(%d, %p) = %s\n",
342 (int) bogus_fd, bogus_sev + 1, sprintrc(rc));
343
344 /* Invalid SIGEV_* */
345 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev);
346 printf("mq_notify(%d, {sigev_value={sival_int=%d, sival_ptr=%p}"
347 ", sigev_signo=%u, sigev_notify=%#x /* SIGEV_??? */}) = %s\n",
348 (int) bogus_fd, bogus_sev->sigev_value.sival_int,
349 bogus_sev->sigev_value.sival_ptr,
350 bogus_sev->sigev_signo, bogus_sev->sigev_notify,
351 sprintrc(rc));
352
353 /* SIGEV_NONE */
354 bogus_sev->sigev_notify = SIGEV_NONE;
355 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev);
356 printf("mq_notify(%d, {sigev_value={sival_int=%d, sival_ptr=%p}"
357 ", sigev_signo=%u, sigev_notify=SIGEV_NONE}) = %s\n",
358 (int) bogus_fd, bogus_sev->sigev_value.sival_int,
359 bogus_sev->sigev_value.sival_ptr,
360 bogus_sev->sigev_signo, sprintrc(rc));
361
362 /* SIGEV_SIGNAL */
363 bogus_sev->sigev_notify = SIGEV_SIGNAL;
364 bogus_sev->sigev_signo = SIGALRM;
365 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev);
366 printf("mq_notify(%d, {sigev_value={sival_int=%d, sival_ptr=%p}"
367 ", sigev_signo=SIGALRM, sigev_notify=SIGEV_SIGNAL}) = %s\n",
368 (int) bogus_fd, bogus_sev->sigev_value.sival_int,
369 bogus_sev->sigev_value.sival_ptr, sprintrc(rc));
370
371 /* SIGEV_THREAD */
372 bogus_sev->sigev_notify = SIGEV_THREAD;
373 bogus_sev->sigev_un.sigev_thread.function =
374 (void *) (unsigned long) 0xdeadbeefbadc0dedULL;
375 bogus_sev->sigev_un.sigev_thread.attribute =
376 (void *) (unsigned long) 0xcafef00dfacefeedULL;
377 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev);
378 printf("mq_notify(%d, {sigev_value={sival_int=%d, sival_ptr=%p}"
379 ", sigev_signo=SIGALRM, sigev_notify=SIGEV_THREAD"
380 ", sigev_notify_function=%p, sigev_notify_attributes=%p})"
381 " = %s\n",
382 (int) bogus_fd, bogus_sev->sigev_value.sival_int,
383 bogus_sev->sigev_value.sival_ptr,
384 bogus_sev->sigev_un.sigev_thread.function,
385 bogus_sev->sigev_un.sigev_thread.attribute, sprintrc(rc));
386
387 /* mq_unlink */
388
389 /* Zero values */
390 rc = syscall(__NR_mq_unlink, NULL);
391 printf("mq_unlink(NULL) = %s\n", sprintrc(rc));
392
393 /* Invalid ptr */
394 rc = syscall(__NR_mq_unlink, msg + MSG_SIZE);
395 printf("mq_unlink(%p) = %s\n", msg + MSG_SIZE, sprintrc(rc));
396
397 /* Long unterminated string */
398 rc = syscall(__NR_mq_unlink, msg);
399 errstr = sprintrc(rc);
400 printf("mq_unlink(%p) = %s\n", msg, errstr);
401
402
403 /* Sending and receiving test */
404
405 mq_name = xasprintf("strace-mq_sendrecv-%u.sample", getpid());
406
407 # if DUMPIO_READ || DUMPIO_WRITE
408 close(0);
409 # endif
410 bogus_attrs[1] = 2;
411 bogus_attrs[2] = MSG_SIZE;
412 fd = rc = syscall(__NR_mq_open, mq_name,
413 O_CREAT|O_RDWR|O_NONBLOCK, 0700, bogus_attrs);
414 errstr = sprintrc(rc);
415 if (rc < 0)
416 perror_msg_and_skip("mq_open");
417 else
418 atexit(cleanup);
419 # if DUMPIO_READ || DUMPIO_WRITE
420 if (fd != 0)
421 error_msg_and_skip("mq_open returned fd other than 0");
422 # endif
423 fill_memory_ex(bogus_attrs, sizeof(*bogus_attrs) * NUM_ATTRS,
424 0xbb, 0x70);
425 printf("mq_open(\"%s\", O_RDWR|O_CREAT|O_NONBLOCK, 0700"
426 ", {mq_flags=%#llx, mq_maxmsg=2, mq_msgsize=%u"
427 ", mq_curmsgs=%lld}) = %s\n",
428 mq_name, (unsigned long long) (kernel_ulong_t) bogus_attrs[0],
429 MSG_SIZE, (long long) bogus_attrs[3], errstr);
430
431 rc = syscall(__NR_mq_getsetattr, fd, NULL, bogus_attrs);
432 if (rc < 0)
433 perror_msg_and_skip("mq_getsetattr");
434 if ((bogus_attrs[1] < 2) || (bogus_attrs[2] < MSG_SIZE))
435 error_msg_and_skip("mq too small");
436
437 do_send(fd, msg, MSG_CUT, future_tmout, false);
438 do_send(fd, msg, MSG_SIZE, future_tmout, true);
439
440 memset(msg, '\0', MSG_SIZE);
441 do_recv(fd, msg, MSG_CUT, future_tmout, false);
442
443 memset(msg, '\0', MSG_SIZE);
444 do_recv(fd, msg, MSG_SIZE, future_tmout, true);
445
446 return 0;
447 }
448
449 #else
450
451 SKIP_MAIN_UNDEFINED("__NR_mq_timedsend && __NR_mq_timedreceive")
452
453 #endif