Home | History | Annotate | Download | only in tests-m32
      1 /*
      2  * Check decoding of socket filters.
      3  *
      4  * Copyright (c) 2017 Dmitry V. Levin <ldv (at) altlinux.org>
      5  * Copyright (c) 2017-2018 The strace developers.
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. The name of the author may not be used to endorse or promote products
     17  *    derived from this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "tests.h"
     32 
     33 #include <stdio.h>
     34 #include <unistd.h>
     35 #include <netinet/in.h>
     36 #include <sys/socket.h>
     37 #include <linux/filter.h>
     38 
     39 /* SO_GET_FILTER was introduced by Linux commit v3.8-rc1~139^2~518 */
     40 #ifndef SO_GET_FILTER
     41 # define SO_GET_FILTER SO_ATTACH_FILTER
     42 #endif
     43 
     44 #define HEX_FMT "%#x"
     45 
     46 #if XLAT_RAW
     47 # define XLAT_FMT HEX_FMT
     48 # define XLAT_ARGS(a_) (a_)
     49 #elif XLAT_VERBOSE
     50 # define XLAT_FMT HEX_FMT " /* %s */"
     51 # define XLAT_ARGS(a_) (a_), #a_
     52 #else
     53 # define XLAT_FMT "%s"
     54 # define XLAT_ARGS(a_) #a_
     55 #endif
     56 
     57 #define PRINT_STMT(pfx, code_fmt, k_fmt, ...)	\
     58 	printf("%sBPF_STMT(" code_fmt ", " k_fmt ")", pfx, __VA_ARGS__)
     59 
     60 #define PRINT_JUMP(pfx, code_fmt, k, jt, jf, ...)		\
     61 	printf("%sBPF_JUMP(" code_fmt ", %#x, %#x, %#x)",	\
     62 	       pfx, __VA_ARGS__, k, jt, jf)
     63 
     64 static const struct sock_filter bpf_filter[] = {
     65 	BPF_STMT(BPF_LD|BPF_B|BPF_ABS, SKF_LL_OFF+4),
     66 	BPF_STMT(BPF_LD|BPF_B|BPF_ABS, SKF_NET_OFF+8),
     67 	BPF_STMT(BPF_LD|BPF_B|BPF_ABS, SKF_AD_OFF+SKF_AD_PROTOCOL),
     68 	BPF_JUMP(BPF_JMP|BPF_K|BPF_JEQ, IPPROTO_UDP, 0, 5),
     69 	BPF_STMT(BPF_LD|BPF_W|BPF_LEN, 0),
     70 	BPF_JUMP(BPF_JMP|BPF_K|BPF_JGE, 100, 0, 3),
     71 	BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 42),
     72 	BPF_JUMP(BPF_JMP|BPF_K|BPF_JEQ, 'a', 0, 1),
     73 	BPF_STMT(BPF_RET|BPF_K, -1U),
     74 	BPF_STMT(BPF_RET|BPF_K, 0)
     75 };
     76 
     77 static void
     78 print_filter(void)
     79 {
     80 	PRINT_STMT("[", XLAT_FMT "|" XLAT_FMT "|" XLAT_FMT,
     81 		   XLAT_FMT "+4",
     82 		   XLAT_ARGS(BPF_LD), XLAT_ARGS(BPF_B), XLAT_ARGS(BPF_ABS),
     83 		   XLAT_ARGS(SKF_LL_OFF));
     84 	PRINT_STMT(", ", XLAT_FMT "|" XLAT_FMT "|" XLAT_FMT,
     85 		   XLAT_FMT "+8",
     86 		   XLAT_ARGS(BPF_LD), XLAT_ARGS(BPF_B), XLAT_ARGS(BPF_ABS),
     87 		   XLAT_ARGS(SKF_NET_OFF));
     88 	PRINT_STMT(", ", XLAT_FMT "|" XLAT_FMT "|" XLAT_FMT,
     89 		   XLAT_FMT "+" XLAT_FMT,
     90 		   XLAT_ARGS(BPF_LD), XLAT_ARGS(BPF_B), XLAT_ARGS(BPF_ABS),
     91 		   XLAT_ARGS(SKF_AD_OFF), XLAT_ARGS(SKF_AD_PROTOCOL));
     92 	PRINT_JUMP(", ", XLAT_FMT "|" XLAT_FMT "|" XLAT_FMT,
     93 		   IPPROTO_UDP, 0, 5,
     94 		   XLAT_ARGS(BPF_JMP), XLAT_ARGS(BPF_K), XLAT_ARGS(BPF_JEQ));
     95 	PRINT_STMT(", ", XLAT_FMT "|" XLAT_FMT "|" XLAT_FMT,
     96 		   HEX_FMT,
     97 		   XLAT_ARGS(BPF_LD), XLAT_ARGS(BPF_W), XLAT_ARGS(BPF_LEN),
     98 		   0);
     99 	PRINT_JUMP(", ", XLAT_FMT "|" XLAT_FMT "|" XLAT_FMT,
    100 		   100, 0, 3,
    101 		   XLAT_ARGS(BPF_JMP), XLAT_ARGS(BPF_K), XLAT_ARGS(BPF_JGE));
    102 	PRINT_STMT(", ", XLAT_FMT "|" XLAT_FMT "|" XLAT_FMT,
    103 		   HEX_FMT,
    104 		   XLAT_ARGS(BPF_LD), XLAT_ARGS(BPF_B), XLAT_ARGS(BPF_ABS),
    105 		   42);
    106 	PRINT_JUMP(", ", XLAT_FMT "|" XLAT_FMT "|" XLAT_FMT,
    107 		   'a', 0, 1,
    108 		   XLAT_ARGS(BPF_JMP), XLAT_ARGS(BPF_K), XLAT_ARGS(BPF_JEQ));
    109 	PRINT_STMT(", ", XLAT_FMT "|" XLAT_FMT,
    110 		   HEX_FMT,
    111 		   XLAT_ARGS(BPF_RET), XLAT_ARGS(BPF_K),
    112 		   -1U);
    113 	PRINT_STMT(", ", XLAT_FMT "|" XLAT_FMT,
    114 		   HEX_FMT,
    115 		   XLAT_ARGS(BPF_RET), XLAT_ARGS(BPF_K),
    116 		   0);
    117 	putchar(']');
    118 }
    119 
    120 static const char *errstr;
    121 
    122 static int
    123 get_filter(int fd, void *val, socklen_t *len)
    124 {
    125 	int rc = getsockopt(fd, SOL_SOCKET, SO_GET_FILTER, val, len);
    126 	errstr = sprintrc(rc);
    127 	return rc;
    128 }
    129 
    130 static int
    131 set_filter(int fd, void *val, socklen_t len)
    132 {
    133 	int rc = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, val, len);
    134 	errstr = sprintrc(rc);
    135 	return rc;
    136 }
    137 
    138 int
    139 main(void)
    140 {
    141 	int rc;
    142 	struct sock_filter *const filter =
    143 		tail_memdup(bpf_filter, sizeof(bpf_filter));
    144 	void *const efault = filter + ARRAY_SIZE(bpf_filter);
    145 	TAIL_ALLOC_OBJECT_CONST_PTR(struct sock_fprog, prog);
    146 	TAIL_ALLOC_OBJECT_CONST_PTR(socklen_t, len);
    147 
    148 	prog->len = ARRAY_SIZE(bpf_filter);
    149 	prog->filter = filter;
    150 
    151 	int fd = socket(AF_INET, SOCK_DGRAM, 0);
    152 	if (fd < 0)
    153 		perror_msg_and_skip("socket AF_INET SOCK_DGRAM");
    154 
    155 	/* query sock_filter program length -> 0 */
    156 	*len = BPF_MAXINSNS;
    157 	rc = get_filter(fd, NULL, len);
    158 	if (rc)
    159 		perror_msg_and_skip("getsockopt SOL_SOCKET SO_GET_FILTER");
    160 	printf("getsockopt(%d, " XLAT_FMT ", " XLAT_FMT ", NULL, [%u->0]) "
    161 	       "= 0\n",
    162 	       fd, XLAT_ARGS(SOL_SOCKET), XLAT_ARGS(SO_GET_FILTER),
    163 	       BPF_MAXINSNS);
    164 
    165 	/* getsockopt NULL optlen - EFAULT */
    166 	rc = get_filter(fd, NULL, NULL);
    167 	printf("getsockopt(%d, " XLAT_FMT ", " XLAT_FMT ", NULL, NULL) "
    168 	       "= %s\n",
    169 	       fd, XLAT_ARGS(SOL_SOCKET), XLAT_ARGS(SO_GET_FILTER), errstr);
    170 
    171 	/* attach a filter */
    172 	rc = set_filter(fd, prog, sizeof(*prog));
    173 	if (rc)
    174 		perror_msg_and_skip("setsockopt SOL_SOCKET SO_ATTACH_FILTER");
    175 	printf("setsockopt(%d, " XLAT_FMT ", " XLAT_FMT ", {len=%u, filter=",
    176 	       fd, XLAT_ARGS(SOL_SOCKET), XLAT_ARGS(SO_ATTACH_FILTER),
    177 	       prog->len);
    178 	print_filter();
    179 	printf("}, %u) = 0\n", (unsigned int) sizeof(*prog));
    180 
    181 	/* setsockopt optlen is too small - EINVAL */
    182 	rc = set_filter(fd, prog, sizeof(*prog) - 4);
    183 	printf("setsockopt(%d, " XLAT_FMT ", " XLAT_FMT ", %p, %u) = %s\n",
    184 	       fd, XLAT_ARGS(SOL_SOCKET), XLAT_ARGS(SO_ATTACH_FILTER), prog,
    185 	       (unsigned int) sizeof(*prog) - 4, errstr);
    186 
    187 #ifdef SO_ATTACH_REUSEPORT_CBPF
    188 	rc = setsockopt(fd, SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF,
    189 			prog, sizeof(*prog));
    190 	errstr = sprintrc(rc);
    191 	printf("setsockopt(%d, " XLAT_FMT ", " XLAT_FMT ", {len=%u, filter=",
    192 	       fd, XLAT_ARGS(SOL_SOCKET), XLAT_ARGS(SO_ATTACH_REUSEPORT_CBPF),
    193 	       prog->len);
    194 	print_filter();
    195 	printf("}, %u) = %s\n", (unsigned int) sizeof(*prog), errstr);
    196 #endif
    197 
    198 	/* query sock_filter program length -> ARRAY_SIZE(bpf_filter) */
    199 	*len = 0;
    200 	rc = get_filter(fd, efault, len);
    201 	printf("getsockopt(%d, " XLAT_FMT ", " XLAT_FMT ", %p, [0->%u]) "
    202 	       "= %s\n",
    203 	       fd, XLAT_ARGS(SOL_SOCKET), XLAT_ARGS(SO_GET_FILTER), efault,
    204 	       (unsigned int) ARRAY_SIZE(bpf_filter), errstr);
    205 
    206 	/* getsockopt optlen is too small - EINVAL */
    207 	*len = ARRAY_SIZE(bpf_filter) - 1;
    208 	rc = get_filter(fd, efault, len);
    209 	printf("getsockopt(%d, " XLAT_FMT ", " XLAT_FMT ", %p, [%u]) = %s\n",
    210 	       fd, XLAT_ARGS(SOL_SOCKET), XLAT_ARGS(SO_GET_FILTER), efault,
    211 	       (unsigned int) ARRAY_SIZE(bpf_filter) - 1, errstr);
    212 
    213 	/* getsockopt optval EFAULT */
    214 	*len = ARRAY_SIZE(bpf_filter);
    215 	rc = get_filter(fd, filter + 1, len);
    216 	printf("getsockopt(%d, " XLAT_FMT ", " XLAT_FMT ", %p, [%u]) = %s\n",
    217 	       fd, XLAT_ARGS(SOL_SOCKET), XLAT_ARGS(SO_GET_FILTER),
    218 	       filter + 1, (unsigned int) ARRAY_SIZE(bpf_filter), errstr);
    219 
    220 	/* getsockopt optlen is too large - truncated */
    221 	*len = ARRAY_SIZE(bpf_filter) + 1;
    222 	rc = get_filter(fd, filter, len);
    223 	printf("getsockopt(%d, " XLAT_FMT ", " XLAT_FMT ", ",
    224 	       fd, XLAT_ARGS(SOL_SOCKET), XLAT_ARGS(SO_GET_FILTER));
    225 	print_filter();
    226 	printf(", [%u->%d]) = %s\n",
    227 	       (unsigned int) ARRAY_SIZE(bpf_filter) + 1, *len, errstr);
    228 
    229 	puts("+++ exited with 0 +++");
    230 	return 0;
    231 }
    232