[Pkg-clamav-commits] [SCM] Debian repository for ClamAV branch, debian/unstable, updated. debian/0.95+dfsg-1-6156-g094ec9b
Török Edvin
edwin at clamav.net
Sun Apr 4 00:56:25 UTC 2010
The following commit has been merged in the debian/unstable branch:
commit e0c4fd853c9ae255569c9d0316f54fa91afb32ed
Author: Török Edvin <edwin at clamav.net>
Date: Tue Jul 7 23:36:36 2009 +0300
Start implementing bytecode opcodes.
diff --git a/clambc/bcrun.c b/clambc/bcrun.c
index 6b1acf8..52ac64e 100644
--- a/clambc/bcrun.c
+++ b/clambc/bcrun.c
@@ -36,7 +36,7 @@ static void help(void)
get_version());
printf(" By The ClamAV Team: http://www.clamav.net/team\n");
printf(" (C) 2009 Sourcefire, Inc.\n\n");
- printf("clambc <file>\n\n");
+ printf("clambc <file> [function] [param1 ...]\n\n");
printf(" --help -h Show help\n");
printf(" --version -V Show version\n");
printf(" file file to test\n");
@@ -51,13 +51,14 @@ int main(int argc, char *argv[])
struct cli_bc_ctx *ctx;
int rc;
struct optstruct *opts;
+ unsigned funcid=0, i;
opts = optparse(NULL, argc, argv, 1, OPT_CLAMBC, 0, NULL);
if (!opts) {
fprintf(stderr, "ERROR: Can't parse command line options\n");
exit(1);
}
- if(optget(opts, "help")->enabled) {
+ if(optget(opts, "help")->enabled || !opts->filename) {
optfree(opts);
help();
exit(0);
@@ -67,7 +68,7 @@ int main(int argc, char *argv[])
optfree(opts);
exit(0);
}
- f = fopen(argv[1], "r");
+ f = fopen(opts->filename[0], "r");
if (!f) {
fprintf(stderr, "Unable to load %s\n", argv[1]);
optfree(opts);
@@ -98,9 +99,29 @@ int main(int argc, char *argv[])
exit(3);
}
- printf("Running bytecode\n");
- cli_bytecode_run(bc, ctx);
- printf("Bytecode run finished\n");
+ if (opts->filename[1]) {
+ funcid = atoi(opts->filename[1]);
+ }
+ cli_bytecode_context_setfuncid(ctx, bc, funcid);
+ printf("Running bytecode function :%u\n", funcid);
+
+ if (opts->filename[1]) {
+ i=2;
+ while (opts->filename[i]) {
+ rc = cli_bytecode_context_setparam_int(ctx, i-2, atoi(opts->filename[i]));
+ if (rc != CL_SUCCESS) {
+ fprintf(stderr,"Unable to set param %u: %s\n", i-2, cl_strerror(rc));
+ }
+ i++;
+ }
+ }
+
+ rc = cli_bytecode_run(bc, ctx);
+ if (rc != CL_SUCCESS) {
+ fprintf(stderr,"Unable to run bytecode: %s\n", cl_strerror(rc));
+ } else {
+ printf("Bytecode run finished\n");
+ }
cli_bytecode_context_destroy(ctx);
cli_bytecode_destroy(bc);
free(bc);
diff --git a/libclamav/bytecode.c b/libclamav/bytecode.c
index c0f6f4b..693590c 100644
--- a/libclamav/bytecode.c
+++ b/libclamav/bytecode.c
@@ -62,19 +62,21 @@ int cli_bytecode_context_setfuncid(struct cli_bc_ctx *ctx, struct cli_bc *bc, un
cli_errmsg("bytecode: function ID doesn't exist: %u\n", funcid);
return CL_EARG;
}
- ctx->func = &bc->funcs[funcid];
+ func = ctx->func = &bc->funcs[funcid];
ctx->bc = bc;
ctx->numParams = func->numArgs;
ctx->funcid = funcid;
- ctx->values = cli_malloc(sizeof(*ctx->values)*func->numArgs);
- if (!ctx->values) {
- cli_errmsg("bytecode: error allocating memory for parameters\n");
- return CL_EMEM;
- }
- ctx->operands = cli_malloc(sizeof(*ctx->operands)*func->numArgs);
- if (!ctx->operands) {
- cli_errmsg("bytecode: error allocating memory for parameters\n");
- return CL_EMEM;
+ if (func->numArgs) {
+ ctx->values = cli_malloc(sizeof(*ctx->values)*func->numArgs);
+ if (!ctx->values) {
+ cli_errmsg("bytecode: error allocating memory for parameters\n");
+ return CL_EMEM;
+ }
+ ctx->operands = cli_malloc(sizeof(*ctx->operands)*func->numArgs);
+ if (!ctx->operands) {
+ cli_errmsg("bytecode: error allocating memory for parameters\n");
+ return CL_EMEM;
+ }
}
for (i=0;i<func->numArgs;i++) {
ctx->values[i].ref = MAX_OP;
@@ -98,8 +100,8 @@ int cli_bytecode_context_setparam_int(struct cli_bc_ctx *ctx, unsigned i, uint64
cli_errmsg("bytecode: parameter type mismatch\n");
return CL_EARG;
}
- ctx->func->values[i].v = c;
- ctx->func->values[i].ref = CONSTANT_OP;
+ ctx->values[i].v = c;
+ ctx->values[i].ref = CONSTANT_OP;
return CL_SUCCESS;
}
@@ -151,8 +153,8 @@ static inline uint64_t readNumber(const unsigned char *p, unsigned *off, unsigne
static inline funcid_t readFuncID(struct cli_bc *bc, unsigned char *p,
unsigned *off, unsigned len, char *ok)
{
- funcid_t id = readNumber(p, off, len, ok);
- if (id >= bc->num_func) {
+ funcid_t id = readNumber(p, off, len, ok)-1;
+ if (*ok && id >= bc->num_func) {
cli_errmsg("Called function out of range: %u >= %u\n", id, bc->num_func);
*ok = 0;
return ~0;
@@ -484,6 +486,15 @@ static int parseBB(struct cli_bc *bc, unsigned func, unsigned bb, unsigned char
}
}
break;
+ case OP_ZEXT:
+ case OP_SEXT:
+ case OP_TRUNC:
+ inst.u.cast.source = readOperand(bcfunc, buffer, &offset, len, &ok);
+ if (ok) {
+ /* calculate mask */
+ inst.u.cast.mask = (1<<bcfunc->allinsts[inst.u.cast.source].type)-1;
+ }
+ break;
default:
numOp = operand_counts[inst.opcode];
switch (numOp) {
@@ -593,8 +604,11 @@ int cli_bytecode_run(struct cli_bc *bc, struct cli_bc_ctx *ctx)
{
struct cli_bc_inst inst;
struct cli_bc_func func;
+ struct cli_bc_value value;
unsigned i;
- if (!ctx || !ctx->bc || !ctx->func || !ctx->values)
+ if (!ctx || !ctx->bc || !ctx->func)
+ return CL_ENULLARG;
+ if (ctx->numParams && (!ctx->values || !ctx->operands))
return CL_ENULLARG;
for (i=0;i<ctx->numParams;i++) {
if (ctx->values[i].ref == MAX_OP) {
@@ -610,7 +624,7 @@ int cli_bytecode_run(struct cli_bc *bc, struct cli_bc_ctx *ctx)
inst.u.ops.numOps = ctx->numParams;
inst.u.ops.funcid = ctx->funcid;
inst.u.ops.ops = ctx->operands;
- return cli_vm_execute_inst(ctx->bc, ctx, &func, &inst);
+ return cli_vm_execute(ctx->bc, ctx, &func, &inst, &value);
}
void cli_bytecode_destroy(struct cli_bc *bc)
diff --git a/libclamav/bytecode.h b/libclamav/bytecode.h
index 983c9bd..d565248 100644
--- a/libclamav/bytecode.h
+++ b/libclamav/bytecode.h
@@ -50,6 +50,4 @@ int cli_bytecode_load(struct cli_bc *bc, FILE *f, struct cli_dbio *dbio);
int cli_bytecode_run(struct cli_bc *bc, struct cli_bc_ctx *ctx);
void cli_bytecode_destroy(struct cli_bc *bc);
-int cli_vm_execute_inst(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func *func, struct cli_bc_inst *inst);
-
#endif
diff --git a/libclamav/bytecode_priv.h b/libclamav/bytecode_priv.h
new file mode 100644
index 0000000..cfb90bd
--- /dev/null
+++ b/libclamav/bytecode_priv.h
@@ -0,0 +1,96 @@
+/*
+ * Load, verify and execute ClamAV bytecode.
+ *
+ * Copyright (C) 2009 Sourcefire, Inc.
+ *
+ * Authors: Török Edvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifndef BYTECODE_PRIV_H
+#define BYTECODE_PRIV_H
+typedef uint32_t operand_t;
+typedef uint16_t bbid_t;
+typedef uint16_t funcid_t;
+
+struct cli_bc_callop {
+ operand_t* ops;
+ uint8_t numOps;
+ funcid_t funcid;
+};
+
+struct branch {
+ operand_t condition;
+ bbid_t br_true;
+ bbid_t br_false;
+};
+
+#define MAX_OP (operand_t)(~0u)
+#define CONSTANT_OP (MAX_OP-1)
+#define ARG_OP (MAX_OP-1)
+struct cli_bc_value {
+ uint64_t v;
+ operand_t ref;/* this has CONSTANT_OP value for constants, and ARG_op for arguments */
+};
+
+struct cli_bc_cast {
+ operand_t source;
+ uint64_t mask;
+};
+struct cli_bc_inst {
+ enum bc_opcode opcode;
+ uint16_t type;
+ union {
+ operand_t unaryop;
+ struct cli_bc_cast cast;
+ operand_t binop[2];
+ operand_t three[3];
+ struct cli_bc_callop ops;
+ struct branch branch;
+ bbid_t jump;
+ } u;
+};
+
+struct cli_bc_bb {
+ unsigned numInsts;
+ struct cli_bc_inst *insts;
+};
+
+struct cli_bc_func {
+ uint8_t numArgs;
+ uint16_t numLocals;
+ uint32_t numInsts;
+ uint32_t numConstants;
+ uint16_t numBB;
+ uint16_t *types;
+ uint32_t insn_idx;
+ struct cli_bc_bb *BB;
+ struct cli_bc_inst *allinsts;
+ struct cli_bc_value *values;
+};
+
+struct cli_bc_ctx {
+ /* id and params of toplevel function called */
+ struct cli_bc *bc;
+ struct cli_bc_func *func;
+ struct cli_bc_value *values;
+ operand_t *operands;
+ uint16_t funcid;
+ unsigned numParams;
+};
+
+int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func *func, struct cli_bc_inst *inst, struct cli_bc_value *value);
+#endif
diff --git a/libclamav/bytecode_vm.c b/libclamav/bytecode_vm.c
new file mode 100644
index 0000000..706e717
--- /dev/null
+++ b/libclamav/bytecode_vm.c
@@ -0,0 +1,148 @@
+/*
+ * Execute ClamAV bytecode.
+ *
+ * Copyright (C) 2009 Sourcefire, Inc.
+ *
+ * Authors: Török Edvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+#include "clamav.h"
+#include "others.h"
+#include "bytecode.h"
+#include "bytecode_priv.h"
+#include "readdb.h"
+#include <string.h>
+
+/* These checks will also be done by the bytecode verifier, but for
+ * debugging purposes we have explicit checks, these should never fail! */
+#ifdef CL_DEBUG
+static int bcfail(const char *msg, unsigned a, unsigned b,
+ const char *file, unsigned line)
+{
+ cli_errmsg("bytecode: check failed %s (%u and %u) at %s:%u\n", msg, a, b, file, line);
+ return CL_EARG;
+}
+#define CHECK_FUNCID(funcid) do { if (funcid >= bc->num_func) return \
+ bcfail("funcid out of bounds!",funcid, bc->num_func,__FILE__,__LINE__); } while(0)
+#define CHECK_EQ(a, b) do { if (a != b) return \
+ bcfail("Values "#a" and "#b" don't match!",a,b,__FILE__,__LINE__); } while(0)
+#define CHECK_GT(a, b) do {if (a < b) return \
+ bcfail("Condition failed "#a" > "#b,a,b, __FILE__, __LINE__); } while(0)
+#else
+#define CHECK_FUNCID(x)
+#define CHECK_EQ(a,b)
+#define CHECK_GT(a,b)
+#endif
+
+struct stack_entry {
+ struct cli_bc_func *func;
+ struct cli_bc_value *ret;
+ struct cli_bc_bb *bb;
+ unsigned bb_inst;
+};
+
+int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func *func, struct cli_bc_inst *inst, struct cli_bc_value *value)
+{
+ unsigned i, stack_depth=0, bb_inst=0, stop=0;
+ struct cli_bc_func *func2;
+ struct stack_entry *stack = NULL;
+ struct cli_bc_bb *bb = NULL;
+ struct cli_bc_value *values = NULL;
+
+ do {
+ switch (inst->opcode) {
+ case OP_ADD:
+ values->v = values[inst->u.binop[0]].v + values[inst->u.binop[1]].v;
+ break;
+ case OP_SUB:
+ values->v = values[inst->u.binop[0]].v - values[inst->u.binop[1]].v;
+ break;
+ case OP_MUL:
+ values->v = values[inst->u.binop[0]].v * values[inst->u.binop[1]].v;
+ break;
+ case OP_AND:
+ values->v = values[inst->u.binop[0]].v & values[inst->u.binop[1]].v;
+ break;
+ case OP_OR:
+ values->v = values[inst->u.binop[0]].v | values[inst->u.binop[1]].v;
+ break;
+ case OP_XOR:
+ values->v = values[inst->u.binop[0]].v ^ values[inst->u.binop[1]].v;
+ break;
+ case OP_ZEXT:
+ case OP_TRUNC:
+ values->v = values[inst->u.cast.source].v & values[inst->u.cast.mask].v;
+ break;
+ case OP_RET:
+ CHECK_GT(stack_depth, 0);
+ stack_depth--;
+ value = stack[stack_depth].ret;
+ value->v = values[inst->u.unaryop].v;
+ func = stack[stack_depth].func;
+ values = func->values;
+ if (!stack[stack_depth].bb) {
+ stop = CL_BREAK;
+ bb_inst--;
+ break;
+ }
+ bb = stack[stack_depth].bb;
+ bb_inst = stack[stack_depth].bb_inst;
+ inst = &bb->insts[bb_inst];
+ break;
+ case OP_ICMP_EQ:
+ value->v = values[inst->u.binop[0]].v == values[inst->u.binop[1]].v ? 1 : 0;
+ break;
+ case OP_SELECT:
+ values->v = values[inst->u.three[0]].v ?
+ values[inst->u.three[1]].v : values[inst->u.three[2]].v;
+ break;
+ case OP_CALL_DIRECT:
+ CHECK_FUNCID(inst->u.ops.funcid);
+ func2 = &bc->funcs[inst->u.ops.funcid];
+ CHECK_EQ(func2->numArgs, inst->u.ops.numOps);
+ for (i=0;i<func2->numArgs;i++)
+ func2->values[i] = func->values[inst->u.ops.ops[i]];
+ stack = cli_realloc2(stack, sizeof(*stack)*(stack_depth+1));
+ if (!stack)
+ return CL_EMEM;
+ stack[stack_depth].func = func;
+ stack[stack_depth].ret = value;
+ stack[stack_depth].bb = bb;
+ stack[stack_depth].bb_inst = bb_inst;
+ stack_depth++;
+ func = func2;
+ values = func->values;
+ CHECK_GT(func->numBB, 0);
+ bb = &func->BB[0];
+ inst = &bb->insts[0];
+ bb_inst = 0;
+ continue;
+ default:
+ cli_errmsg("Opcode %u is not implemented yet!\n", inst->opcode);
+ stop = CL_EARG;
+ }
+ bb_inst++;
+ inst++;
+ value++;
+ CHECK_GT(bb->numInsts, bb_inst);
+ } while (stop == CL_SUCCESS);
+
+ free(stack);
+ return stop == CL_BREAK ? CL_SUCCESS : stop;
+}
--
Debian repository for ClamAV
More information about the Pkg-clamav-commits
mailing list