(root)/
strace-6.5/
tests/
sockopt-sol_netlink.c
       1  /*
       2   * Check decoding of getsockopt and setsockopt for SOL_NETLINK level.
       3   *
       4   * Copyright (c) 2017-2023 Dmitry V. Levin <ldv@strace.io>
       5   * All rights reserved.
       6   *
       7   * SPDX-License-Identifier: GPL-2.0-or-later
       8   */
       9  
      10  #include "tests.h"
      11  #include "netlink.h"
      12  #include <stdio.h>
      13  
      14  #ifndef SOL_NETLINK
      15  # define SOL_NETLINK 270
      16  #endif
      17  
      18  static int rc;
      19  static const char *errstr;
      20  
      21  static int
      22  get_sockopt(int fd, int name, void *val, socklen_t *len)
      23  {
      24  	rc = getsockopt(fd, SOL_NETLINK, name, val, len);
      25  	errstr = sprintrc(rc);
      26  	return rc;
      27  }
      28  
      29  static int
      30  set_sockopt(int fd, int name, void *val, socklen_t len)
      31  {
      32  	rc = setsockopt(fd, SOL_NETLINK, name, val, len);
      33  	errstr = sprintrc(rc);
      34  	return rc;
      35  }
      36  
      37  int
      38  main(void)
      39  {
      40  	static const struct {
      41  		int val;
      42  		const char *str;
      43  	} names[] = {
      44  #ifdef NETLINK_ADD_MEMBERSHIP
      45  		{ ARG_STR(NETLINK_ADD_MEMBERSHIP) },
      46  #endif
      47  #ifdef NETLINK_DROP_MEMBERSHIP
      48  		{ ARG_STR(NETLINK_DROP_MEMBERSHIP) },
      49  #endif
      50  #ifdef NETLINK_PKTINFO
      51  		{ ARG_STR(NETLINK_PKTINFO) },
      52  #endif
      53  #ifdef NETLINK_BROADCAST_ERROR
      54  		{ ARG_STR(NETLINK_BROADCAST_ERROR) },
      55  #endif
      56  #ifdef NETLINK_NO_ENOBUFS
      57  		{ ARG_STR(NETLINK_NO_ENOBUFS) },
      58  #endif
      59  #ifdef NETLINK_RX_RING
      60  		{ ARG_STR(NETLINK_RX_RING) },
      61  #endif
      62  #ifdef NETLINK_TX_RING
      63  		{ ARG_STR(NETLINK_TX_RING) },
      64  #endif
      65  #ifdef NETLINK_LISTEN_ALL_NSID
      66  		{ ARG_STR(NETLINK_LISTEN_ALL_NSID) },
      67  #endif
      68  #ifdef NETLINK_LIST_MEMBERSHIPS
      69  		{ ARG_STR(NETLINK_LIST_MEMBERSHIPS) },
      70  #endif
      71  #ifdef NETLINK_CAP_ACK
      72  		{ ARG_STR(NETLINK_CAP_ACK) },
      73  #endif
      74  #ifdef NETLINK_EXT_ACK
      75  		{ ARG_STR(NETLINK_EXT_ACK) },
      76  #endif
      77  	};
      78  
      79  	TAIL_ALLOC_OBJECT_CONST_PTR(int, val);
      80  	TAIL_ALLOC_OBJECT_CONST_PTR(socklen_t, len);
      81  	void *const efault = val + 1;
      82          int fd = socket(AF_NETLINK, SOCK_RAW, 0);
      83          if (fd < 0)
      84                  perror_msg_and_skip("socket AF_NETLINK SOCK_RAW");
      85  
      86  	for (unsigned int i = 0; i < ARRAY_SIZE(names); ++i) {
      87  		/* getsockopt */
      88  
      89  		/* classic */
      90  		*len = sizeof(*val);
      91  		get_sockopt(fd, names[i].val, val, len);
      92  		printf("getsockopt(%d, SOL_NETLINK, %s, ", fd, names[i].str);
      93  		if (rc)
      94  			printf("%p", val);
      95  		else
      96  			printf("[%d]", *val);
      97  		printf(", [%d", (int) sizeof(*val));
      98  		if ((int) sizeof(*val) != *len)
      99  			printf(" => %d", *len);
     100  		printf("]) = %s\n", errstr);
     101  
     102  		/* optlen larger than necessary - shortened */
     103  		*len = sizeof(*val) + 1;
     104  		get_sockopt(fd, names[i].val, val, len);
     105  		printf("getsockopt(%d, SOL_NETLINK, %s, ", fd, names[i].str);
     106  		if (rc)
     107  			printf("%p", val);
     108  		else
     109  			printf("[%d]", *val);
     110  		printf(", [%d", (int) sizeof(*val) + 1);
     111  		if ((int) sizeof(*val) + 1 != *len)
     112  			printf(" => %d", *len);
     113  		printf("]) = %s\n", errstr);
     114  
     115  		/* zero optlen - print returned optlen */
     116  		*len = 0;
     117  		get_sockopt(fd, names[i].val, NULL, len);
     118  		printf("getsockopt(%d, SOL_NETLINK, %s, NULL, [0",
     119  		       fd, names[i].str);
     120  		if (*len)
     121  			printf(" => %d", *len);
     122  		printf("]) = %s\n", errstr);
     123  
     124  #ifdef NETLINK_LIST_MEMBERSHIPS
     125  		if (names[i].val != NETLINK_LIST_MEMBERSHIPS) {
     126  #endif
     127  			/* optlen shorter than necessary - print address */
     128  			*len = sizeof(*val) - 1;
     129  			get_sockopt(fd, names[i].val, val, len);
     130  			printf("getsockopt(%d, SOL_NETLINK, %s, %p, [%d",
     131  			       fd, names[i].str, val, (int) sizeof(*val) - 1);
     132  			if ((int) sizeof(*val) - 1 != *len)
     133  				printf(" => %d", *len);
     134  			printf("]) = %s\n", errstr);
     135  #ifdef NETLINK_LIST_MEMBERSHIPS
     136  		} else {
     137  			/* optlen shorter than required for the first element */
     138  			*len = sizeof(*val) - 1;
     139  			get_sockopt(fd, names[i].val, efault, len);
     140  			printf("getsockopt(%d, SOL_NETLINK, %s, ",
     141  			       fd, names[i].str);
     142  			if (rc)
     143  				printf("%p", efault);
     144  			else
     145  				printf("[]");
     146  			printf(", [%d", (int) sizeof(*val) - 1);
     147  			if ((int) sizeof(*val) - 1 != *len)
     148  				printf(" => %d", *len);
     149  			printf("]) = %s\n", errstr);
     150  		}
     151  #endif
     152  
     153  		/* optval EFAULT - print address */
     154  		*len = sizeof(*val);
     155  		get_sockopt(fd, names[i].val, efault, len);
     156  		printf("getsockopt(%d, SOL_NETLINK, %s, %p",
     157  		       fd, names[i].str, efault);
     158  		printf(", [%d", (int) sizeof(*val));
     159  		if ((int) sizeof(*val) != *len)
     160  			printf(" => %d", *len);
     161  		printf("]) = %s\n", errstr);
     162  
     163  		/* optlen EFAULT - print address */
     164  		get_sockopt(fd, names[i].val, val, len + 1);
     165  		printf("getsockopt(%d, SOL_NETLINK, %s, %p, %p) = %s\n",
     166  		       fd, names[i].str, val, len + 1, errstr);
     167  
     168  		/* setsockopt */
     169  
     170  		/* classic */
     171  		*val = 0xdefaced;
     172  		set_sockopt(fd, names[i].val, val, sizeof(*val));
     173  		printf("setsockopt(%d, SOL_NETLINK, %s, [%d], %d) = %s\n",
     174  		       fd, names[i].str, *val, (int) sizeof(*val), errstr);
     175  
     176  		/* optlen larger than necessary - shortened */
     177  		set_sockopt(fd, names[i].val, val, sizeof(*val) + 1);
     178  		printf("setsockopt(%d, SOL_NETLINK, %s, [%d], %d) = %s\n",
     179  		       fd, names[i].str, *val, (int) sizeof(*val) + 1, errstr);
     180  
     181  		/* optlen < 0 - print address */
     182  		set_sockopt(fd, names[i].val, val, -1U);
     183  		printf("setsockopt(%d, SOL_NETLINK, %s, %p, -1) = %s\n",
     184  		       fd, names[i].str, val, errstr);
     185  
     186  		/* optlen smaller than necessary - print address */
     187  		set_sockopt(fd, names[i].val, val, sizeof(*val) - 1);
     188  		printf("setsockopt(%d, SOL_NETLINK, %s, %p, %d) = %s\n",
     189  		       fd, names[i].str, val, (int) sizeof(*val) - 1, errstr);
     190  
     191  		/* optval EFAULT - print address */
     192  		set_sockopt(fd, names[i].val, efault, sizeof(*val));
     193  		printf("setsockopt(%d, SOL_NETLINK, %s, %p, %d) = %s\n",
     194  		       fd, names[i].str, efault, (int) sizeof(*val), errstr);
     195  	}
     196  
     197  	puts("+++ exited with 0 +++");
     198  	return 0;
     199  }