1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from the Stanford/CMU enet packet filter, 6 * (net/enet.c) distributed as part of 4.3BSD, and code contributed 7 * to Berkeley by Steven McCanne of Lawrence Berkeley Laboratory. 8 * 9 * %sccs.include.redist.c% 10 * 11 * @(#)bpf_filter.c 7.1 (Berkeley) 05/07/91 12 * 13 * static char rcsid[] = 14 * "@(#) $Header: bpf_filter.c,v 1.10 91/04/24 22:07:07 mccanne Locked $ (LBL)"; 15 */ 16 17 #include <sys/param.h> 18 #include <sys/types.h> 19 #include <sys/time.h> 20 #include <net/bpf.h> 21 22 #if defined(sparc) || defined(mips) 23 #define ALIGN 24 #endif 25 26 #ifndef ALIGN 27 #define EXTRACT_SHORT(p) (ntohs(*(u_short *)p)) 28 #define EXTRACT_LONG(p) (ntohl(*(u_long *)p)) 29 #else 30 #define EXTRACT_SHORT(p)\ 31 ((u_short)\ 32 (*((u_char *)p+0)<<8|\ 33 *((u_char *)p+1)<<0)) 34 #define EXTRACT_LONG(p)\ 35 (*((u_char *)p+0)<<24|\ 36 *((u_char *)p+1)<<16|\ 37 *((u_char *)p+2)<<8|\ 38 *((u_char *)p+3)<<0) 39 #endif 40 41 #ifdef KERNEL 42 #include <sys/mbuf.h> 43 #define MINDEX(m, k) \ 44 { \ 45 register int len = m->m_len; \ 46 \ 47 while (k >= len) { \ 48 k -= len; \ 49 m = m->m_next; \ 50 if (m == 0) \ 51 return 0; \ 52 len = m->m_len; \ 53 } \ 54 } 55 #endif 56 57 /* 58 * Execute the filter program starting at pc on the packet p 59 * wirelen is the length of the original packet 60 * buflen is the amount of data present 61 */ 62 u_int 63 bpf_filter(pc, p, wirelen, buflen) 64 register struct bpf_insn *pc; 65 register u_char *p; 66 u_int wirelen; 67 register u_int buflen; 68 { 69 register long A, X; 70 register int k; 71 long mem[BPF_MEMWORDS]; 72 73 if (pc == 0) 74 /* 75 * No filter means accept all. 76 */ 77 return (u_int)-1; 78 #ifdef lint 79 A = 0; 80 X = 0; 81 #endif 82 --pc; 83 while (1) { 84 ++pc; 85 switch (pc->code) { 86 87 default: 88 #ifdef KERNEL 89 return 0; 90 #else 91 abort(); 92 #endif 93 case BPF_RET|BPF_K: 94 return (u_int)pc->k; 95 96 case BPF_RET|BPF_A: 97 return (u_int)A; 98 99 case BPF_LD|BPF_W|BPF_ABS: 100 k = pc->k; 101 if (k + sizeof(long) > buflen) { 102 #ifdef KERNEL 103 register struct mbuf *m; 104 105 if (buflen != 0) 106 return 0; 107 m = (struct mbuf *)p; 108 MINDEX(m, k); 109 A = EXTRACT_LONG(mtod(m, char *) + k); 110 break; 111 #else 112 return 0; 113 #endif 114 } 115 #ifdef ALIGN 116 if (((int)(p + k) & 3) != 0) 117 A = EXTRACT_LONG(&p[k]); 118 else 119 #endif 120 A = *(long *)(p + k); 121 break; 122 123 case BPF_LD|BPF_H|BPF_ABS: 124 k = pc->k; 125 if (k + sizeof(short) > buflen) { 126 #ifdef KERNEL 127 register struct mbuf *m; 128 129 if (buflen != 0) 130 return 0; 131 m = (struct mbuf *)p; 132 MINDEX(m, k); 133 A = EXTRACT_SHORT(mtod(m, char *) + k); 134 break; 135 #else 136 return 0; 137 #endif 138 } 139 A = EXTRACT_SHORT(&p[k]); 140 break; 141 142 case BPF_LD|BPF_B|BPF_ABS: 143 k = pc->k; 144 if (k >= buflen) { 145 #ifdef KERNEL 146 register struct mbuf *m; 147 148 if (buflen != 0) 149 return 0; 150 m = (struct mbuf *)p; 151 MINDEX(m, k); 152 A = mtod(m, char *)[k]; 153 break; 154 #else 155 return 0; 156 #endif 157 } 158 A = p[k]; 159 break; 160 161 case BPF_LD|BPF_W|BPF_LEN: 162 A = wirelen; 163 break; 164 165 case BPF_LDX|BPF_W|BPF_LEN: 166 X = wirelen; 167 break; 168 169 case BPF_LD|BPF_W|BPF_IND: 170 k = X + pc->k; 171 if (k + sizeof(long) > buflen) { 172 #ifdef KERNEL 173 register struct mbuf *m; 174 175 if (buflen != 0) 176 return 0; 177 m = (struct mbuf *)p; 178 MINDEX(m, k); 179 A = EXTRACT_LONG(mtod(m, char *) + k); 180 break; 181 #else 182 return 0; 183 #endif 184 } 185 #ifdef ALIGN 186 if (((int)(p + k) & 3) != 0) 187 A = EXTRACT_LONG(&p[k]); 188 else 189 #endif 190 A = *(long *)(p + k); 191 break; 192 193 case BPF_LD|BPF_H|BPF_IND: 194 k = X + pc->k; 195 if (k + sizeof(short) > buflen) { 196 #ifdef KERNEL 197 register struct mbuf *m; 198 199 if (buflen != 0) 200 return 0; 201 m = (struct mbuf *)p; 202 MINDEX(m, k); 203 A = EXTRACT_SHORT(mtod(m, char *) + k); 204 break; 205 #else 206 return 0; 207 #endif 208 } 209 A = EXTRACT_SHORT(&p[k]); 210 break; 211 212 case BPF_LD|BPF_B|BPF_IND: 213 k = X + pc->k; 214 if (k >= buflen) { 215 #ifdef KERNEL 216 register struct mbuf *m; 217 218 if (buflen != 0) 219 return 0; 220 m = (struct mbuf *)p; 221 MINDEX(m, k); 222 A = mtod(m, char *)[k]; 223 break; 224 #else 225 return 0; 226 #endif 227 } 228 A = p[k]; 229 break; 230 231 case BPF_LDX|BPF_MSH|BPF_B: 232 k = pc->k; 233 if (k >= buflen) { 234 #ifdef KERNEL 235 register struct mbuf *m; 236 237 if (buflen != 0) 238 return 0; 239 m = (struct mbuf *)p; 240 MINDEX(m, k); 241 X = (mtod(m, char *)[k] & 0xf) << 2; 242 break; 243 #else 244 return 0; 245 #endif 246 } 247 X = (p[pc->k] & 0xf) << 2; 248 break; 249 250 case BPF_LD|BPF_IMM: 251 A = pc->k; 252 break; 253 254 case BPF_LDX|BPF_IMM: 255 X = pc->k; 256 break; 257 258 case BPF_LD|BPF_MEM: 259 A = mem[pc->k]; 260 break; 261 262 case BPF_LDX|BPF_MEM: 263 X = mem[pc->k]; 264 break; 265 266 case BPF_ST: 267 mem[pc->k] = A; 268 break; 269 270 case BPF_STX: 271 mem[pc->k] = X; 272 break; 273 274 case BPF_JMP|BPF_JA: 275 pc += pc->k; 276 break; 277 278 case BPF_JMP|BPF_JGT|BPF_K: 279 pc += (A > pc->k) ? pc->jt : pc->jf; 280 break; 281 282 case BPF_JMP|BPF_JGE|BPF_K: 283 pc += (A >= pc->k) ? pc->jt : pc->jf; 284 break; 285 286 case BPF_JMP|BPF_JEQ|BPF_K: 287 pc += (A == pc->k) ? pc->jt : pc->jf; 288 break; 289 290 case BPF_JMP|BPF_JSET|BPF_K: 291 pc += (A & pc->k) ? pc->jt : pc->jf; 292 break; 293 294 case BPF_JMP|BPF_JGT|BPF_X: 295 pc += (A > X) ? pc->jt : pc->jf; 296 break; 297 298 case BPF_JMP|BPF_JGE|BPF_X: 299 pc += (A >= X) ? pc->jt : pc->jf; 300 break; 301 302 case BPF_JMP|BPF_JEQ|BPF_X: 303 pc += (A == X) ? pc->jt : pc->jf; 304 break; 305 306 case BPF_JMP|BPF_JSET|BPF_X: 307 pc += (A & X) ? pc->jt : pc->jf; 308 break; 309 310 case BPF_ALU|BPF_ADD|BPF_X: 311 A += X; 312 break; 313 314 case BPF_ALU|BPF_SUB|BPF_X: 315 A -= X; 316 break; 317 318 case BPF_ALU|BPF_MUL|BPF_X: 319 A *= X; 320 break; 321 322 case BPF_ALU|BPF_DIV|BPF_X: 323 if (X == 0) 324 return 0; 325 A /= X; 326 break; 327 328 case BPF_ALU|BPF_AND|BPF_X: 329 A &= X; 330 break; 331 332 case BPF_ALU|BPF_OR|BPF_X: 333 A |= X; 334 break; 335 336 case BPF_ALU|BPF_LSH|BPF_X: 337 A <<= X; 338 break; 339 340 case BPF_ALU|BPF_RSH|BPF_X: 341 A >>= X; 342 break; 343 344 case BPF_ALU|BPF_ADD|BPF_K: 345 A += pc->k; 346 break; 347 348 case BPF_ALU|BPF_SUB|BPF_K: 349 A -= pc->k; 350 break; 351 352 case BPF_ALU|BPF_MUL|BPF_K: 353 A *= pc->k; 354 break; 355 356 case BPF_ALU|BPF_DIV|BPF_K: 357 A /= pc->k; 358 break; 359 360 case BPF_ALU|BPF_AND|BPF_K: 361 A &= pc->k; 362 break; 363 364 case BPF_ALU|BPF_OR|BPF_K: 365 A |= pc->k; 366 break; 367 368 case BPF_ALU|BPF_LSH|BPF_K: 369 A <<= pc->k; 370 break; 371 372 case BPF_ALU|BPF_RSH|BPF_K: 373 A >>= pc->k; 374 break; 375 376 case BPF_ALU|BPF_NEG: 377 A = -A; 378 break; 379 380 case BPF_MISC|BPF_TAX: 381 X = A; 382 break; 383 384 case BPF_MISC|BPF_TXA: 385 A = X; 386 break; 387 } 388 } 389 } 390 391 #ifdef KERNEL 392 /* 393 * Return true if the 'fcode' is a valid filter program. 394 * The constraints are that each jump be forward and to a valid 395 * code. The code must terminate with either an accept or reject. 396 * 'valid' is an array for use by the routine (it must be at least 397 * 'len' bytes long). 398 * 399 * The kernel needs to be able to verify an application's filter code. 400 * Otherwise, a bogus program could easily crash the system. 401 */ 402 int 403 bpf_validate(f, len) 404 struct bpf_insn *f; 405 int len; 406 { 407 register int i; 408 register struct bpf_insn *p; 409 410 for (i = 0; i < len; ++i) { 411 /* 412 * Check that that jumps are forward, and within 413 * the code block. 414 */ 415 p = &f[i]; 416 if (BPF_CLASS(p->code) == BPF_JMP) { 417 register int from = i + 1; 418 419 if (BPF_OP(p->code) == BPF_JA) { 420 if (from + p->k >= len) 421 return 0; 422 } 423 else if (from + p->jt >= len || from + p->jf >= len) 424 return 0; 425 } 426 /* 427 * Check that memory operations use valid addresses. 428 */ 429 if ((BPF_CLASS(p->code) == BPF_ST || 430 (BPF_CLASS(p->code) == BPF_LD && 431 (p->code & 0xe0) == BPF_MEM)) && 432 (p->k >= BPF_MEMWORDS || p->k < 0)) 433 return 0; 434 /* 435 * Check for constant division by 0. 436 */ 437 if (p->code == BPF_ALU|BPF_DIV|BPF_K && p->k == 0) 438 return; 439 } 440 return BPF_CLASS(f[len - 1].code) == BPF_RET; 441 } 442 #endif 443