Implement the `BPF_MOD` and `BPF_XOR` ALU operations and reject
unknown BPF instructions before they reach the filter interpreter.

* libbpf/bpf_impl.c: Add `bpf_valid_insn` for validate BPF
instructions and implement BPF_MOD and BPF_XOR
---
 libbpf/bpf_impl.c | 123 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 120 insertions(+), 3 deletions(-)

diff --git a/libbpf/bpf_impl.c b/libbpf/bpf_impl.c
index c78176c2..60980b43 100644
--- a/libbpf/bpf_impl.c
+++ b/libbpf/bpf_impl.c
@@ -288,6 +288,16 @@ load_byte:
                                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;
@@ -320,6 +330,14 @@ load_byte:
                                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;
@@ -337,6 +355,97 @@ load_byte:
        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
@@ -363,11 +472,16 @@ bpf_validate(bpf_insn_t f, int bytes, bpf_insn_t *match)
         */
 
        for (i = 1; i < len; ++i) {
+                p = &f[i];
+                /*
+                * Check that the instruction is valid.
+                */
+               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;
 
@@ -388,11 +502,14 @@ bpf_validate(bpf_insn_t f, int bytes, bpf_insn_t *match)
                        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.
-- 
2.55.0


Reply via email to