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