(root)/
strace-6.5/
tests-m32/
process_vm_readv_writev.c
       1  /*
       2   * Check decoding of process_vm_readv/process_vm_writev syscall.
       3   *
       4   * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
       5   * Copyright (c) 2016-2021 The strace developers.
       6   * All rights reserved.
       7   *
       8   * SPDX-License-Identifier: GPL-2.0-or-later
       9   */
      10  
      11  #include <inttypes.h>
      12  #include <stdio.h>
      13  #include <unistd.h>
      14  #include <sys/uio.h>
      15  #include "pidns.h"
      16  
      17  #if OP_WR
      18  # define in_iovec  rmt_iovec
      19  # define out_iovec lcl_iovec
      20  # define in_iov    rmt_iov
      21  # define out_iov   lcl_iov
      22  #else
      23  # define in_iovec  lcl_iovec
      24  # define out_iovec rmt_iovec
      25  # define in_iov    lcl_iov
      26  # define out_iov   rmt_iov
      27  #endif
      28  
      29  typedef void (*iov_print_fn)(const struct iovec *, const void *, long);
      30  
      31  enum { MAX_SEGM_COUNT = 2, MAX_STR_LEN = 5 };
      32  
      33  struct print_iov_arg {
      34  	uint32_t count;
      35  	uint32_t valid    :1,
      36  		 string   :1,
      37  		 addr_term:1,
      38  		 check_rc :1;
      39  	uint32_t str_segms;
      40  	uint8_t  str_base[MAX_SEGM_COUNT];
      41  	uint8_t  str_size[MAX_SEGM_COUNT];
      42  };
      43  
      44  static void
      45  print_iov(const struct iovec *iov, const void *arg_ptr, long rc)
      46  {
      47  	const struct print_iov_arg *arg = arg_ptr;
      48  	uint32_t num_segm = 0;
      49  	uint64_t segm_offs = 0;
      50  
      51  	if (!arg || !arg->valid) {
      52  		if (iov)
      53  			printf("%p", iov);
      54  		else
      55  			printf("NULL");
      56  
      57  		return;
      58  	}
      59  
      60  	printf("[");
      61  
      62  	for (uint32_t i = 0; i < arg->count; ++i) {
      63  		if (i)
      64  			printf(", ");
      65  
      66  		if (i >= MAX_STR_LEN) {
      67  			printf("...");
      68  			break;
      69  		}
      70  
      71  		printf("{iov_base=");
      72  		if (arg->string && (!arg->check_rc || (rc != -1))) {
      73  			uint64_t str_left = iov[i].iov_len;
      74  			uint64_t pr_count = 0;
      75  
      76  			printf("\"");
      77  
      78  			while (str_left--) {
      79  				static const char oct_str[] = "01234567";
      80  				uint8_t c = arg->str_base[num_segm] + segm_offs;
      81  
      82  				if ((num_segm >= arg->str_segms) ||
      83  				    (num_segm >= MAX_SEGM_COUNT))
      84  					error_msg_and_fail("print_iov: segment "
      85  							   "count overrun");
      86  
      87  				if (pr_count++ < MAX_STR_LEN)
      88  					printf("\\%.1s%.1s%d",
      89  					       (c >> 6) ?
      90  					       oct_str + (c >> 6) : "",
      91  					       (c >> 3) ?
      92  					       oct_str + ((c >> 3) & 7) : "",
      93  					       c & 7);
      94  
      95  				segm_offs++;
      96  
      97  				if (segm_offs >= arg->str_size[num_segm]) {
      98  					num_segm++;
      99  					segm_offs = 0;
     100  				}
     101  			}
     102  
     103  			printf("\"");
     104  
     105  			if (pr_count > MAX_STR_LEN)
     106  				printf("...");
     107  		} else {
     108  			if (iov[i].iov_base)
     109  				printf("%p", iov[i].iov_base);
     110  			else
     111  				printf("NULL");
     112  		}
     113  
     114  		printf(", iov_len=%zu}", iov[i].iov_len);
     115  	}
     116  
     117  	if (arg->addr_term)
     118  		printf(", ... /* %p */", iov + arg->count);
     119  
     120  	printf("]");
     121  }
     122  
     123  static void
     124  do_call(kernel_ulong_t pid, enum pid_type pid_type,
     125  	kernel_ulong_t local_iov, const char *local_arg,
     126  	kernel_ulong_t liovcnt,
     127  	kernel_ulong_t remote_iov, const char *remote_arg,
     128  	kernel_ulong_t riovcnt,
     129  	kernel_ulong_t flags, iov_print_fn pr_iov)
     130  {
     131  	long rc;
     132  	const char *errstr;
     133  
     134  	rc = syscall(OP_NR, pid, local_iov, liovcnt, remote_iov, riovcnt,
     135  		flags);
     136  	errstr = sprintrc(rc);
     137  
     138  	pidns_print_leader();
     139  	printf("%s(%d%s, ", OP_STR, (int) pid, pidns_pid2str(pid_type));
     140  
     141  	if (pr_iov)
     142  		pr_iov((const struct iovec *) (uintptr_t) local_iov, local_arg,
     143  			rc);
     144  	else
     145  		printf("%s", local_arg);
     146  
     147  	printf(", %lu, ", (unsigned long) liovcnt);
     148  
     149  	if (pr_iov)
     150  		pr_iov((const struct iovec *) (uintptr_t) remote_iov,
     151  		       remote_arg, rc);
     152  	else
     153  		printf("%s", remote_arg);
     154  
     155  	printf(", %lu, %lu) = %s\n", (unsigned long) riovcnt,
     156  		(unsigned long) flags, errstr);
     157  }
     158  
     159  static kernel_ulong_t
     160  ptr_cast(void *ptr)
     161  {
     162  	return (kernel_ulong_t) (uintptr_t) ptr;
     163  }
     164  
     165  int
     166  main(void)
     167  {
     168  	PIDNS_TEST_INIT;
     169  
     170  	enum {
     171  		SIZE_11 = 2,
     172  		SIZE_12 = 3,
     173  		SIZE_13 = 4,
     174  		SIZE_1 = SIZE_11 + SIZE_12 + SIZE_13,
     175  		SIZE_21 = 5,
     176  		SIZE_22 = 6,
     177  		SIZE_23 = 7,
     178  		SIZE_2 = SIZE_21 + SIZE_22 + SIZE_23,
     179  	};
     180  
     181  	enum {
     182  		SEGM1_BASE = 0x80,
     183  		SEGM2_BASE = 0xA0,
     184  	};
     185  
     186  	static const kernel_ulong_t bogus_pid =
     187  		(kernel_ulong_t) 0xbadfaceddeadca57ULL;
     188  	static const kernel_ulong_t bogus_iovcnt1 =
     189  		(kernel_ulong_t) 0xdec0ded1defaced2ULL;
     190  	static const kernel_ulong_t bogus_iovcnt2 =
     191  		(kernel_ulong_t) 0xdec0ded3defaced4ULL;
     192  	static const kernel_ulong_t bogus_flags =
     193  		(kernel_ulong_t) 0xdeadc0deda7adeadULL;
     194  
     195  	pid_t my_pid = getpid();
     196  	char *data1_out = tail_alloc(SIZE_1);
     197  	char *data2_out = tail_alloc(SIZE_2);
     198  	char *data1_in  = tail_alloc(SIZE_2);
     199  	char *data2_in  = tail_alloc(SIZE_1);
     200  
     201  	struct iovec bogus_iovec[] = {
     202  		{ data1_out + SIZE_1, (size_t) 0xdeadfaceca57beefULL },
     203  		{ data1_in  + SIZE_2, (size_t) 0xbadc0dedda7adeadULL },
     204  		{ data2_out + SIZE_2, (size_t) 0xf157facedec0ded1ULL },
     205  		{ data2_in  + SIZE_1, (size_t) 0xdefaced2bea7be57ULL },
     206  	};
     207  
     208  	struct iovec out_iovec[] = {
     209  		{ data1_out,  SIZE_11 },
     210  		{ data1_out + SIZE_11,  SIZE_12 },
     211  		{ data1_out + SIZE_11 + SIZE_12,  SIZE_13 },
     212  		{ data2_out,  SIZE_21 },
     213  		{ data2_out + SIZE_21,  SIZE_22 },
     214  		{ data2_out + SIZE_21 + SIZE_22,  SIZE_23 },
     215  	};
     216  	struct iovec in_iovec[] = {
     217  		{ data1_in,  SIZE_23 },
     218  		{ data1_in + SIZE_23,  SIZE_22 },
     219  		{ data1_in + SIZE_23 + SIZE_22,  SIZE_21 },
     220  		{ data2_in,  SIZE_13 },
     221  		{ data2_in + SIZE_13,  SIZE_12 },
     222  		{ data2_in + SIZE_13 + SIZE_12,  SIZE_11 },
     223  	};
     224  
     225  	struct iovec *bogus_iov = tail_memdup(bogus_iovec, sizeof(bogus_iovec));
     226  	struct iovec *lcl_iov   = tail_memdup(lcl_iovec,   sizeof(lcl_iovec));
     227  	struct iovec *rmt_iov   = tail_memdup(rmt_iovec,   sizeof(rmt_iovec));
     228  
     229  	struct print_iov_arg bogus_arg   = { ARRAY_SIZE(bogus_iovec), 1 };
     230  	struct print_iov_arg lcl_arg     = { ARRAY_SIZE(lcl_iovec), 1, 1, 0, 0,
     231  		2, {SEGM1_BASE, SEGM2_BASE}, {SIZE_1, SIZE_2} };
     232  	struct print_iov_arg rmt_arg     = { ARRAY_SIZE(rmt_iovec), 1 };
     233  
     234  	struct print_iov_arg bogus_arg_cut = {
     235  		ARRAY_SIZE(bogus_iovec) - 2, 1, 0, 1
     236  	};
     237  	struct print_iov_arg lcl_arg_cut = {
     238  		ARRAY_SIZE(lcl_iovec) - 2, 1, 1, 1, 0, 2,
     239  		{ SEGM1_BASE + SIZE_11 + SIZE_12, SEGM2_BASE },
     240  		{SIZE_13, SIZE_2}
     241  	};
     242  	struct print_iov_arg rmt_arg_cut = { ARRAY_SIZE(rmt_iovec) - 2, 1 };
     243  
     244  
     245  	fill_memory_ex(data1_out, SIZE_1, SEGM1_BASE, SIZE_1);
     246  	fill_memory_ex(data2_out, SIZE_2, SEGM2_BASE, SIZE_2);
     247  
     248  
     249  	do_call(bogus_pid, PT_NONE, (kernel_ulong_t) (uintptr_t) ARG_STR(NULL),
     250  		bogus_iovcnt1, (kernel_ulong_t) (uintptr_t) ARG_STR(NULL),
     251  		bogus_iovcnt2, bogus_flags, NULL);
     252  
     253  	do_call(my_pid, PT_TGID, ptr_cast(bogus_iov + ARRAY_SIZE(bogus_iovec)),
     254  		"[]", 0, ptr_cast(in_iov + ARRAY_SIZE(in_iovec)), "[]",
     255  		0, 0, NULL);
     256  	do_call(my_pid, PT_TGID, ptr_cast(bogus_iov + ARRAY_SIZE(bogus_iovec)),
     257  		NULL, bogus_iovcnt1, ptr_cast(in_iov + ARRAY_SIZE(in_iovec)),
     258  		NULL, bogus_iovcnt2, 0, print_iov);
     259  
     260  	do_call(my_pid, PT_TGID, ptr_cast(bogus_iov), (char *) &bogus_arg,
     261  		ARRAY_SIZE(bogus_iovec), ptr_cast(rmt_iov + 2),
     262  		(char *) &rmt_arg_cut, ARRAY_SIZE(rmt_iovec) - 2, 0, print_iov);
     263  
     264  #if !OP_WR
     265  	lcl_arg.check_rc = 1;
     266  	lcl_arg_cut.check_rc = 1;
     267  #endif
     268  
     269  	do_call(my_pid, PT_TGID, ptr_cast(lcl_iov + 2), (char *) &lcl_arg_cut,
     270  		ARRAY_SIZE(lcl_iovec) - 1, ptr_cast(bogus_iov + 2),
     271  		(char *) &bogus_arg_cut, ARRAY_SIZE(bogus_iovec) - 1, 0,
     272  		print_iov);
     273  
     274  	lcl_arg_cut.addr_term = 0;
     275  
     276  	rmt_arg_cut.addr_term = 1;
     277  	rmt_arg_cut.count = 5;
     278  
     279  	do_call(my_pid, PT_TGID, ptr_cast(lcl_iov + 2), (char *) &lcl_arg_cut,
     280  		ARRAY_SIZE(lcl_iovec) - 2, ptr_cast(rmt_iov + 1),
     281  		(char *) &rmt_arg_cut, ARRAY_SIZE(rmt_iovec), 0, print_iov);
     282  
     283  	/* Correct call */
     284  	do_call(my_pid, PT_TGID, ptr_cast(lcl_iov), (char *) &lcl_arg,
     285  		ARRAY_SIZE(lcl_iovec), ptr_cast(rmt_iov), (char *) &rmt_arg,
     286  		ARRAY_SIZE(rmt_iovec), 0, print_iov);
     287  
     288  	pidns_print_leader();
     289  	puts("+++ exited with 0 +++");
     290  
     291  	return 0;
     292  }