bpf_test.c revision 182175
1240616Sjimharris/*- 2240616Sjimharris * Copyright (C) 2008 Jung-uk Kim <jkim@FreeBSD.org>. All rights reserved. 3240616Sjimharris * 4240616Sjimharris * Redistribution and use in source and binary forms, with or without 5240616Sjimharris * modification, are permitted provided that the following conditions 6240616Sjimharris * are met: 7240616Sjimharris * 1. Redistributions of source code must retain the above copyright 8240616Sjimharris * notice, this list of conditions and the following disclaimer. 9240616Sjimharris * 2. Redistributions in binary form must reproduce the above copyright 10240616Sjimharris * notice, this list of conditions and the following disclaimer in the 11240616Sjimharris * documentation and/or other materials provided with the distribution. 12240616Sjimharris * 13240616Sjimharris * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14240616Sjimharris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15240616Sjimharris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16240616Sjimharris * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17240616Sjimharris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18240616Sjimharris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19240616Sjimharris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20240616Sjimharris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21240616Sjimharris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22240616Sjimharris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23240616Sjimharris * SUCH DAMAGE. 24240616Sjimharris */ 25240616Sjimharris 26240616Sjimharris#include <sys/cdefs.h> 27240616Sjimharris__FBSDID("$FreeBSD: head/tools/regression/bpf/bpf_filter/bpf_test.c 182175 2008-08-25 21:33:12Z jkim $"); 28240616Sjimharris 29240616Sjimharris#include <signal.h> 30240616Sjimharris#include <stdio.h> 31240616Sjimharris#include <stdlib.h> 32240616Sjimharris 33240616Sjimharris#include <sys/types.h> 34240616Sjimharris 35240616Sjimharris#include <net/bpf.h> 36240616Sjimharris 37240616Sjimharris#include BPF_TEST_H 38240616Sjimharris 39240616Sjimharris#define PASSED 0 40240616Sjimharris#define FAILED 1 41240616Sjimharris#define FATAL -1 42240616Sjimharris 43240616Sjimharris#ifndef LOG_LEVEL 44240616Sjimharris#define LOG_LEVEL 1 45240616Sjimharris#endif 46240616Sjimharris 47240616Sjimharrisstatic void sig_handler(int); 48240616Sjimharris 49240616Sjimharrisstatic int nins = sizeof(pc) / sizeof(pc[0]); 50240616Sjimharrisstatic int verbose = LOG_LEVEL; 51240616Sjimharris 52240616Sjimharris#ifdef BPF_JIT_COMPILER 53240616Sjimharris 54240616Sjimharris#include <string.h> 55240616Sjimharris 56240616Sjimharris#include <net/bpf_jitter.h> 57240616Sjimharris 58240616Sjimharrisbpf_filter_func bpf_jit_compile(struct bpf_insn *, u_int, int *); 59240616Sjimharris 60240616Sjimharrisstatic u_int 61240616Sjimharrisbpf_compile_and_filter(void) 62240616Sjimharris{ 63240616Sjimharris bpf_jit_filter filter; 64240616Sjimharris u_int ret; 65240616Sjimharris 66240616Sjimharris /* Do not use BPF JIT compiler for an empty program */ 67240616Sjimharris if (nins == 0) 68240616Sjimharris return (0); 69240616Sjimharris 70240616Sjimharris /* Create the binary */ 71240616Sjimharris if ((filter.func = bpf_jit_compile(pc, nins, filter.mem)) == NULL) { 72240616Sjimharris if (verbose > 1) 73240616Sjimharris printf("Failed to allocate memory:\t"); 74240616Sjimharris if (verbose > 0) 75240616Sjimharris printf("FATAL\n"); 76240616Sjimharris exit(FATAL); 77240616Sjimharris } 78240616Sjimharris 79240616Sjimharris ret = (*(filter.func))(pkt, wirelen, buflen); 80240616Sjimharris 81240616Sjimharris free(filter.func); 82240616Sjimharris 83240616Sjimharris return (ret); 84240616Sjimharris} 85240616Sjimharris 86240616Sjimharris#else 87240616Sjimharris 88240616Sjimharrisu_int bpf_filter(struct bpf_insn *, u_char *, u_int, u_int); 89240616Sjimharris 90240616Sjimharris#endif 91240616Sjimharris 92240616Sjimharris#ifdef BPF_VALIDATE 93240616Sjimharris/* 94240616Sjimharris * XXX Copied from sys/net/bpf_filter.c and modified. 95240616Sjimharris * 96240616Sjimharris * Return true if the 'fcode' is a valid filter program. 97240616Sjimharris * The constraints are that each jump be forward and to a valid 98240616Sjimharris * code. The code must terminate with either an accept or reject. 99240616Sjimharris * 100240616Sjimharris * The kernel needs to be able to verify an application's filter code. 101240616Sjimharris * Otherwise, a bogus program could easily crash the system. 102240616Sjimharris */ 103240616Sjimharrisstatic int 104240616Sjimharrisbpf_validate(const struct bpf_insn *f, int len) 105240616Sjimharris{ 106240616Sjimharris register int i; 107240616Sjimharris register const struct bpf_insn *p; 108240616Sjimharris 109240616Sjimharris /* Do not accept negative length filter. */ 110240616Sjimharris if (len < 0) 111240616Sjimharris return (0); 112240616Sjimharris 113240616Sjimharris /* An empty filter means accept all. */ 114240616Sjimharris if (len == 0) 115240616Sjimharris return (1); 116240616Sjimharris 117240616Sjimharris for (i = 0; i < len; ++i) { 118240616Sjimharris /* 119240616Sjimharris * Check that that jumps are forward, and within 120240616Sjimharris * the code block. 121 */ 122 p = &f[i]; 123 if (BPF_CLASS(p->code) == BPF_JMP) { 124 register int from = i + 1; 125 126 if (BPF_OP(p->code) == BPF_JA) { 127 if (from >= len || p->k >= (u_int)len - from) 128 return (0); 129 } 130 else if (from >= len || p->jt >= len - from || 131 p->jf >= len - from) 132 return (0); 133 } 134 /* 135 * Check that memory operations use valid addresses. 136 */ 137 if ((BPF_CLASS(p->code) == BPF_ST || 138 (BPF_CLASS(p->code) == BPF_LD && 139 (p->code & 0xe0) == BPF_MEM)) && 140 p->k >= BPF_MEMWORDS) 141 return (0); 142 /* 143 * Check for constant division by 0. 144 */ 145 if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0) 146 return (0); 147 } 148 return (BPF_CLASS(f[len - 1].code) == BPF_RET); 149} 150#endif 151 152int 153main(void) 154{ 155 u_int ret; 156 int sig; 157#ifdef BPF_VALIDATE 158 int valid; 159#endif 160 161 /* Try to catch all signals */ 162 for (sig = SIGHUP; sig <= SIGUSR2; sig++) 163 signal(sig, sig_handler); 164 165#ifdef BPF_VALIDATE 166 valid = bpf_validate(pc, nins); 167 if (valid != 0 && invalid != 0) { 168 if (verbose > 1) 169 printf("Validated invalid instructions:\t"); 170 if (verbose > 0) 171 printf("FAILED\n"); 172 return (FAILED); 173 } else if (valid == 0 && invalid == 0) { 174 if (verbose > 1) 175 printf("Invalidated valid instructions:\t"); 176 if (verbose > 0) 177 printf("FAILED\n"); 178 return (FAILED); 179 } 180#endif 181 182#ifdef BPF_JIT_COMPILER 183 ret = bpf_compile_and_filter(); 184#else 185 ret = bpf_filter(pc, pkt, wirelen, buflen); 186#endif 187 if (ret != expect) { 188 if (verbose > 1) 189 printf("Expected 0x%x but got 0x%x:\t", expect, ret); 190 if (verbose > 0) 191 printf("FAILED\n"); 192 return (FAILED); 193 } 194 if (verbose > 1) 195 printf("Expected and got 0x%x:\t", ret); 196 if (verbose > 0) 197 printf("PASSED\n"); 198 199 return (PASSED); 200} 201 202static void 203sig_handler(int sig) 204{ 205 206 if (expect_signal == 0) { 207 if (verbose > 1) 208 printf("Received unexpected signal %d:\t", sig); 209 if (verbose > 0) 210 printf("FATAL\n"); 211 exit(FATAL); 212 } 213 if (expect_signal != sig) { 214 if (verbose > 1) 215 printf("Expected signal %d but got %d:\t", 216 expect_signal, sig); 217 if (verbose > 0) 218 printf("FAILED\n"); 219 exit(FAILED); 220 } 221 222 if (verbose > 1) 223 printf("Expected and got signal %d:\t", sig); 224 if (verbose > 0) 225 printf("PASSED\n"); 226 227 exit(PASSED); 228} 229