(root)/
strace-6.5/
tests-mx32/
sock_filter-v.c
       1  /*
       2   * Check decoding of socket filters.
       3   *
       4   * Copyright (c) 2017 Dmitry V. Levin <ldv@strace.io>
       5   * Copyright (c) 2017-2021 The strace developers.
       6   * All rights reserved.
       7   *
       8   * SPDX-License-Identifier: GPL-2.0-or-later
       9   */
      10  
      11  #include "tests.h"
      12  
      13  #include <stdio.h>
      14  #include <unistd.h>
      15  #include <netinet/in.h>
      16  #include <sys/socket.h>
      17  #include <linux/filter.h>
      18  
      19  /* SO_GET_FILTER was introduced by Linux commit v3.8-rc1~139^2~518 */
      20  #ifndef SO_GET_FILTER
      21  # define SO_GET_FILTER SO_ATTACH_FILTER
      22  #endif
      23  
      24  #define HEX_FMT "%#x"
      25  
      26  #define PRINT_STMT(pfx, code_fmt, k_fmt, ...)	\
      27  	printf("%sBPF_STMT(" code_fmt ", " k_fmt ")", pfx, __VA_ARGS__)
      28  
      29  #define PRINT_JUMP(pfx, code_fmt, k, jt, jf, ...)		\
      30  	printf("%sBPF_JUMP(" code_fmt ", %#x, %#x, %#x)",	\
      31  	       pfx, __VA_ARGS__, k, jt, jf)
      32  
      33  static const struct sock_filter bpf_filter[] = {
      34  	BPF_STMT(BPF_LD|BPF_B|BPF_ABS, SKF_LL_OFF+4),
      35  	BPF_STMT(BPF_LD|BPF_B|BPF_ABS, SKF_NET_OFF+8),
      36  	BPF_STMT(BPF_LD|BPF_B|BPF_ABS, SKF_AD_OFF+SKF_AD_PROTOCOL),
      37  	BPF_JUMP(BPF_JMP|BPF_K|BPF_JEQ, IPPROTO_UDP, 0, 5),
      38  	BPF_STMT(BPF_LD|BPF_W|BPF_LEN, 0),
      39  	BPF_JUMP(BPF_JMP|BPF_K|BPF_JGE, 100, 0, 3),
      40  	BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 42),
      41  	BPF_JUMP(BPF_JMP|BPF_K|BPF_JEQ, 'a', 0, 1),
      42  	BPF_STMT(BPF_RET|BPF_K, -1U),
      43  	BPF_STMT(BPF_RET|BPF_K, 0)
      44  };
      45  
      46  static void
      47  print_filter(void)
      48  {
      49  	PRINT_STMT("[", XLAT_FMT "|" XLAT_FMT "|" XLAT_FMT,
      50  		   XLAT_FMT "+4",
      51  		   XLAT_ARGS(BPF_LD), XLAT_ARGS(BPF_B), XLAT_ARGS(BPF_ABS),
      52  		   XLAT_ARGS(SKF_LL_OFF));
      53  	PRINT_STMT(", ", XLAT_FMT "|" XLAT_FMT "|" XLAT_FMT,
      54  		   XLAT_FMT "+8",
      55  		   XLAT_ARGS(BPF_LD), XLAT_ARGS(BPF_B), XLAT_ARGS(BPF_ABS),
      56  		   XLAT_ARGS(SKF_NET_OFF));
      57  	PRINT_STMT(", ", XLAT_FMT "|" XLAT_FMT "|" XLAT_FMT,
      58  		   XLAT_FMT "+" XLAT_FMT,
      59  		   XLAT_ARGS(BPF_LD), XLAT_ARGS(BPF_B), XLAT_ARGS(BPF_ABS),
      60  		   XLAT_ARGS(SKF_AD_OFF), XLAT_ARGS(SKF_AD_PROTOCOL));
      61  	PRINT_JUMP(", ", XLAT_FMT "|" XLAT_FMT "|" XLAT_FMT,
      62  		   IPPROTO_UDP, 0, 5,
      63  		   XLAT_ARGS(BPF_JMP), XLAT_ARGS(BPF_K), XLAT_ARGS(BPF_JEQ));
      64  	PRINT_STMT(", ", XLAT_FMT "|" XLAT_FMT "|" XLAT_FMT,
      65  		   HEX_FMT,
      66  		   XLAT_ARGS(BPF_LD), XLAT_ARGS(BPF_W), XLAT_ARGS(BPF_LEN),
      67  		   0);
      68  	PRINT_JUMP(", ", XLAT_FMT "|" XLAT_FMT "|" XLAT_FMT,
      69  		   100, 0, 3,
      70  		   XLAT_ARGS(BPF_JMP), XLAT_ARGS(BPF_K), XLAT_ARGS(BPF_JGE));
      71  	PRINT_STMT(", ", XLAT_FMT "|" XLAT_FMT "|" XLAT_FMT,
      72  		   HEX_FMT,
      73  		   XLAT_ARGS(BPF_LD), XLAT_ARGS(BPF_B), XLAT_ARGS(BPF_ABS),
      74  		   42);
      75  	PRINT_JUMP(", ", XLAT_FMT "|" XLAT_FMT "|" XLAT_FMT,
      76  		   'a', 0, 1,
      77  		   XLAT_ARGS(BPF_JMP), XLAT_ARGS(BPF_K), XLAT_ARGS(BPF_JEQ));
      78  	PRINT_STMT(", ", XLAT_FMT "|" XLAT_FMT,
      79  		   HEX_FMT,
      80  		   XLAT_ARGS(BPF_RET), XLAT_ARGS(BPF_K),
      81  		   -1U);
      82  	PRINT_STMT(", ", XLAT_FMT "|" XLAT_FMT,
      83  		   HEX_FMT,
      84  		   XLAT_ARGS(BPF_RET), XLAT_ARGS(BPF_K),
      85  		   0);
      86  	putchar(']');
      87  }
      88  
      89  static const char *errstr;
      90  
      91  static int
      92  get_filter(int fd, void *val, socklen_t *len)
      93  {
      94  	int rc = getsockopt(fd, SOL_SOCKET, SO_GET_FILTER, val, len);
      95  	errstr = sprintrc(rc);
      96  	return rc;
      97  }
      98  
      99  static int
     100  set_filter(int fd, void *val, socklen_t len)
     101  {
     102  	int rc = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, val, len);
     103  	errstr = sprintrc(rc);
     104  	return rc;
     105  }
     106  
     107  int
     108  main(void)
     109  {
     110  	int rc;
     111  	struct sock_filter *const filter =
     112  		tail_memdup(bpf_filter, sizeof(bpf_filter));
     113  	void *const efault = filter + ARRAY_SIZE(bpf_filter);
     114  	TAIL_ALLOC_OBJECT_CONST_PTR(struct sock_fprog, prog);
     115  	TAIL_ALLOC_OBJECT_CONST_PTR(socklen_t, len);
     116  
     117  	prog->len = ARRAY_SIZE(bpf_filter);
     118  	prog->filter = filter;
     119  
     120  	int fd = socket(AF_INET, SOCK_DGRAM, 0);
     121  	if (fd < 0)
     122  		perror_msg_and_skip("socket AF_INET SOCK_DGRAM");
     123  
     124  	/* query sock_filter program length -> 0 */
     125  	*len = BPF_MAXINSNS;
     126  	rc = get_filter(fd, NULL, len);
     127  	if (rc)
     128  		perror_msg_and_skip("getsockopt SOL_SOCKET SO_GET_FILTER");
     129  	printf("getsockopt(%d, " XLAT_FMT ", " XLAT_FMT ", NULL, [%u => 0]) "
     130  	       "= 0\n",
     131  	       fd, XLAT_ARGS(SOL_SOCKET), XLAT_ARGS(SO_GET_FILTER),
     132  	       BPF_MAXINSNS);
     133  
     134  	/* getsockopt NULL optlen - EFAULT */
     135  	rc = get_filter(fd, NULL, NULL);
     136  	printf("getsockopt(%d, " XLAT_FMT ", " XLAT_FMT ", NULL, NULL) "
     137  	       "= %s\n",
     138  	       fd, XLAT_ARGS(SOL_SOCKET), XLAT_ARGS(SO_GET_FILTER), errstr);
     139  
     140  	/* attach a filter */
     141  	rc = set_filter(fd, prog, sizeof(*prog));
     142  	if (rc)
     143  		perror_msg_and_skip("setsockopt SOL_SOCKET SO_ATTACH_FILTER");
     144  	printf("setsockopt(%d, " XLAT_FMT ", " XLAT_FMT ", {len=%u, filter=",
     145  	       fd, XLAT_ARGS(SOL_SOCKET), XLAT_ARGS(SO_ATTACH_FILTER),
     146  	       prog->len);
     147  	print_filter();
     148  	printf("}, %u) = 0\n", (unsigned int) sizeof(*prog));
     149  
     150  	/* setsockopt optlen is too small - EINVAL */
     151  	rc = set_filter(fd, prog, sizeof(*prog) - 4);
     152  	printf("setsockopt(%d, " XLAT_FMT ", " XLAT_FMT ", %p, %u) = %s\n",
     153  	       fd, XLAT_ARGS(SOL_SOCKET), XLAT_ARGS(SO_ATTACH_FILTER), prog,
     154  	       (unsigned int) sizeof(*prog) - 4, errstr);
     155  
     156  #ifdef SO_ATTACH_REUSEPORT_CBPF
     157  	rc = setsockopt(fd, SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF,
     158  			prog, sizeof(*prog));
     159  	errstr = sprintrc(rc);
     160  	printf("setsockopt(%d, " XLAT_FMT ", " XLAT_FMT ", {len=%u, filter=",
     161  	       fd, XLAT_ARGS(SOL_SOCKET), XLAT_ARGS(SO_ATTACH_REUSEPORT_CBPF),
     162  	       prog->len);
     163  	print_filter();
     164  	printf("}, %u) = %s\n", (unsigned int) sizeof(*prog), errstr);
     165  #endif
     166  
     167  	/* query sock_filter program length -> ARRAY_SIZE(bpf_filter) */
     168  	*len = 0;
     169  	rc = get_filter(fd, efault, len);
     170  	printf("getsockopt(%d, " XLAT_FMT ", " XLAT_FMT ", %p, [0 => %u]) "
     171  	       "= %s\n",
     172  	       fd, XLAT_ARGS(SOL_SOCKET), XLAT_ARGS(SO_GET_FILTER), efault,
     173  	       (unsigned int) ARRAY_SIZE(bpf_filter), errstr);
     174  
     175  	/* getsockopt optlen is too small - EINVAL */
     176  	*len = ARRAY_SIZE(bpf_filter) - 1;
     177  	rc = get_filter(fd, efault, len);
     178  	printf("getsockopt(%d, " XLAT_FMT ", " XLAT_FMT ", %p, [%u]) = %s\n",
     179  	       fd, XLAT_ARGS(SOL_SOCKET), XLAT_ARGS(SO_GET_FILTER), efault,
     180  	       (unsigned int) ARRAY_SIZE(bpf_filter) - 1, errstr);
     181  
     182  	/* getsockopt optval EFAULT */
     183  	*len = ARRAY_SIZE(bpf_filter);
     184  	rc = get_filter(fd, filter + 1, len);
     185  	printf("getsockopt(%d, " XLAT_FMT ", " XLAT_FMT ", %p, [%u]) = %s\n",
     186  	       fd, XLAT_ARGS(SOL_SOCKET), XLAT_ARGS(SO_GET_FILTER),
     187  	       filter + 1, (unsigned int) ARRAY_SIZE(bpf_filter), errstr);
     188  
     189  	/* getsockopt optlen is too large - truncated */
     190  	*len = ARRAY_SIZE(bpf_filter) + 1;
     191  	rc = get_filter(fd, filter, len);
     192  	printf("getsockopt(%d, " XLAT_FMT ", " XLAT_FMT ", ",
     193  	       fd, XLAT_ARGS(SOL_SOCKET), XLAT_ARGS(SO_GET_FILTER));
     194  	print_filter();
     195  	printf(", [%u => %d]) = %s\n",
     196  	       (unsigned int) ARRAY_SIZE(bpf_filter) + 1, *len, errstr);
     197  
     198  	puts("+++ exited with 0 +++");
     199  	return 0;
     200  }