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


Reply via email to