1 /* 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: (1) source code distributions 7 * retain the above copyright notice and this paragraph in its entirety, (2) 8 * distributions including binary code include the above copyright notice and 9 * this paragraph in its entirety in the documentation or other materials 10 * provided with the distribution, and (3) all advertising materials mentioning 11 * features or use of this software display the following acknowledgement: 12 * ``This product includes software developed by the University of California, 13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14 * the University nor the names of its contributors may be used to endorse 15 * or promote products derived from this software without specific prior 16 * written permission. 17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20 */ 21 #if !(defined(lint) || defined(KERNEL)) 22 static char rcsid[] = 23 "@(#) $Header: bpf_filter.c,v 1.9 91/01/30 18:21:54 mccanne Exp $ (LBL)"; 24 #endif 25 26 #include <sys/param.h> 27 #include <sys/types.h> 28 #include <protosw.h> 29 #include <netinet/in.h> 30 #include <sys/time.h> 31 #include <net/bpf.h> 32 33 #if defined(sparc) || defined(mips) 34 #define ALIGN 35 #endif 36 37 #ifndef ALIGN 38 #define EXTRACT_SHORT(p) (ntohs(*(u_short *)p)) 39 #define EXTRACT_LONG(p) (ntohl(*(u_long *)p)) 40 #else 41 #define EXTRACT_SHORT(p)\ 42 ((u_short)\ 43 (*((u_char *)p+0)<<8|\ 44 *((u_char *)p+1)<<0)) 45 #define EXTRACT_LONG(p)\ 46 (*((u_char *)p+0)<<24|\ 47 *((u_char *)p+1)<<16|\ 48 *((u_char *)p+2)<<8|\ 49 *((u_char *)p+3)<<0) 50 #endif 51 52 /* 53 * Execute the filter program pointed to by 'pc' on the 54 * packet pointed to by 'p'. 'wirelen' is the length of actual 55 * packet received by the interface. 'buflen' is the amount of 56 * contiguous data. The return value is the return value of the 57 * filter program, or 0 on an error. 58 */ 59 u_int 60 bpf_filter(pc, p, wirelen, buflen) 61 register struct bpf_insn *pc; 62 register u_char *p; 63 u_int wirelen; 64 u_int buflen; 65 { 66 #define JUMP(delta) pc += (delta) 67 #define BR(cond) JUMP((cond) ? pc->jt : pc->jf) 68 69 register long A, X; 70 long mem[BPF_MEMWORDS]; 71 72 if (pc == 0) 73 /* 74 * No filter means accept all. 75 */ 76 return 1; 77 78 #ifdef lint 79 A = 0; 80 X = 0; 81 #endif 82 83 while (1) { 84 85 switch (pc->code) { 86 87 default: 88 #ifdef KERNEL 89 return 0; 90 #else 91 abort(); 92 #endif 93 case RetOp: 94 return (u_int)pc->k; 95 96 case RetAOp: 97 return (u_int)A; 98 99 case LdOp: 100 if (pc->k + sizeof(long) > buflen) 101 return 0; 102 A = EXTRACT_LONG(&p[pc->k]); 103 break; 104 105 case LdHOp: 106 if (pc->k + sizeof(short) > buflen) 107 return 0; 108 A = EXTRACT_SHORT(&p[pc->k]); 109 break; 110 111 case LdBOp: 112 if (pc->k >= buflen) 113 return 0; 114 A = p[pc->k]; 115 break; 116 117 case LdLenOp: 118 A = wirelen; 119 break; 120 121 case ILdOp: 122 if (X + pc->k + sizeof(long) > buflen) 123 return 0; 124 A = EXTRACT_LONG(&p[X + pc->k]); 125 break; 126 127 case ILdHOp: 128 if (X + pc->k + sizeof(short) > buflen) 129 return 0; 130 A = EXTRACT_SHORT(&p[X + pc->k]); 131 break; 132 133 case ILdBOp: 134 if (X + pc->k >= buflen) 135 return 0; 136 A = p[X + pc->k]; 137 break; 138 139 case LdIOp: 140 A = pc->k; 141 break; 142 143 case LdXIOp: 144 X = pc->k; 145 break; 146 147 case LdxmsOp: 148 if (pc->k >= buflen) 149 return 0; 150 X = (p[pc->k] & 0xf) << 2; 151 break; 152 153 case TaxOp: 154 X = A; 155 break; 156 157 case TxaOp: 158 A = X; 159 break; 160 161 case StmOp: 162 mem[pc->k] = A; 163 break; 164 165 case LdmOp: 166 A = mem[pc->k]; 167 break; 168 169 case StmXOp: 170 mem[pc->k] = X; 171 break; 172 173 case LdmXOp: 174 X = mem[pc->k]; 175 break; 176 177 case NopOp: 178 break; 179 180 case GTOp: 181 BR(A > pc->k); 182 continue; 183 184 case GEOp: 185 BR(A >= pc->k); 186 continue; 187 188 case EQOp: 189 BR(A == pc->k); 190 continue; 191 192 case AddXOp: 193 A += X; 194 break; 195 196 case SubXOp: 197 A -= X; 198 break; 199 200 case MulXOp: 201 A *= X; 202 break; 203 204 case DivXOp: 205 if (X == 0) 206 return 0; 207 A /= X; 208 break; 209 210 case AndXOp: 211 A &= X; 212 break; 213 214 case OrXOp: 215 A |= X; 216 break; 217 218 case LshXOp: 219 A <<= X; 220 break; 221 222 case RshXOp: 223 A >>= X; 224 break; 225 226 case AddIOp: 227 A += pc->k; 228 break; 229 230 case SubIOp: 231 A -= pc->k; 232 break; 233 234 case MulIOp: 235 A *= pc->k; 236 break; 237 238 case DivIOp: 239 if (pc->k == 0) 240 return 0; 241 A /= pc->k; 242 break; 243 244 case AndIOp: 245 A &= pc->k; 246 break; 247 248 case OrIOp: 249 A |= pc->k; 250 break; 251 252 case LshIOp: 253 A <<= pc->k; 254 break; 255 256 case RshIOp: 257 A >>= pc->k; 258 break; 259 260 case NegOp: 261 A = -A; 262 break; 263 } 264 ++pc; 265 } 266 } 267 268 #ifdef KERNEL 269 /* 270 * Return true if the 'fcode' is a valid filter program. 271 * The constraints are that each jump be forward and to a valid 272 * code. The code must terminate with either an accept or reject. 273 * 'valid' is an array for use by the routine (it must be at least 274 * 'len' bytes long). 275 * 276 * The kernel needs to be able to verify an application's filter code. 277 * Otherwise, a bogus program could easily crash the system. 278 */ 279 int 280 bpf_validate(fcode, len) 281 struct bpf_insn *fcode; 282 int len; 283 { 284 struct bpf_insn *p; 285 int i; 286 287 p = fcode; 288 for (i = 0; i < len; ++p, ++i) 289 if (!BPF_VALIDCODE(p->code)) 290 return 0; 291 p = fcode; 292 for (i = 0; i < len; ++p, ++i) { 293 /* 294 * Check that that jumps are forward, and within 295 * the code block. 296 */ 297 if (BPF_ISJUMP(p->code) && 298 (p->jt <= 0 || i + p->jt >= len || 299 p->jf <= 0 || i + p->jf >= len)) 300 return 0; 301 /* 302 * Check that memory operations use valid addresses. 303 */ 304 switch (p->code) { 305 case StmOp: 306 case StmXOp: 307 case LdmOp: 308 case LdmXOp: 309 if (p->k >= BPF_MEMWORDS || p->k < 0) 310 return 0; 311 } 312 } 313 return BPF_ISLEAF(fcode[len - 1].code); 314 } 315 #endif 316