Implement BPF_MOD and BPF_XOR instructions.

These two ALU instructions first appeared on Linux.  Then, libpcap adopted
and made them available since 1.6.2.  Now more platforms including NetBSD
have them in kernel.  So do we.
 --이 줄 이하는 자동으로 제거됩니다--
This commit is contained in:
Jung-uk Kim 2016-10-21 06:55:07 +00:00
parent ffaa5deb38
commit 69d410eeb1
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=307707
6 changed files with 96 additions and 8 deletions

View File

@ -49,7 +49,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd June 15, 2010
.Dd October 21, 2016
.Dt BPF 4
.Os
.Sh NAME
@ -881,16 +881,20 @@ BPF_ALU+BPF_ADD+BPF_K A <- A + k
BPF_ALU+BPF_SUB+BPF_K A <- A - k
BPF_ALU+BPF_MUL+BPF_K A <- A * k
BPF_ALU+BPF_DIV+BPF_K A <- A / k
BPF_ALU+BPF_MOD+BPF_K A <- A % k
BPF_ALU+BPF_AND+BPF_K A <- A & k
BPF_ALU+BPF_OR+BPF_K A <- A | k
BPF_ALU+BPF_XOR+BPF_K A <- A ^ k
BPF_ALU+BPF_LSH+BPF_K A <- A << k
BPF_ALU+BPF_RSH+BPF_K A <- A >> k
BPF_ALU+BPF_ADD+BPF_X A <- A + X
BPF_ALU+BPF_SUB+BPF_X A <- A - X
BPF_ALU+BPF_MUL+BPF_X A <- A * X
BPF_ALU+BPF_DIV+BPF_X A <- A / X
BPF_ALU+BPF_MOD+BPF_X A <- A % X
BPF_ALU+BPF_AND+BPF_X A <- A & X
BPF_ALU+BPF_OR+BPF_X A <- A | X
BPF_ALU+BPF_XOR+BPF_X A <- A ^ X
BPF_ALU+BPF_LSH+BPF_X A <- A << X
BPF_ALU+BPF_RSH+BPF_X A <- A >> X
BPF_ALU+BPF_NEG A <- -A

View File

@ -1,6 +1,6 @@
/*-
* Copyright (C) 2002-2003 NetGroup, Politecnico di Torino (Italy)
* Copyright (C) 2005-2009 Jung-uk Kim <jkim@FreeBSD.org>
* Copyright (C) 2005-2016 Jung-uk Kim <jkim@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -494,6 +494,7 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
break;
case BPF_ALU|BPF_DIV|BPF_X:
case BPF_ALU|BPF_MOD|BPF_X:
TESTrd(EDX, EDX);
if (fmem) {
JNEb(4);
@ -507,6 +508,8 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
MOVrd(EDX, ECX);
ZEROrd(EDX);
DIVrd(ECX);
if (BPF_OP(ins->code) == BPF_MOD)
MOVrd(EDX, EAX);
MOVrd(ECX, EDX);
break;
@ -518,6 +521,10 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
ORrd(EDX, EAX);
break;
case BPF_ALU|BPF_XOR|BPF_X:
XORrd(EDX, EAX);
break;
case BPF_ALU|BPF_LSH|BPF_X:
MOVrd(EDX, ECX);
SHL_CLrb(EAX);
@ -544,10 +551,13 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
break;
case BPF_ALU|BPF_DIV|BPF_K:
case BPF_ALU|BPF_MOD|BPF_K:
MOVrd(EDX, ECX);
ZEROrd(EDX);
MOVid(ins->k, ESI);
DIVrd(ESI);
if (BPF_OP(ins->code) == BPF_MOD)
MOVrd(EDX, EAX);
MOVrd(ECX, EDX);
break;
@ -559,6 +569,10 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
ORid(ins->k, EAX);
break;
case BPF_ALU|BPF_XOR|BPF_K:
XORid(ins->k, EAX);
break;
case BPF_ALU|BPF_LSH|BPF_K:
SHLib((ins->k) & 0xff, EAX);
break;

View File

@ -1,6 +1,6 @@
/*-
* Copyright (C) 2002-2003 NetGroup, Politecnico di Torino (Italy)
* Copyright (C) 2005-2009 Jung-uk Kim <jkim@FreeBSD.org>
* Copyright (C) 2005-2016 Jung-uk Kim <jkim@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -357,6 +357,24 @@ typedef void (*emit_func)(bpf_bin_stream *stream, u_int value, u_int n);
emitm(&stream, i32, 4); \
} while (0)
/* xorl sr32,dr32 */
#define XORrd(sr32, dr32) do { \
emitm(&stream, 0x31, 1); \
emitm(&stream, \
(3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \
} while (0)
/* xorl i32,r32 */
#define XORid(i32, r32) do { \
if (r32 == EAX) { \
emitm(&stream, 0x35, 1); \
} else { \
emitm(&stream, 0x81, 1); \
emitm(&stream, (25 << 3) | r32, 1); \
} \
emitm(&stream, i32, 4); \
} while (0)
/* shll i8,r32 */
#define SHLib(i8, r32) do { \
emitm(&stream, 0xc1, 1); \

View File

