Home | History | Annotate | Download | only in tests-mx32
      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 (at) 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
    482