(root)/
strace-6.5/
tests/
sockopt-sol_socket.c
       1  /*
       2   * Check decoding of getsockopt and setsockopt for SOL_SOCKET level.
       3   *
       4   * Copyright (c) 2017-2023 Dmitry V. Levin <ldv@strace.io>
       5   * Copyright (c) 2022 Eugene Syromyatnikov <evgsyr@gmail.com>
       6   * All rights reserved.
       7   *
       8   * SPDX-License-Identifier: GPL-2.0-or-later
       9   */
      10  
      11  #include "tests.h"
      12  #include <stdio.h>
      13  #include <sys/socket.h>
      14  #include <sys/un.h>
      15  
      16  #define XLAT_MACROS_ONLY
      17  # include "xlat/sock_options.h"
      18  #undef XLAT_MACROS_ONLY
      19  
      20  #ifdef INJECT_RETVAL
      21  # define INJSTR " (INJECTED)"
      22  #else
      23  # define INJSTR ""
      24  #endif
      25  
      26  static int rc;
      27  static const char *errstr;
      28  
      29  struct intstr {
      30  	int val;
      31  	const char *str;
      32  };
      33  
      34  static int
      35  get_sockopt(int fd, int name, void *val, socklen_t *len)
      36  {
      37  	rc = getsockopt(fd, SOL_SOCKET, name, val, len);
      38  	errstr = sprintrc(rc);
      39  	return rc;
      40  }
      41  
      42  static int
      43  set_sockopt(int fd, int name, void *val, socklen_t len)
      44  {
      45  	rc = setsockopt(fd, SOL_SOCKET, name, val, len);
      46  	errstr = sprintrc(rc);
      47  	return rc;
      48  }
      49  
      50  static void
      51  print_optval(int val, const struct intstr *vecs, size_t vecs_sz)
      52  {
      53  	for (size_t k = 0; k < vecs_sz; k++) {
      54  		if (vecs[k].val == val) {
      55  			printf("[%s]", vecs[k].str);
      56  			return;
      57  		}
      58  	}
      59  
      60  	printf("[%d]", val);
      61  }
      62  
      63  int
      64  main(void)
      65  {
      66  	static const struct intstr int_vecs[] = {
      67  		{ ARG_STR(0) },
      68  		{ ARG_STR(1) },
      69  		{ ARG_STR(1234567890) },
      70  		{ ARG_STR(-1234567890) },
      71  	};
      72  	static const struct intstr txrehash_vecs[] = {
      73  		{ ARG_XLAT_KNOWN(0, "SOCK_TXREHASH_DISABLED") },
      74  		{ ARG_XLAT_KNOWN(1, "SOCK_TXREHASH_ENABLED") },
      75  		{ ARG_XLAT_UNKNOWN(2, "SOCK_TXREHASH_???") },
      76  		{ ARG_XLAT_UNKNOWN(254, "SOCK_TXREHASH_???") },
      77  		{ ARG_XLAT_KNOWN(255, "SOCK_TXREHASH_DEFAULT") },
      78  		{ ARG_XLAT_UNKNOWN(256, "SOCK_TXREHASH_???") },
      79  		{ ARG_XLAT_UNKNOWN(511, "SOCK_TXREHASH_???") },
      80  		{ ARG_XLAT_UNKNOWN(-1, "SOCK_TXREHASH_???") },
      81  	};
      82  	static const struct {
      83  		int val;
      84  		const char *str;
      85  		const struct intstr *const vecs;
      86  		size_t vecs_sz;
      87  		size_t optsz;
      88  	} names[] = {
      89  		{ ARG_STR(SO_DEBUG), .optsz = sizeof(int) },
      90  		{ ARG_STR(SO_REUSEADDR), .optsz = sizeof(int) },
      91  		{ ARG_STR(SO_TYPE), /* TODO */ },
      92  		/* SO_ERROR - see so_error test */
      93  		{ ARG_STR(SO_DONTROUTE), .optsz = sizeof(int) },
      94  		{ ARG_STR(SO_BROADCAST), .optsz = sizeof(int) },
      95  		{ ARG_STR(SO_SNDBUF), .optsz = sizeof(int) },
      96  		{ ARG_STR(SO_RCVBUF), .optsz = sizeof(int) },
      97  		{ ARG_STR(SO_KEEPALIVE), .optsz = sizeof(int) },
      98  		{ ARG_STR(SO_OOBINLINE), .optsz = sizeof(int) },
      99  		{ ARG_STR(SO_NO_CHECK), .optsz = sizeof(int) },
     100  		{ ARG_STR(SO_PRIORITY), .optsz = sizeof(int) },
     101  		/* SO_LINGER - see so_linger test */
     102  		{ ARG_STR(SO_BSDCOMPAT), .optsz = sizeof(int) },
     103  		{ ARG_STR(SO_REUSEPORT), .optsz = sizeof(int) },
     104  		{ ARG_STR(SO_PASSCRED), .optsz = sizeof(int) },
     105  		/* SO_PEERCRED - see so_peercred test */
     106  		{ ARG_STR(SO_RCVLOWAT), .optsz = sizeof(int) },
     107  		{ ARG_STR(SO_SNDLOWAT), .optsz = sizeof(int) },
     108  		{ ARG_STR(SO_RCVTIMEO_OLD), /* TODO */ },
     109  		{ ARG_STR(SO_SNDTIMEO_OLD), /* TODO */ },
     110  		{ ARG_STR(SO_SECURITY_AUTHENTICATION) },
     111  		{ ARG_STR(SO_SECURITY_ENCRYPTION_TRANSPORT) },
     112  		{ ARG_STR(SO_SECURITY_ENCRYPTION_NETWORK) },
     113  		/* TODO: SO_BINDTODEVICE */
     114  		{ ARG_STR(SO_DETACH_FILTER), .optsz = sizeof(int) },
     115  		{ ARG_STR(SO_PEERNAME), /* TODO */ },
     116  		{ ARG_STR(SO_TIMESTAMP_OLD), .optsz = sizeof(int) },
     117  		{ ARG_STR(SO_ACCEPTCONN), .optsz = sizeof(int) },
     118  		{ ARG_STR(SO_PEERSEC), /* TODO */ },
     119  		{ ARG_STR(SO_SNDBUFFORCE), .optsz = sizeof(int) },
     120  		{ ARG_STR(SO_RCVBUFFORCE), .optsz = sizeof(int) },
     121  		{ ARG_STR(SO_PASSSEC), .optsz = sizeof(int) },
     122  		{ ARG_STR(SO_TIMESTAMPNS_OLD), .optsz = sizeof(int) },
     123  		{ ARG_STR(SO_MARK), .optsz = sizeof(int) },
     124  		{ ARG_STR(SO_TIMESTAMPING_OLD), .optsz = sizeof(int) },
     125  		{ ARG_STR(SO_PROTOCOL), /* TODO */ },
     126  		{ ARG_STR(SO_DOMAIN), /* TODO */ },
     127  		{ ARG_STR(SO_RXQ_OVFL), .optsz = sizeof(int) },
     128  		{ ARG_STR(SO_WIFI_STATUS), .optsz = sizeof(int) },
     129  		{ ARG_STR(SO_PEEK_OFF), .optsz = sizeof(int) },
     130  		{ ARG_STR(SO_NOFCS), .optsz = sizeof(int) },
     131  		{ ARG_STR(SO_LOCK_FILTER), .optsz = sizeof(int) },
     132  		{ ARG_STR(SO_SELECT_ERR_QUEUE), .optsz = sizeof(int) },
     133  		{ ARG_STR(SO_BUSY_POLL), .optsz = sizeof(int) },
     134  		{ ARG_STR(SO_MAX_PACING_RATE), /* TODO */ },
     135  		{ ARG_STR(SO_BPF_EXTENSIONS), /* TODO */ },
     136  		{ ARG_STR(SO_INCOMING_CPU), .optsz = sizeof(int) },
     137  		{ ARG_STR(SO_ATTACH_BPF), /* TODO */ },
     138  		/* SO_ATTACH_REUSEPORT_CBPF - see sock_filter-v test */
     139  		{ ARG_STR(SO_ATTACH_REUSEPORT_EBPF), /* TODO */ },
     140  		{ ARG_STR(SO_CNX_ADVICE), .optsz = sizeof(int) },
     141  		{ ARG_STR(SO_MEMINFO), /* TODO */ },
     142  		{ ARG_STR(SO_INCOMING_NAPI_ID), .optsz = sizeof(int) },
     143  		{ ARG_STR(SO_COOKIE), /* TODO */ },
     144  		{ ARG_STR(SO_PEERGROUPS), /* TODO */ },
     145  		{ ARG_STR(SO_ZEROCOPY), .optsz = sizeof(int) },
     146  		{ ARG_STR(SO_TXTIME), /* TODO */ },
     147  		{ ARG_STR(SO_BINDTOIFINDEX), /* TODO */ },
     148  		{ ARG_STR(SO_TIMESTAMP_NEW), .optsz = sizeof(int) },
     149  		{ ARG_STR(SO_TIMESTAMPNS_NEW), .optsz = sizeof(int) },
     150  		{ ARG_STR(SO_TIMESTAMPING_NEW), .optsz = sizeof(int) },
     151  		{ ARG_STR(SO_RCVTIMEO_NEW), /* TODO */ },
     152  		{ ARG_STR(SO_SNDTIMEO_NEW), /* TODO */ },
     153  		{ ARG_STR(SO_DETACH_REUSEPORT_BPF), .optsz = sizeof(int) },
     154  		{ ARG_STR(SO_PREFER_BUSY_POLL), .optsz = sizeof(int) },
     155  		{ ARG_STR(SO_BUSY_POLL_BUDGET), .optsz = sizeof(int) },
     156  		{ ARG_STR(SO_NETNS_COOKIE), /* TODO */ },
     157  		{ ARG_STR(SO_BUF_LOCK), /* TODO */ },
     158  		{ ARG_STR(SO_RESERVE_MEM), .optsz = sizeof(int) },
     159  		{ ARG_STR(SO_TXREHASH), ARRSZ_PAIR(txrehash_vecs), sizeof(int) },
     160  		{ ARG_STR(SO_RCVMARK), .optsz = sizeof(int) },
     161  		{ ARG_STR(SO_PASSPIDFD), .optsz = sizeof(int) },
     162  		/* SO_PEERPIDFD - see so_peerpidfd test */
     163  		{ 78, NULL },
     164  		{ -1, NULL },
     165  	};
     166  
     167  	char pfx_str[256];
     168  	char sol_str[64];
     169  	TAIL_ALLOC_OBJECT_CONST_PTR(int, val);
     170  	TAIL_ALLOC_OBJECT_CONST_ARR(int, bigval, 2);
     171  	TAIL_ALLOC_OBJECT_CONST_PTR(socklen_t, len);
     172  	void *const efault = val + 1;
     173  	int fd = socket(AF_UNIX, SOCK_RAW, 0);
     174  	if (fd < 0)
     175  		perror_msg_and_skip("socket AF_UNIX SOCK_RAW");
     176  
     177  	snprintf(sol_str, sizeof(sol_str), XLAT_FMT, XLAT_ARGS(SOL_SOCKET));
     178  
     179  	for (size_t i = 0; i < ARRAY_SIZE(names); ++i) {
     180  		static char so_str[64];
     181  		const struct intstr *const vecs = names[i].vecs ?: int_vecs;
     182  		size_t vecs_sz = names[i].vecs_sz ?: ARRAY_SIZE(int_vecs);
     183  
     184  		if (names[i].str) {
     185  			snprintf(so_str, sizeof(so_str), XLAT_FMT,
     186  				 XLAT_SEL(names[i].val, names[i].str));
     187  		} else {
     188  			snprintf(so_str, sizeof(so_str),
     189  				 "%#x" NRAW(" /* SO_??? */"), names[i].val);
     190  		}
     191  
     192  		snprintf(pfx_str, sizeof(pfx_str), "etsockopt(%d, %s, %s, ",
     193  			 fd, sol_str, so_str);
     194  
     195  		/* getsockopt */
     196  
     197  		for (size_t j = 0; j < vecs_sz; j++) {
     198  			/* classic */
     199  			*len = sizeof(*val);
     200  			*val = vecs[j].val;
     201  			get_sockopt(fd, names[i].val, val, len);
     202  			printf("g%s", pfx_str);
     203  			if (rc < 0)
     204  				printf("%p", val);
     205  			else
     206  				print_optval(*val, vecs, vecs_sz);
     207  			printf(", [%d]) = %s" INJSTR "\n", *len, errstr);
     208  
     209  			/* optlen larger than accessible memory */
     210  			*len = sizeof(*val) + 1;
     211  			get_sockopt(fd, names[i].val, val, len);
     212  			printf("g%s", pfx_str);
     213  			if (rc < 0 || (!names[i].optsz && *len > sizeof(*val)))
     214  				printf("%p", val);
     215  			else
     216  				print_optval(*val, vecs, vecs_sz);
     217  			printf(", [%d", (int) sizeof(*val) + 1);
     218  			if ((int) sizeof(*val) + 1 != *len)
     219  				printf(" => %d", *len);
     220  			printf("]) = %s" INJSTR "\n", errstr);
     221  
     222  			/* optlen larger than necessary */
     223  			*len = sizeof(*val) + 1;
     224  			*bigval = vecs[j].val;
     225  			get_sockopt(fd, names[i].val, bigval, len);
     226  			printf("g%s", pfx_str);
     227  			if (rc < 0) {
     228  				printf("%p", bigval);
     229  			} else {
     230  				if (*len == sizeof(*val) || names[i].optsz)
     231  					print_optval(*val, vecs, vecs_sz);
     232  				else
     233  					print_quoted_memory(bigval, *len);
     234  			}
     235  			printf(", [%d", (int) sizeof(*val) + 1);
     236  			if ((int) sizeof(*val) + 1 != *len)
     237  				printf(" => %d", *len);
     238  			printf("]) = %s" INJSTR "\n", errstr);
     239  		}
     240  
     241  		/* zero optlen - print returned optlen */
     242  		*len = 0;
     243  #ifdef INJECT_RETVAL
     244  		*val = vecs[0].val;
     245  #endif
     246  		get_sockopt(fd, names[i].val, NULL, len);
     247  		printf("g%sNULL, [0", pfx_str);
     248  		if (*len)
     249  			printf(" => %d", *len);
     250  		printf("]) = %s" INJSTR "\n", errstr);
     251  
     252  		/* optlen shorter than necessary */
     253  		*len = sizeof(*val) - 1;
     254  		get_sockopt(fd, names[i].val, val, len);
     255  		printf("g%s", pfx_str);
     256  		if (rc < 0)
     257  			printf("%p", val);
     258  		else if (names[i].optsz)
     259  			print_quoted_hex(val, sizeof(*val) - 1);
     260  		else
     261  			print_quoted_memory(val, sizeof(*val) - 1);
     262  		printf(", [%d", (int) sizeof(*val) - 1);
     263  		if ((int) sizeof(*val) - 1 != *len)
     264  			printf(" => %d", *len);
     265  		printf("]) = %s" INJSTR "\n", errstr);
     266  
     267  		/* optval EFAULT - print address */
     268  		*len = sizeof(*val);
     269  		get_sockopt(fd, names[i].val, efault, len);
     270  		printf("g%s%p, [%d]) = %s" INJSTR "\n",
     271  		       pfx_str, efault, *len, errstr);
     272  
     273  		/* optlen EFAULT - print address */
     274  		get_sockopt(fd, names[i].val, val, len + 1);
     275  		printf("g%s%p, %p) = %s" INJSTR "\n",
     276  		       pfx_str, val, len + 1, errstr);
     277  
     278  
     279  		/* setsockopt */
     280  
     281  		for (size_t j = 0; j < vecs_sz; j++) {
     282  			/* classic */
     283  			*val = vecs[j].val;
     284  			set_sockopt(fd, names[i].val, val, sizeof(*val));
     285  			printf("s%s[%s], %d) = %s" INJSTR "\n",
     286  			       pfx_str, vecs[j].str, (int) sizeof(*val), errstr);
     287  
     288  			/* optlen larger than necessary */
     289  			set_sockopt(fd, names[i].val, val, sizeof(*val) + 1);
     290  			printf("s%s", pfx_str);
     291  			if (names[i].optsz && names[i].optsz <= sizeof(*val))
     292  				printf("[%s]", vecs[j].str);
     293  			else
     294  				printf("%p", val);
     295  			printf(", %d) = %s" INJSTR "\n",
     296  			       (int) sizeof(*val) + 1, errstr);
     297  		}
     298  
     299  		/* optlen < 0 - print address */
     300  		*val = vecs[0].val;
     301  		set_sockopt(fd, names[i].val, val, -1U);
     302  		printf("s%s%p, -1) = %s" INJSTR "\n", pfx_str, val, errstr);
     303  
     304  		/* optlen smaller than necessary */
     305  		set_sockopt(fd, names[i].val, val, sizeof(*val) - 1);
     306  		printf("s%s", pfx_str);
     307  		if (names[i].optsz)
     308  			printf("%p", val);
     309  		else
     310  			print_quoted_memory(val, sizeof(*val) - 1);
     311  		printf(", %d) = %s" INJSTR "\n", (int) sizeof(*val) - 1, errstr);
     312  
     313  		/* optval EFAULT - print address */
     314  		set_sockopt(fd, names[i].val, efault, sizeof(*val));
     315  		printf("s%s%p, %d) = %s" INJSTR "\n",
     316  		       pfx_str, efault, (int) sizeof(*val), errstr);
     317  	}
     318  
     319  	puts("+++ exited with 0 +++");
     320  	return 0;
     321  }