@ -1,6 +1,6 @@
/*-
* Copyright (C) 2002-2003 NetGroup, Politecnico di Torino (Italy)
* Copyright (C) 2005-2009 Jung-uk Kim <jkim@FreeBSD.org>
* Copyright (C) 2005-2016 Jung-uk Kim <jkim@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -139,6 +139,7 @@ bpf_jit_optimize(struct bpf_insn *prog, u_int nins)
flags |= BPF_JIT_FJMP;
break;
case BPF_ALU|BPF_DIV|BPF_K:
case BPF_ALU|BPF_MOD|BPF_K:
flags |= BPF_JIT_FADK;
break;
}
@ -515,6 +516,7 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
break;
case BPF_ALU|BPF_DIV|BPF_X:
case BPF_ALU|BPF_MOD|BPF_X:
TESTrd(EDX, EDX);
if (save_esp) {
if (fpkt) {
@ -536,6 +538,8 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
MOVrd(EDX, ECX);
ZEROrd(EDX);
DIVrd(ECX);
if (BPF_OP(ins->code) == BPF_MOD)
MOVrd(EDX, EAX);
MOVrd(ECX, EDX);
break;
@ -547,6 +551,10 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
ORrd(EDX, EAX);
break;
case BPF_ALU|BPF_XOR|BPF_X:
XORrd(EDX, EAX);
break;
case BPF_ALU|BPF_LSH|BPF_X:
MOVrd(EDX, ECX);
SHL_CLrb(EAX);
@ -573,10 +581,13 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
break;
case BPF_ALU|BPF_DIV|BPF_K:
case BPF_ALU|BPF_MOD|BPF_K:
MOVrd(EDX, ECX);
ZEROrd(EDX);
MOVid(ins->k, ESI);
DIVrd(ESI);
if (BPF_OP(ins->code) == BPF_MOD)
MOVrd(EDX, EAX);
MOVrd(ECX, EDX);
break;
@ -588,6 +599,10 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
ORid(ins->k, EAX);
break;
case BPF_ALU|BPF_XOR|BPF_K:
XORid(ins->k, EAX);
break;
case BPF_ALU|BPF_LSH|BPF_K:
SHLib((ins->k) & 0xff, EAX);
break;

View File

@ -1,6 +1,6 @@
/*-
* Copyright (C) 2002-2003 NetGroup, Politecnico di Torino (Italy)
* Copyright (C) 2005-2009 Jung-uk Kim <jkim@FreeBSD.org>
* Copyright (C) 2005-2016 Jung-uk Kim <jkim@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -302,6 +302,24 @@ typedef void (*emit_func)(bpf_bin_stream *stream, u_int value, u_int n);
emitm(&stream, i32, 4); \
} while (0)
/* xorl sr32,dr32 */
#define XORrd(sr32, dr32) do { \
emitm(&stream, 0x31, 1); \
emitm(&stream, \
(3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \
} while (0)
/* xorl i32,r32 */
#define XORid(i32, r32) do { \
if (r32 == EAX) { \
emitm(&stream, 0x35, 1); \
} else { \
emitm(&stream, 0x81, 1); \
emitm(&stream, (25 << 3) | r32, 1); \
} \
emitm(&stream, i32, 4); \
} while (0)
/* shll i8,r32 */
#define SHLib(i8, r32) do { \
emitm(&stream, 0xc1, 1); \

View File

@ -434,6 +434,12 @@ bpf_filter(const struct bpf_insn *pc, u_char *p, u_int wirelen, u_int buflen)
A /= X;
continue;
case BPF_ALU|BPF_MOD|BPF_X:
if (X == 0)
return (0);
A %= X;
continue;
case BPF_ALU|BPF_AND|BPF_X:
A &= X;
continue;
@ -442,6 +448,10 @@ bpf_filter(const struct bpf_insn *pc, u_char *p, u_int wirelen, u_int buflen)
A |= X;
continue;
case BPF_ALU|BPF_XOR|BPF_X:
A ^= X;
continue;
case BPF_ALU|BPF_LSH|BPF_X:
A <<= X;
continue;
@ -466,6 +476,10 @@ bpf_filter(const struct bpf_insn *pc, u_char *p, u_int wirelen, u_int buflen)
A /= pc->k;
continue;
case BPF_ALU|BPF_MOD|BPF_K:
A %= pc->k;
continue;
case BPF_ALU|BPF_AND|BPF_K:
A &= pc->k;
continue;
@ -474,6 +488,10 @@ bpf_filter(const struct bpf_insn *pc, u_char *p, u_int wirelen, u_int buflen)
A |= pc->k;
continue;
case BPF_ALU|BPF_XOR|BPF_K:
A ^= pc->k;
continue;
case BPF_ALU|BPF_LSH|BPF_K:
A <<= pc->k;
continue;
@ -508,8 +526,8 @@ static const u_short bpf_code_map[] = {
0x1013, /* 0x60-0x6f: 1100100000001000 */
0x1010, /* 0x70-0x7f: 0000100000001000 */
0x0093, /* 0x80-0x8f: 1100100100000000 */
0x0000, /* 0x90-0x9f: 0000000000000000 */
0x0000, /* 0xa0-0xaf: 0000000000000000 */
0x1010, /* 0x90-0x9f: 0000100000001000 */
0x1010, /* 0xa0-0xaf: 0000100000001000 */
0x0002, /* 0xb0-0xbf: 0100000000000000 */
0x0000, /* 0xc0-0xcf: 0000000000000000 */
0x0000, /* 0xd0-0xdf: 0000000000000000 */
@ -577,7 +595,8 @@ bpf_validate(const struct bpf_insn *f, int len)
/*
* Check for constant division by 0.
*/
if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0)
if ((p->code == (BPF_ALU|BPF_DIV|BPF_K) ||
p->code == (BPF_ALU|BPF_MOD|BPF_K)) && p->k == 0)
return (0);
}
return (BPF_CLASS(f[len - 1].code) == BPF_RET);