(root)/
strace-6.5/
tests-mx32/
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-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