1/*- 2 * Copyright (C) 2008-2009 Jung-uk Kim <jkim@FreeBSD.org>. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h> 27__FBSDID("$FreeBSD$"); 28 29#include <signal.h> 30#include <stdio.h> 31#include <stdlib.h> 32 33#include <sys/types.h> 34 35#include <net/bpf.h> 36 37#include BPF_TEST_H 38 39#define PASSED 0 40#define FAILED 1 41#define FATAL -1 42 43#ifndef LOG_LEVEL 44#define LOG_LEVEL 1 45#endif 46 47#ifdef BPF_BENCHMARK 48#define BPF_NRUNS 10000000 49#else 50#define BPF_NRUNS 1 51#endif 52 53static void sig_handler(int); 54 55static int nins = sizeof(pc) / sizeof(pc[0]); 56static int verbose = LOG_LEVEL; 57 58#ifdef BPF_JIT_COMPILER 59 60#include <libutil.h> 61 62#include <net/bpf_jitter.h> 63 64static u_int 65bpf_compile_and_filter(void) 66{ 67 bpf_jit_filter *filter; 68 u_int i, ret; 69 70 /* Compile the BPF filter program and generate native code. */ 71 if ((filter = bpf_jitter(pc, nins)) == NULL) { 72 if (verbose > 1) 73 printf("Failed to allocate memory:\t"); 74 if (verbose > 0) 75 printf("FATAL\n"); 76 exit(FATAL); 77 } 78 if (verbose > 2) { 79 printf("\n"); 80 hexdump(filter->func, filter->size, NULL, HD_OMIT_CHARS); 81 } 82 83 for (i = 0; i < BPF_NRUNS; i++) 84 ret = (*(filter->func))(pkt, wirelen, buflen); 85 86 bpf_destroy_jit_filter(filter); 87 88 return (ret); 89} 90 91#else 92 93u_int bpf_filter(const struct bpf_insn *, u_char *, u_int, u_int); 94 95#endif 96 97#ifdef BPF_VALIDATE 98static const u_short bpf_code_map[] = { 99 0x10ff, /* 0x00-0x0f: 1111111100001000 */ 100 0x3070, /* 0x10-0x1f: 0000111000001100 */ 101 0x3131, /* 0x20-0x2f: 1000110010001100 */ 102 0x3031, /* 0x30-0x3f: 1000110000001100 */ 103 0x3131, /* 0x40-0x4f: 1000110010001100 */ 104 0x1011, /* 0x50-0x5f: 1000100000001000 */ 105 0x1013, /* 0x60-0x6f: 1100100000001000 */ 106 0x1010, /* 0x70-0x7f: 0000100000001000 */ 107 0x0093, /* 0x80-0x8f: 1100100100000000 */ 108 0x0000, /* 0x90-0x9f: 0000000000000000 */ 109 0x0000, /* 0xa0-0xaf: 0000000000000000 */ 110 0x0002, /* 0xb0-0xbf: 0100000000000000 */ 111 0x0000, /* 0xc0-0xcf: 0000000000000000 */ 112 0x0000, /* 0xd0-0xdf: 0000000000000000 */ 113 0x0000, /* 0xe0-0xef: 0000000000000000 */ 114 0x0000 /* 0xf0-0xff: 0000000000000000 */ 115}; 116 117#define BPF_VALIDATE_CODE(c) \ 118 ((c) <= 0xff && (bpf_code_map[(c) >> 4] & (1 << ((c) & 0xf))) != 0) 119 120/* 121 * XXX Copied from sys/net/bpf_filter.c and modified. 122 * 123 * Return true if the 'fcode' is a valid filter program. 124 * The constraints are that each jump be forward and to a valid 125 * code. The code must terminate with either an accept or reject. 126 * 127 * The kernel needs to be able to verify an application's filter code. 128 * Otherwise, a bogus program could easily crash the system. 129 */ 130static int 131bpf_validate(const struct bpf_insn *f, int len) 132{ 133 register int i; 134 register const struct bpf_insn *p; 135 136 /* Do not accept negative length filter. */ 137 if (len < 0) 138 return (0); 139 140 /* An empty filter means accept all. */ 141 if (len == 0) 142 return (1); 143 144 for (i = 0; i < len; ++i) { 145 p = &f[i]; 146 /* 147 * Check that the code is valid. 148 */ 149 if (!BPF_VALIDATE_CODE(p->code)) 150 return (0); 151 /* 152 * Check that that jumps are forward, and within 153 * the code block. 154 */ 155 if (BPF_CLASS(p->code) == BPF_JMP) { 156 register u_int offset; 157 158 if (p->code == (BPF_JMP|BPF_JA)) 159 offset = p->k; 160 else 161 offset = p->jt > p->jf ? p->jt : p->jf; 162 if (offset >= (u_int)(len - i) - 1) 163 return (0); 164 continue; 165 } 166 /* 167 * Check that memory operations use valid addresses. 168 */ 169 if (p->code == BPF_ST || p->code == BPF_STX || 170 p->code == (BPF_LD|BPF_MEM) || 171 p->code == (BPF_LDX|BPF_MEM)) { 172 if (p->k >= BPF_MEMWORDS) 173 return (0); 174 continue; 175 } 176 /* 177 * Check for constant division by 0. 178 */ 179 if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0) 180 return (0); 181 } 182 return (BPF_CLASS(f[len - 1].code) == BPF_RET); 183} 184#endif 185 186int 187main(void) 188{ 189#ifndef BPF_JIT_COMPILER 190 u_int i; 191#endif 192 u_int ret; 193 int sig; 194#ifdef BPF_VALIDATE 195 int valid; 196#endif 197 198 /* Try to catch all signals */ 199 for (sig = SIGHUP; sig <= SIGUSR2; sig++) 200 signal(sig, sig_handler); 201 202#ifdef BPF_VALIDATE 203 valid = bpf_validate(pc, nins); 204 if (valid != 0 && invalid != 0) { 205 if (verbose > 1) 206 printf("Validated invalid instruction(s):\t"); 207 if (verbose > 0) 208 printf("FAILED\n"); 209 return (FAILED); 210 } else if (valid == 0 && invalid == 0) { 211 if (verbose > 1) 212 printf("Invalidated valid instruction(s):\t"); 213 if (verbose > 0) 214 printf("FAILED\n"); 215 return (FAILED); 216 } else if (invalid != 0) { 217 if (verbose > 1) 218 printf("Expected and invalidated:\t"); 219 if (verbose > 0) 220 printf("PASSED\n"); 221 return (PASSED); 222 } 223#endif 224 225#ifdef BPF_JIT_COMPILER 226 ret = bpf_compile_and_filter(); 227#else 228 for (i = 0; i < BPF_NRUNS; i++) 229 ret = bpf_filter(nins != 0 ? pc : NULL, pkt, wirelen, buflen); 230#endif 231 if (expect_signal != 0) { 232 if (verbose > 1) 233 printf("Expected signal %d but got none:\t", 234 expect_signal); 235 if (verbose > 0) 236 printf("FAILED\n"); 237 return (FAILED); 238 } 239 if (ret != expect) { 240 if (verbose > 1) 241 printf("Expected 0x%x but got 0x%x:\t", expect, ret); 242 if (verbose > 0) 243 printf("FAILED\n"); 244 return (FAILED); 245 } 246 if (verbose > 1) 247 printf("Expected and got 0x%x:\t", ret); 248 if (verbose > 0) 249 printf("PASSED\n"); 250 251 return (PASSED); 252} 253 254static void 255sig_handler(int sig) 256{ 257 258 if (expect_signal == 0) { 259 if (verbose > 1) 260 printf("Received unexpected signal %d:\t", sig); 261 if (verbose > 0) 262 printf("FATAL\n"); 263 exit(FATAL); 264 } 265 if (expect_signal != sig) { 266 if (verbose > 1) 267 printf("Expected signal %d but got %d:\t", 268 expect_signal, sig); 269 if (verbose > 0) 270 printf("FAILED\n"); 271 exit(FAILED); 272 } 273 274 if (verbose > 1) 275 printf("Expected and got signal %d:\t", sig); 276 if (verbose > 0) 277 printf("PASSED\n"); 278 279 exit(PASSED); 280} 281