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