Implement the BPF_MOD and BPF_XOR ALU operations and validate BPF
instructions before they are executed.
* include/device/bpf.h: Define `BPF_MOD` and `BPF_XOR`.
* device/net_io.c: Implement BPF_MOD and BPF_XOR and add
`bpf_valid_insn` to validate BPF instructions.
---
device/net_io.c | 120 +++++++++++++++++++++++++++++++++++++++++--
include/device/bpf.h | 2 +
2 files changed, 118 insertions(+), 4 deletions(-)
diff --git a/device/net_io.c b/device/net_io.c
index 7b5c3e74..4b69ea81 100644
--- a/device/net_io.c
+++ b/device/net_io.c
@@ -1803,6 +1803,16 @@ bpf_do_filter(
A >>= X;
continue;
+ case BPF_ALU|BPF_MOD|BPF_X:
+ if (X == 0)
+ return 0;
+ A %= X;
+ continue;
+
+ case BPF_ALU|BPF_XOR|BPF_X:
+ A ^= X;
+ continue;
+
case BPF_ALU|BPF_ADD|BPF_K:
A += pc->k;
continue;
@@ -1835,6 +1845,14 @@ bpf_do_filter(
A >>= pc->k;
continue;
+ case BPF_ALU|BPF_MOD|BPF_K:
+ A %= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_XOR|BPF_K:
+ A ^= pc->k;
+ continue;
+
case BPF_ALU|BPF_NEG:
A = -A;
continue;
@@ -1852,6 +1870,97 @@ bpf_do_filter(
return 0;
}
+/*
+ * Return 1 if 'code' is a valid BPF instruction.
+ */
+static int
+bpf_valid_insn (unsigned short code)
+{
+ switch (BPF_CLASS(code)) {
+ /*
+ * Check BPF_LD and BPF_LDX modes.
+ */
+ case BPF_LD:
+ case BPF_LDX:
+ if (BPF_SRC(code) != BPF_K)
+ return 0;
+ switch (BPF_MODE(code)) {
+ case BPF_IMM:
+ return BPF_SIZE (code) == BPF_W;
+ case BPF_ABS:
+ case BPF_IND:
+ return BPF_CLASS (code) == BPF_LD
+ && (BPF_SIZE (code) == BPF_W
+ || BPF_SIZE (code) == BPF_H
+ || BPF_SIZE (code) == BPF_B);
+ case BPF_MEM:
+ return BPF_SIZE (code) == BPF_W;
+ case BPF_LEN:
+ return BPF_SIZE (code) == BPF_W;
+ case BPF_MSH:
+ return BPF_CLASS (code) == BPF_LDX
+ && BPF_SIZE (code) == BPF_B;
+ default:
+ return 0;
+ }
+ case BPF_ST:
+ case BPF_STX:
+ return code == BPF_ST || code == BPF_STX;
+ case BPF_ALU:
+ switch (BPF_OP (code)) {
+ case BPF_ADD:
+ case BPF_SUB:
+ case BPF_MUL:
+ case BPF_DIV:
+ case BPF_OR:
+ case BPF_AND:
+ case BPF_LSH:
+ case BPF_RSH:
+ case BPF_MOD:
+ case BPF_XOR:
+ return BPF_SRC (code) == BPF_K || BPF_SRC (code) ==
BPF_X;
+ case BPF_NEG:
+ /* BPF_NEG has no second operand. */
+ return BPF_SRC (code) == BPF_K;
+ default:
+ return 0;
+ }
+ case BPF_JMP:
+ switch (BPF_OP (code)) {
+ case BPF_JA:
+ return BPF_SRC (code) == BPF_K;
+ case BPF_JEQ:
+ case BPF_JGT:
+ case BPF_JGE:
+ case BPF_JSET:
+ return BPF_SRC (code) == BPF_K || BPF_SRC (code) ==
BPF_X;
+ default:
+ return 0;
+ }
+ case BPF_RET:
+ if (code & 0xe0)
+ return 0;
+ switch (BPF_RVAL (code)) {
+ case BPF_K:
+ case BPF_A:
+ case BPF_MATCH_IMM:
+ return 1;
+ default:
+ return 0;
+ }
+ case BPF_MISC:
+ switch (BPF_MISCOP (code)) {
+ case BPF_TAX:
+ case BPF_TXA:
+ return 1;
+ default:
+ return 0;
+ }
+ default:
+ return 0;
+ }
+}
+
/*
* Return 1 if the 'f' is a valid filter program without a MATCH
* instruction. Return 2 if it is a valid filter program with a MATCH
@@ -1881,11 +1990,13 @@ bpf_validate(
*/
for (i = 1; i < len; ++i) {
+ p = &f[i];
+ if (!bpf_valid_insn (p->code))
+ return 0;
/*
- * Check that that jumps are forward, and within
+ * Check that jumps are forward, and within
* the code block.
*/
- p = &f[i];
if (BPF_CLASS(p->code) == BPF_JMP) {
int from = i + 1;
@@ -1905,10 +2016,12 @@ bpf_validate(
(p->k >= BPF_MEMWORDS || p->k < 0))
return 0;
/*
- * Check for constant division by 0.
+ * Check for constant division or modulo by 0.
*/
if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0)
return 0;
+ if (p->code == (BPF_ALU|BPF_MOD|BPF_K) && p->k == 0)
+ return 0;
/*
* Check for match instruction.
* Only one match instruction per filter is allowed.
@@ -2125,4 +2238,3 @@ net_free_dead_entp(queue_entry_t dead_entp)
kmem_cache_free(&net_hash_entry_cache, (vm_offset_t) entp);
}
}
-
diff --git a/include/device/bpf.h b/include/device/bpf.h
index 1d00e8c6..b2d5a6e7 100644
--- a/include/device/bpf.h
+++ b/include/device/bpf.h
@@ -154,6 +154,8 @@ struct bpf_version {
#define BPF_LSH 0x60
#define BPF_RSH 0x70
#define BPF_NEG 0x80
+#define BPF_MOD 0x90
+#define BPF_XOR 0xa0
#define BPF_JA 0x00
#define BPF_JEQ 0x10
#define BPF_JGT 0x20
--
2.55.0