1181847Sjkim/*- 2199605Sjkim * Copyright (C) 2008-2009 Jung-uk Kim <jkim@FreeBSD.org>. All rights reserved. 3181847Sjkim * 4181847Sjkim * Redistribution and use in source and binary forms, with or without 5181847Sjkim * modification, are permitted provided that the following conditions 6181847Sjkim * are met: 7181847Sjkim * 1. Redistributions of source code must retain the above copyright 8181847Sjkim * notice, this list of conditions and the following disclaimer. 9181847Sjkim * 2. Redistributions in binary form must reproduce the above copyright 10181847Sjkim * notice, this list of conditions and the following disclaimer in the 11181847Sjkim * documentation and/or other materials provided with the distribution. 12181847Sjkim * 13181847Sjkim * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14181847Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15181847Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16181847Sjkim * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17181847Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18181847Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19181847Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20181847Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21181847Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22181847Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23181847Sjkim * SUCH DAMAGE. 24181847Sjkim */ 25181847Sjkim 26181847Sjkim#include <sys/cdefs.h> 27181847Sjkim__FBSDID("$FreeBSD$"); 28181847Sjkim 29181847Sjkim#include <signal.h> 30181847Sjkim#include <stdio.h> 31181847Sjkim#include <stdlib.h> 32181847Sjkim 33181847Sjkim#include <sys/types.h> 34181847Sjkim 35181847Sjkim#include <net/bpf.h> 36181847Sjkim 37181847Sjkim#include BPF_TEST_H 38181847Sjkim 39181847Sjkim#define PASSED 0 40181847Sjkim#define FAILED 1 41181847Sjkim#define FATAL -1 42181847Sjkim 43181847Sjkim#ifndef LOG_LEVEL 44181847Sjkim#define LOG_LEVEL 1 45181847Sjkim#endif 46181847Sjkim 47182183Sjkim#ifdef BPF_BENCHMARK 48182183Sjkim#define BPF_NRUNS 10000000 49182183Sjkim#else 50182183Sjkim#define BPF_NRUNS 1 51182183Sjkim#endif 52182183Sjkim 53181847Sjkimstatic void sig_handler(int); 54181847Sjkim 55181847Sjkimstatic int nins = sizeof(pc) / sizeof(pc[0]); 56181847Sjkimstatic int verbose = LOG_LEVEL; 57181847Sjkim 58181847Sjkim#ifdef BPF_JIT_COMPILER 59181847Sjkim 60199604Sjkim#include <libutil.h> 61199604Sjkim 62181847Sjkim#include <net/bpf_jitter.h> 63181847Sjkim 64181847Sjkimstatic u_int 65181847Sjkimbpf_compile_and_filter(void) 66181847Sjkim{ 67182182Sjkim bpf_jit_filter *filter; 68182183Sjkim u_int i, ret; 69181847Sjkim 70182182Sjkim /* Compile the BPF filter program and generate native code. */ 71182182Sjkim if ((filter = bpf_jitter(pc, nins)) == NULL) { 72182175Sjkim if (verbose > 1) 73182175Sjkim printf("Failed to allocate memory:\t"); 74182175Sjkim if (verbose > 0) 75182175Sjkim printf("FATAL\n"); 76182175Sjkim exit(FATAL); 77182175Sjkim } 78199604Sjkim if (verbose > 2) { 79199604Sjkim printf("\n"); 80199604Sjkim hexdump(filter->func, filter->size, NULL, HD_OMIT_CHARS); 81199604Sjkim } 82181847Sjkim 83182183Sjkim for (i = 0; i < BPF_NRUNS; i++) 84182183Sjkim ret = (*(filter->func))(pkt, wirelen, buflen); 85181847Sjkim 86182182Sjkim bpf_destroy_jit_filter(filter); 87181847Sjkim 88181847Sjkim return (ret); 89181847Sjkim} 90181847Sjkim 91182219Sjkim#else 92182219Sjkim 93182219Sjkimu_int bpf_filter(const struct bpf_insn *, u_char *, u_int, u_int); 94182219Sjkim 95181847Sjkim#endif 96181847Sjkim 97181847Sjkim#ifdef BPF_VALIDATE 98182457Sjkimstatic const u_short bpf_code_map[] = { 99182415Sjkim 0x10ff, /* 0x00-0x0f: 1111111100001000 */ 100182415Sjkim 0x3070, /* 0x10-0x1f: 0000111000001100 */ 101182415Sjkim 0x3131, /* 0x20-0x2f: 1000110010001100 */ 102182415Sjkim 0x3031, /* 0x30-0x3f: 1000110000001100 */ 103182415Sjkim 0x3131, /* 0x40-0x4f: 1000110010001100 */ 104182415Sjkim 0x1011, /* 0x50-0x5f: 1000100000001000 */ 105182415Sjkim 0x1013, /* 0x60-0x6f: 1100100000001000 */ 106182415Sjkim 0x1010, /* 0x70-0x7f: 0000100000001000 */ 107182415Sjkim 0x0093, /* 0x80-0x8f: 1100100100000000 */ 108182415Sjkim 0x0000, /* 0x90-0x9f: 0000000000000000 */ 109182415Sjkim 0x0000, /* 0xa0-0xaf: 0000000000000000 */ 110182415Sjkim 0x0002, /* 0xb0-0xbf: 0100000000000000 */ 111182415Sjkim 0x0000, /* 0xc0-0xcf: 0000000000000000 */ 112182415Sjkim 0x0000, /* 0xd0-0xdf: 0000000000000000 */ 113182415Sjkim 0x0000, /* 0xe0-0xef: 0000000000000000 */ 114182415Sjkim 0x0000 /* 0xf0-0xff: 0000000000000000 */ 115182415Sjkim}; 116182415Sjkim 117182457Sjkim#define BPF_VALIDATE_CODE(c) \ 118182457Sjkim ((c) <= 0xff && (bpf_code_map[(c) >> 4] & (1 << ((c) & 0xf))) != 0) 119182457Sjkim 120181847Sjkim/* 121181847Sjkim * XXX Copied from sys/net/bpf_filter.c and modified. 122181847Sjkim * 123181847Sjkim * Return true if the 'fcode' is a valid filter program. 124181847Sjkim * The constraints are that each jump be forward and to a valid 125181847Sjkim * code. The code must terminate with either an accept or reject. 126181847Sjkim * 127181847Sjkim * The kernel needs to be able to verify an application's filter code. 128181847Sjkim * Otherwise, a bogus program could easily crash the system. 129181847Sjkim */ 130181847Sjkimstatic int 131181847Sjkimbpf_validate(const struct bpf_insn *f, int len) 132181847Sjkim{ 133181847Sjkim register int i; 134181847Sjkim register const struct bpf_insn *p; 135181847Sjkim 136181847Sjkim /* Do not accept negative length filter. */ 137181847Sjkim if (len < 0) 138181847Sjkim return (0); 139181847Sjkim 140181847Sjkim /* An empty filter means accept all. */ 141181847Sjkim if (len == 0) 142181847Sjkim return (1); 143181847Sjkim 144181847Sjkim for (i = 0; i < len; ++i) { 145181847Sjkim p = &f[i]; 146182219Sjkim /* 147182417Sjkim * Check that the code is valid. 148182219Sjkim */ 149182457Sjkim if (!BPF_VALIDATE_CODE(p->code)) 150182219Sjkim return (0); 151182417Sjkim /* 152182417Sjkim * Check that that jumps are forward, and within 153182417Sjkim * the code block. 154182417Sjkim */ 155181847Sjkim if (BPF_CLASS(p->code) == BPF_JMP) { 156182428Sjkim register u_int offset; 157181847Sjkim 158182457Sjkim if (p->code == (BPF_JMP|BPF_JA)) 159182428Sjkim offset = p->k; 160182428Sjkim else 161182428Sjkim offset = p->jt > p->jf ? p->jt : p->jf; 162182428Sjkim if (offset >= (u_int)(len - i) - 1) 163181847Sjkim return (0); 164182457Sjkim continue; 165181847Sjkim } 166181847Sjkim /* 167181847Sjkim * Check that memory operations use valid addresses. 168181847Sjkim */ 169182457Sjkim if (p->code == BPF_ST || p->code == BPF_STX || 170182457Sjkim p->code == (BPF_LD|BPF_MEM) || 171182457Sjkim p->code == (BPF_LDX|BPF_MEM)) { 172182457Sjkim if (p->k >= BPF_MEMWORDS) 173182457Sjkim return (0); 174182457Sjkim continue; 175182457Sjkim } 176181847Sjkim /* 177181847Sjkim * Check for constant division by 0. 178181847Sjkim */ 179181847Sjkim if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0) 180181847Sjkim return (0); 181181847Sjkim } 182181847Sjkim return (BPF_CLASS(f[len - 1].code) == BPF_RET); 183181847Sjkim} 184181847Sjkim#endif 185181847Sjkim 186181847Sjkimint 187181847Sjkimmain(void) 188181847Sjkim{ 189182185Sjkim#ifndef BPF_JIT_COMPILER 190182183Sjkim u_int i; 191182183Sjkim#endif 192181847Sjkim u_int ret; 193181847Sjkim int sig; 194181847Sjkim#ifdef BPF_VALIDATE 195181847Sjkim int valid; 196181847Sjkim#endif 197181847Sjkim 198181847Sjkim /* Try to catch all signals */ 199181847Sjkim for (sig = SIGHUP; sig <= SIGUSR2; sig++) 200181847Sjkim signal(sig, sig_handler); 201181847Sjkim 202181847Sjkim#ifdef BPF_VALIDATE 203181847Sjkim valid = bpf_validate(pc, nins); 204181847Sjkim if (valid != 0 && invalid != 0) { 205181847Sjkim if (verbose > 1) 206182219Sjkim printf("Validated invalid instruction(s):\t"); 207181847Sjkim if (verbose > 0) 208181847Sjkim printf("FAILED\n"); 209181847Sjkim return (FAILED); 210181847Sjkim } else if (valid == 0 && invalid == 0) { 211181847Sjkim if (verbose > 1) 212182219Sjkim printf("Invalidated valid instruction(s):\t"); 213181847Sjkim if (verbose > 0) 214181847Sjkim printf("FAILED\n"); 215181847Sjkim return (FAILED); 216182219Sjkim } else if (invalid != 0) { 217182219Sjkim if (verbose > 1) 218182219Sjkim printf("Expected and invalidated:\t"); 219182219Sjkim if (verbose > 0) 220182219Sjkim printf("PASSED\n"); 221182219Sjkim return (PASSED); 222181847Sjkim } 223181847Sjkim#endif 224181847Sjkim 225181847Sjkim#ifdef BPF_JIT_COMPILER 226181847Sjkim ret = bpf_compile_and_filter(); 227181847Sjkim#else 228182183Sjkim for (i = 0; i < BPF_NRUNS; i++) 229182221Sjkim ret = bpf_filter(nins != 0 ? pc : NULL, pkt, wirelen, buflen); 230181847Sjkim#endif 231199604Sjkim if (expect_signal != 0) { 232199604Sjkim if (verbose > 1) 233199604Sjkim printf("Expected signal %d but got none:\t", 234199604Sjkim expect_signal); 235199604Sjkim if (verbose > 0) 236199604Sjkim printf("FAILED\n"); 237199604Sjkim return (FAILED); 238199604Sjkim } 239181847Sjkim if (ret != expect) { 240181847Sjkim if (verbose > 1) 241181847Sjkim printf("Expected 0x%x but got 0x%x:\t", expect, ret); 242181847Sjkim if (verbose > 0) 243181847Sjkim printf("FAILED\n"); 244181847Sjkim return (FAILED); 245181847Sjkim } 246181847Sjkim if (verbose > 1) 247181847Sjkim printf("Expected and got 0x%x:\t", ret); 248181847Sjkim if (verbose > 0) 249181847Sjkim printf("PASSED\n"); 250181847Sjkim 251181847Sjkim return (PASSED); 252181847Sjkim} 253181847Sjkim 254181847Sjkimstatic void 255181847Sjkimsig_handler(int sig) 256181847Sjkim{ 257181847Sjkim 258181847Sjkim if (expect_signal == 0) { 259181847Sjkim if (verbose > 1) 260181847Sjkim printf("Received unexpected signal %d:\t", sig); 261181847Sjkim if (verbose > 0) 262181847Sjkim printf("FATAL\n"); 263181847Sjkim exit(FATAL); 264181847Sjkim } 265181847Sjkim if (expect_signal != sig) { 266181847Sjkim if (verbose > 1) 267181847Sjkim printf("Expected signal %d but got %d:\t", 268181847Sjkim expect_signal, sig); 269181847Sjkim if (verbose > 0) 270181847Sjkim printf("FAILED\n"); 271181847Sjkim exit(FAILED); 272181847Sjkim } 273181847Sjkim 274181847Sjkim if (verbose > 1) 275181847Sjkim printf("Expected and got signal %d:\t", sig); 276181847Sjkim if (verbose > 0) 277181847Sjkim printf("PASSED\n"); 278181847Sjkim 279181847Sjkim exit(PASSED); 280181847Sjkim} 281