Module Name: src
Committed By: alnsn
Date: Fri Jul 29 20:29:38 UTC 2016
Modified Files:
src/sys/net: bpfjit.c
Log Message:
Don't trigger BJ_ASSERT(false) on invalid BPF_Jxxx opcode in jmp_to_op().
This change helps survive AFL fuzzing without calling bpf_validate() first.
Also change alu_to_op() function to have a similar interface.
To generate a diff of this commit:
cvs rdiff -u -r1.45 -r1.46 src/sys/net/bpfjit.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/net/bpfjit.c
diff -u src/sys/net/bpfjit.c:1.45 src/sys/net/bpfjit.c:1.46
--- src/sys/net/bpfjit.c:1.45 Sun May 29 17:20:22 2016
+++ src/sys/net/bpfjit.c Fri Jul 29 20:29:38 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: bpfjit.c,v 1.45 2016/05/29 17:20:22 alnsn Exp $ */
+/* $NetBSD: bpfjit.c,v 1.46 2016/07/29 20:29:38 alnsn Exp $ */
/*-
* Copyright (c) 2011-2015 Alexander Nasonov.
@@ -31,9 +31,9 @@
#include <sys/cdefs.h>
#ifdef _KERNEL
-__KERNEL_RCSID(0, "$NetBSD: bpfjit.c,v 1.45 2016/05/29 17:20:22 alnsn Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bpfjit.c,v 1.46 2016/07/29 20:29:38 alnsn Exp $");
#else
-__RCSID("$NetBSD: bpfjit.c,v 1.45 2016/05/29 17:20:22 alnsn Exp $");
+__RCSID("$NetBSD: bpfjit.c,v 1.46 2016/07/29 20:29:38 alnsn Exp $");
#endif
#include <sys/types.h>
@@ -1594,10 +1594,9 @@ optimize(const bpf_ctx_t *bc, const stru
/*
* Convert BPF_ALU operations except BPF_NEG and BPF_DIV to sljit operation.
*/
-static int
-bpf_alu_to_sljit_op(const struct bpf_insn *pc)
+static bool
+alu_to_op(const struct bpf_insn *pc, int *res)
{
- const int bad = SLJIT_UNUSED;
const uint32_t k = pc->k;
/*
@@ -1605,49 +1604,64 @@ bpf_alu_to_sljit_op(const struct bpf_ins
* instruction so SLJIT_I32_OP doesn't have any overhead.
*/
switch (BPF_OP(pc->code)) {
- case BPF_ADD: return SLJIT_ADD;
- case BPF_SUB: return SLJIT_SUB;
- case BPF_MUL: return SLJIT_MUL|SLJIT_I32_OP;
- case BPF_OR: return SLJIT_OR;
- case BPF_XOR: return SLJIT_XOR;
- case BPF_AND: return SLJIT_AND;
- case BPF_LSH: return (k > 31) ? bad : SLJIT_SHL;
- case BPF_RSH: return (k > 31) ? bad : SLJIT_LSHR|SLJIT_I32_OP;
+ case BPF_ADD:
+ *res = SLJIT_ADD;
+ return true;
+ case BPF_SUB:
+ *res = SLJIT_SUB;
+ return true;
+ case BPF_MUL:
+ *res = SLJIT_MUL|SLJIT_I32_OP;
+ return true;
+ case BPF_OR:
+ *res = SLJIT_OR;
+ return true;
+ case BPF_XOR:
+ *res = SLJIT_XOR;
+ return true;
+ case BPF_AND:
+ *res = SLJIT_AND;
+ return true;
+ case BPF_LSH:
+ *res = SLJIT_SHL;
+ return k < 32;
+ case BPF_RSH:
+ *res = SLJIT_LSHR|SLJIT_I32_OP;
+ return k < 32;
default:
- return bad;
+ return false;
}
}
/*
* Convert BPF_JMP operations except BPF_JA to sljit condition.
*/
-static int
-bpf_jmp_to_sljit_cond(const struct bpf_insn *pc, bool negate)
+static bool
+jmp_to_cond(const struct bpf_insn *pc, bool negate, int *res)
{
+
/*
* Note: all supported 64bit arches have 32bit comparison
* instructions so SLJIT_I32_OP doesn't have any overhead.
*/
- int rv = SLJIT_I32_OP;
+ *res = SLJIT_I32_OP;
switch (BPF_OP(pc->code)) {
case BPF_JGT:
- rv |= negate ? SLJIT_LESS_EQUAL : SLJIT_GREATER;
- break;
+ *res |= negate ? SLJIT_LESS_EQUAL : SLJIT_GREATER;
+ return true;
case BPF_JGE:
- rv |= negate ? SLJIT_LESS : SLJIT_GREATER_EQUAL;
- break;
+ *res |= negate ? SLJIT_LESS : SLJIT_GREATER_EQUAL;
+ return true;
case BPF_JEQ:
- rv |= negate ? SLJIT_NOT_EQUAL : SLJIT_EQUAL;
- break;
+ *res |= negate ? SLJIT_NOT_EQUAL : SLJIT_EQUAL;
+ return true;
case BPF_JSET:
- rv |= negate ? SLJIT_EQUAL : SLJIT_NOT_EQUAL;
- break;
+ *res |= negate ? SLJIT_EQUAL : SLJIT_NOT_EQUAL;
+ return true;
default:
- BJ_ASSERT(false);
+ return false;
}
-
- return rv;
}
/*
@@ -1695,9 +1709,9 @@ generate_insn_code(struct sljit_compiler
struct sljit_jump *to_mchain_jump;
size_t i;
- int status;
- int branching, negate;
unsigned int rval, mode, src, op;
+ int branching, negate;
+ int status, cond, op2;
uint32_t jt, jf;
bool unconditional_ret;
@@ -1935,10 +1949,9 @@ generate_insn_code(struct sljit_compiler
op = BPF_OP(pc->code);
if (op != BPF_DIV && op != BPF_MOD) {
- const int op2 = bpf_alu_to_sljit_op(pc);
-
- if (op2 == SLJIT_UNUSED)
+ if (!alu_to_op(pc, &op2))
goto fail;
+
status = sljit_emit_op2(compiler,
op2, BJ_AREG, 0, BJ_AREG, 0,
kx_to_reg(pc), kx_to_reg_arg(pc));
@@ -2005,9 +2018,10 @@ generate_insn_code(struct sljit_compiler
if (branching) {
if (op != BPF_JSET) {
+ if (!jmp_to_cond(pc, negate, &cond))
+ goto fail;
jump = sljit_emit_cmp(compiler,
- bpf_jmp_to_sljit_cond(pc, negate),
- BJ_AREG, 0,
+ cond, BJ_AREG, 0,
kx_to_reg(pc), kx_to_reg_arg(pc));
} else {
status = sljit_emit_op2(compiler,
@@ -2018,10 +2032,10 @@ generate_insn_code(struct sljit_compiler
if (status != SLJIT_SUCCESS)
goto fail;
+ if (!jmp_to_cond(pc, negate, &cond))
+ goto fail;
jump = sljit_emit_cmp(compiler,
- bpf_jmp_to_sljit_cond(pc, negate),
- BJ_TMP1REG, 0,
- SLJIT_IMM, 0);
+ cond, BJ_TMP1REG, 0, SLJIT_IMM, 0);
}
if (jump == NULL)