[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