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