[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:59:59 UTC 2010


The following commit has been merged in the debian/unstable branch:
commit cf0cd429e9d75947f6e657033386216f2e42dd6b
Author: Török Edvin <edwin at clamav.net>
Date:   Thu Aug 20 16:23:43 2009 +0300

    Implement API calls from bytecode.

diff --git a/libclamav/Makefile.am b/libclamav/Makefile.am
index c24aa51..2589972 100644
--- a/libclamav/Makefile.am
+++ b/libclamav/Makefile.am
@@ -324,7 +324,10 @@ libclamav_la_SOURCES = \
 	macho.h \
 	ishield.c \
 	ishield.h \
-	type_desc.h
+	type_desc.h \
+	bytecode_api.c \
+	bytecode_api_decl.c \
+	bytecode_api.h
 
 if !LINK_TOMMATH
 libclamav_la_SOURCES += bignum.c \
diff --git a/libclamav/Makefile.in b/libclamav/Makefile.in
index ce8d659..ac6b0de 100644
--- a/libclamav/Makefile.in
+++ b/libclamav/Makefile.in
@@ -131,7 +131,8 @@ am__libclamav_la_SOURCES_DIST = clamav.h matcher-ac.c matcher-ac.h \
 	uniq.h version.c version.h mpool.c mpool.h default.h sha256.c \
 	sha256.h bignum.h bytecode.c bytecode.h bytecode_vm.c \
 	bytecode_priv.h clambc.h cpio.c cpio.h macho.c macho.h \
-	ishield.c ishield.h type_desc.h bignum.c bignum_class.h
+	ishield.c ishield.h type_desc.h bytecode_api.c \
+	bytecode_api_decl.c bytecode_api.h bignum.c bignum_class.h
 @LINK_TOMMATH_FALSE at am__objects_1 = libclamav_la-bignum.lo
 am_libclamav_la_OBJECTS = libclamav_la-matcher-ac.lo \
 	libclamav_la-matcher-bm.lo libclamav_la-matcher.lo \
@@ -177,7 +178,9 @@ am_libclamav_la_OBJECTS = libclamav_la-matcher-ac.lo \
 	libclamav_la-version.lo libclamav_la-mpool.lo \
 	libclamav_la-sha256.lo libclamav_la-bytecode.lo \
 	libclamav_la-bytecode_vm.lo libclamav_la-cpio.lo \
-	libclamav_la-macho.lo libclamav_la-ishield.lo $(am__objects_1)
+	libclamav_la-macho.lo libclamav_la-ishield.lo \
+	libclamav_la-bytecode_api.lo libclamav_la-bytecode_api_decl.lo \
+	$(am__objects_1)
 libclamav_la_OBJECTS = $(am_libclamav_la_OBJECTS)
 libclamav_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(libclamav_la_CFLAGS) \
@@ -547,7 +550,8 @@ libclamav_la_SOURCES = clamav.h matcher-ac.c matcher-ac.h matcher-bm.c \
 	uniq.h version.c version.h mpool.c mpool.h default.h sha256.c \
 	sha256.h bignum.h bytecode.c bytecode.h bytecode_vm.c \
 	bytecode_priv.h clambc.h cpio.c cpio.h macho.c macho.h \
-	ishield.c ishield.h type_desc.h $(am__append_7)
+	ishield.c ishield.h type_desc.h bytecode_api.c \
+	bytecode_api_decl.c bytecode_api.h $(am__append_7)
 noinst_LTLIBRARIES = libclamav_internal_utils.la libclamav_internal_utils_nothreads.la
 COMMON_CLEANFILES = version.h version.h.tmp *.gcda *.gcno
 @MAINTAINER_MODE_TRUE at BUILT_SOURCES = jsparse/generated/operators.h jsparse/generated/keywords.h jsparse-keywords.gperf
@@ -678,6 +682,8 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-binhex.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-blob.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-bytecode.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-bytecode_api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-bytecode_api_decl.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-bytecode_vm.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-bzlib.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-cab.Plo at am__quote@
@@ -1417,6 +1423,20 @@ libclamav_la-ishield.lo: ishield.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -c -o libclamav_la-ishield.lo `test -f 'ishield.c' || echo '$(srcdir)/'`ishield.c
 
+libclamav_la-bytecode_api.lo: bytecode_api.c
+ at am__fastdepCC_TRUE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -MT libclamav_la-bytecode_api.lo -MD -MP -MF $(DEPDIR)/libclamav_la-bytecode_api.Tpo -c -o libclamav_la-bytecode_api.lo `test -f 'bytecode_api.c' || echo '$(srcdir)/'`bytecode_api.c
+ at am__fastdepCC_TRUE@	mv -f $(DEPDIR)/libclamav_la-bytecode_api.Tpo $(DEPDIR)/libclamav_la-bytecode_api.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='bytecode_api.c' object='libclamav_la-bytecode_api.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -c -o libclamav_la-bytecode_api.lo `test -f 'bytecode_api.c' || echo '$(srcdir)/'`bytecode_api.c
+
+libclamav_la-bytecode_api_decl.lo: bytecode_api_decl.c
+ at am__fastdepCC_TRUE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -MT libclamav_la-bytecode_api_decl.lo -MD -MP -MF $(DEPDIR)/libclamav_la-bytecode_api_decl.Tpo -c -o libclamav_la-bytecode_api_decl.lo `test -f 'bytecode_api_decl.c' || echo '$(srcdir)/'`bytecode_api_decl.c
+ at am__fastdepCC_TRUE@	mv -f $(DEPDIR)/libclamav_la-bytecode_api_decl.Tpo $(DEPDIR)/libclamav_la-bytecode_api_decl.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='bytecode_api_decl.c' object='libclamav_la-bytecode_api_decl.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -c -o libclamav_la-bytecode_api_decl.lo `test -f 'bytecode_api_decl.c' || echo '$(srcdir)/'`bytecode_api_decl.c
+
 libclamav_la-bignum.lo: bignum.c
 @am__fastdepCC_TRUE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -MT libclamav_la-bignum.lo -MD -MP -MF $(DEPDIR)/libclamav_la-bignum.Tpo -c -o libclamav_la-bignum.lo `test -f 'bignum.c' || echo '$(srcdir)/'`bignum.c
 @am__fastdepCC_TRUE@	mv -f $(DEPDIR)/libclamav_la-bignum.Tpo $(DEPDIR)/libclamav_la-bignum.Plo
diff --git a/libclamav/bytecode.c b/libclamav/bytecode.c
index 838b39b..4a29922 100644
--- a/libclamav/bytecode.c
+++ b/libclamav/bytecode.c
@@ -203,6 +203,18 @@ static inline funcid_t readFuncID(struct cli_bc *bc, unsigned char *p,
     return id;
 }
 
+static inline funcid_t readAPIFuncID(struct cli_bc *bc, unsigned char *p,
+				     unsigned *off, unsigned len, char *ok)
+{
+    funcid_t id = readNumber(p, off, len, ok)-1;
+    if (*ok && !cli_bitset_test(bc->uses_apis, id)) {
+	cli_errmsg("Called undeclared API function: %u\n", id);
+	*ok = 0;
+	return ~0;
+    }
+    return id;
+}
+
 static inline unsigned readFixedNumber(const unsigned char *p, unsigned *off,
 				       unsigned len, char *ok, unsigned width)
 {
@@ -291,7 +303,7 @@ static inline unsigned char *readData(const unsigned char *p, unsigned *off, uns
 	*datalen = l;
 	return NULL;
     }
-    newoff = *off + l;
+    newoff = *off + 2*l;
     if (newoff > len) {
 	cli_errmsg("Line ended while reading data\n");
 	*ok = 0;
@@ -304,14 +316,15 @@ static inline unsigned char *readData(const unsigned char *p, unsigned *off, uns
 	return NULL;
     }
     q = dat;
-    for (i=*off;i<newoff;i++) {
-	const unsigned char v = p[i];
-	if (UNLIKELY((v&0xf0) != 0x60)) {
-	    cli_errmsg("Invalid data part: %c\n", v);
+    for (i=*off;i<newoff;i += 2) {
+	const unsigned char v0 = p[i];
+	const unsigned char v1 = p[i+1];
+	if (UNLIKELY((v0&0xf0) != 0x60 || (v1&0xf0) != 0x60)) {
+	    cli_errmsg("Invalid data part: %c%c\n", v0, v1);
 	    *ok = 0;
 	    return 0;
 	}
-	*q++ = v;
+	*q++ = (v0&0xf) | ((v1&0xf) << 4);
     }
     *off = newoff;
     *datalen = l;
@@ -323,6 +336,8 @@ static inline char *readString(const unsigned char *p, unsigned *off, unsigned l
     unsigned stringlen;
     char *str = (char*)readData(p, off, len, ok, &stringlen);
     if (*ok && stringlen && str[stringlen-1] != '\0') {
+	str[stringlen-1] = '\0';
+	cli_errmsg("bytecode: string missing \\0 terminator: %s\n", str);
 	free(str);
 	*ok = 0;
 	return NULL;
@@ -362,6 +377,7 @@ static int parseHeader(struct cli_bc *bc, unsigned char *buffer)
     bc->num_types = readNumber(buffer, &offset, len, &ok);
     bc->num_func = readNumber(buffer, &offset, len, &ok);
     bc->state = bc_loaded;
+    bc->uses_apis = NULL;
     if (!ok) {
 	cli_errmsg("Invalid bytecode header at %u\n", offset);
 	return CL_EMALFDB;
@@ -444,7 +460,7 @@ static void add_static_types(struct cli_bc *bc)
 
 static int parseTypes(struct cli_bc *bc, unsigned char *buffer)
 {
-    unsigned i, offset = 1, len = strlen(buffer);
+    unsigned i, offset = 1, len = strlen((const char*)buffer);
     char ok=1;
 
     if (buffer[0] != 'T') {
@@ -516,9 +532,104 @@ static int parseTypes(struct cli_bc *bc, unsigned char *buffer)
     return CL_SUCCESS;
 }
 
+/* checks whether the type described by tid is the same as the one described by
+ * expectty. */
+static int types_equal(const struct cli_bc *bc, uint16_t *apity2ty, uint16_t tid, uint16_t apitid)
+{
+    unsigned i;
+    const struct cli_bc_type *ty = &bc->types[tid - 63];
+    const struct cli_bc_type *apity = &cli_apicall_types[apitid];
+    /* If we've already verified type equality, return.
+     * Since we need to check equality of recursive types, we assume types are
+     * equal while checking equality of contained types, unless proven
+     * otherwise. */
+     if (apity2ty[apitid] == tid + 1)
+	return 1;
+     apity2ty[apitid] = tid+1;
+
+     if (ty->kind != apity->kind) {
+	 cli_dbgmsg("bytecode: type kind mismatch: %u != %u\n", ty->kind, apity->kind);
+	 return 0;
+     }
+     if (ty->numElements != apity->numElements) {
+	 cli_dbgmsg("bytecode: type numElements mismatch: %u != %u\n", ty->numElements, apity->numElements);
+	 return 0;
+     }
+    for (i=0;i<ty->numElements;i++) {
+	if (apity->containedTypes[i] < BC_START_TID) {
+	    if (ty->containedTypes[i] != apity->containedTypes[i])
+		return 0;
+	} else if (!types_equal(bc, apity2ty, ty->containedTypes[i], apity->containedTypes[i] - BC_START_TID))
+	    return 0;
+    }
+    return 1;
+}
+
 static int parseApis(struct cli_bc *bc, unsigned char *buffer)
 {
-    //TODO
+    unsigned i, offset = 1, len = strlen((const char*)buffer), maxapi, calls;
+    char ok =1;
+    uint16_t *apity2ty;/*map of api type to current bytecode type ID */
+
+    if (buffer[0] != 'E') {
+	cli_errmsg("bytecode: Invalid api header: %c\n", buffer[0]);
+	return CL_EMALFDB;
+    }
+
+    maxapi = readNumber(buffer, &offset, len, &ok);
+    if (!ok)
+	return CL_EMALFDB;
+    if (maxapi > cli_apicall_maxapi) {
+	cli_dbgmsg("bytecode using API %u, but highest API known to libclamav is %u, skipping\n", maxapi, cli_apicall_maxapi);
+	return CL_BREAK;
+    }
+    calls = readNumber(buffer, &offset, len, &ok);
+    if (!ok)
+	return CL_EMALFDB;
+    if (calls > maxapi) {
+	cli_errmsg("bytecode: attempting to describe more APIs than max: %u > %u\n", calls, maxapi);
+	return CL_EMALFDB;
+    }
+    bc->uses_apis = cli_bitset_init();
+    if (!bc->uses_apis) {
+	cli_errmsg("Out of memory allocating apis bitset\n");
+	return CL_EMEM;
+    }
+    apity2ty = cli_calloc(cli_apicall_maxtypes, sizeof(*cli_apicall_types));
+    if (!apity2ty) {
+	cli_errmsg("Out of memory allocating apity2ty\n");
+	return CL_EMEM;
+    }
+    for (i=0;i < calls; i++) {
+	unsigned id = readNumber(buffer, &offset, len, &ok);
+	uint16_t tid = readTypeID(bc, buffer, &offset, len, &ok);
+	char *name = readString(buffer, &offset, len, &ok);
+
+	/* validate APIcall prototype */
+	if (id > maxapi) {
+	    cli_errmsg("bytecode: API id %u out of range, max %u\n", id, maxapi);
+	    ok = 0;
+	}
+	/* API ids start from 1 */
+	id--;
+	if (ok && name && strcmp(cli_apicalls[id].name, name)) {
+	    cli_errmsg("bytecode: API %u name mismatch: %s expected %s\n", id, name, cli_apicalls[id].name);
+	    ok = 0;
+	}
+	if (ok && !types_equal(bc, apity2ty, tid, cli_apicalls[id].type)) {
+	    cli_errmsg("bytecode: API %u prototype doesn't match\n", id);
+	    ok = 0;
+	}
+	/* don't need the name anymore */
+	free(name);
+	if (!ok)
+	    return CL_EMALFDB;
+
+	/* APIcall is valid */
+	cli_bitset_set(bc->uses_apis, id);
+    }
+    free(apity2ty); /* free temporary map */
+    cli_dbgmsg("bytecode: Parsed %u APIcalls, maxapi %u\n", calls, maxapi);
     return CL_SUCCESS;
 }
 
@@ -672,6 +783,7 @@ static int parseBB(struct cli_bc *bc, unsigned func, unsigned bb, unsigned char
 		inst.u.branch.br_true = readBBID(bcfunc, buffer, &offset, len, &ok);
 		inst.u.branch.br_false = readBBID(bcfunc, buffer, &offset, len, &ok);
 		break;
+	    case OP_CALL_API:/* fall-through */
 	    case OP_CALL_DIRECT:
 		numOp = readFixedNumber(buffer, &offset, len, &ok, 1);
 		if (ok) {
@@ -682,7 +794,10 @@ static int parseBB(struct cli_bc *bc, unsigned func, unsigned bb, unsigned char
 			cli_errmsg("Out of memory allocating operands\n");
 			return CL_EMALFDB;
 		    }
-		    inst.u.ops.funcid = readFuncID(bc, buffer, &offset, len, &ok);
+		    if (inst.opcode == OP_CALL_DIRECT)
+			inst.u.ops.funcid = readFuncID(bc, buffer, &offset, len, &ok);
+		    else
+			inst.u.ops.funcid = readAPIFuncID(bc, buffer, &offset, len, &ok);
 		    for (i=0;i<numOp;i++) {
 			inst.u.ops.ops[i] = readOperand(bcfunc, buffer, &offset, len, &ok);
 		    }
@@ -931,6 +1046,8 @@ void cli_bytecode_destroy(struct cli_bc *bc)
 	free(f->constants);
     }
     free(bc->funcs);
+    if (bc->uses_apis)
+	cli_bitset_free(bc->uses_apis);
 }
 
 #define MAP(val) do { operand_t o = val; \
@@ -1013,16 +1130,26 @@ static int cli_bytecode_prepare_interpreter(struct cli_bc *bc)
 		    MAP(inst->u.three[1]);
 		    MAP(inst->u.three[2]);
 		    break;
+		case OP_CALL_API:/* fall-through */
 		case OP_CALL_DIRECT:
 		{
-		    struct cli_bc_func *target = &bc->funcs[inst->u.ops.funcid];
-		    if (inst->u.ops.funcid > bc->num_func) {
-			cli_errmsg("bytecode: called function out of range: %u > %u\n", inst->u.ops.funcid, bc->num_func);
-			return CL_EBYTECODE;
-		    }
-		    if (inst->u.ops.numOps != target->numArgs) {
-			cli_errmsg("bytecode: call operands don't match function prototype\n");
-			return CL_EBYTECODE;
+		    struct cli_bc_func *target = NULL;
+		    if (inst->opcode == OP_CALL_DIRECT) {
+			target = &bc->funcs[inst->u.ops.funcid];
+			if (inst->u.ops.funcid > bc->num_func) {
+			    cli_errmsg("bytecode: called function out of range: %u > %u\n", inst->u.ops.funcid, bc->num_func);
+			    return CL_EBYTECODE;
+			}
+			if (inst->u.ops.numOps != target->numArgs) {
+			    cli_errmsg("bytecode: call operands don't match function prototype\n");
+			    return CL_EBYTECODE;
+			}
+		    } else {
+			/* APIs have 2 parameters always */
+			if (inst->u.ops.numOps != 2) {
+			    cli_errmsg("bytecode: call operands don't match function prototype\n");
+			    return CL_EBYTECODE;
+			}
 		    }
 		    if (inst->u.ops.numOps) {
 			inst->u.ops.opsizes = cli_malloc(sizeof(*inst->u.ops.opsizes)*inst->u.ops.numOps);
@@ -1033,7 +1160,10 @@ static int cli_bytecode_prepare_interpreter(struct cli_bc *bc)
 		    }
 		    for (k=0;k<inst->u.ops.numOps;k++) {
 			MAP(inst->u.ops.ops[k]);
-			inst->u.ops.opsizes[k] = typesize(bc, target->types[k]);
+			if (inst->opcode == OP_CALL_DIRECT)
+			    inst->u.ops.opsizes[k] = typesize(bc, target->types[k]);
+			else
+			    inst->u.ops.opsizes[k] = 32; /*XXX*/
 		    }
 		    break;
 		}
diff --git a/libclamav/bytecode.h b/libclamav/bytecode.h
index 965145a..1721f98 100644
--- a/libclamav/bytecode.h
+++ b/libclamav/bytecode.h
@@ -24,6 +24,8 @@
 #include <stdio.h>
 #include "clambc.h"
 #include "cltypes.h"
+#include "others.h"
+
 struct cli_dbio;
 struct cli_bc_ctx;
 struct cli_bc_func;
@@ -48,6 +50,7 @@ struct cli_bc {
   struct cli_bc_type *types;
   enum bc_state state;
   uint16_t start_tid;
+  bitset_t *uses_apis;
 };
 
 struct cli_bc_ctx *cli_bytecode_context_alloc(void);
diff --git a/clamdscan/client.h b/libclamav/bytecode_api.c
similarity index 67%
copy from clamdscan/client.h
copy to libclamav/bytecode_api.c
index db73f3e..df75295 100644
--- a/clamdscan/client.h
+++ b/libclamav/bytecode_api.c
@@ -1,7 +1,7 @@
 /*
- *  Copyright (C) 2009 Sourcefire, Inc.
+ *  ClamAV bytecode internal API
  *
- *  Authors: Tomasz Kojm, aCaB
+ *  Copyright (C) 2009 Sourcefire, Inc.
  *
  *  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
@@ -18,20 +18,16 @@
  *  MA 02110-1301, USA.
  */
 
-#ifndef __CLIENT_H
-#define __CLIENT_H
-
-#include "shared/optparser.h"
-
-enum {
-    CONT,
-    MULTI,
-    STREAM,
-    FILDES
-};
+#include "cltypes.h"
+#include "type_desc.h"
+#include "bytecode_api.h"
 
-int client(const struct optstruct *opts, int *infected);
-int get_clamd_version(const struct optstruct *opts);
-int reload_clamd_database(const struct optstruct *opts);
+int32_t cli_bcapi_test0(struct foo* s, uint32_t u)
+{
+    return (s && s->nxt == s && u == 0xdeadbeef) ? 0x12345678 : 0x55;
+}
 
-#endif
+int32_t cli_bcapi_test1(int32_t a, int32_t b)
+{
+    return (a==0xf00dbeef && b==0xbeeff00d) ? 0x12345678 : 0x55;
+}
diff --git a/libclamav/bytecode_api.h b/libclamav/bytecode_api.h
new file mode 100644
index 0000000..ed7338f
--- /dev/null
+++ b/libclamav/bytecode_api.h
@@ -0,0 +1,6 @@
+struct foo {
+    struct foo *nxt;
+};
+
+int32_t cli_bcapi_test0(struct foo*, uint32_t);
+int32_t cli_bcapi_test1(int32_t, int32_t);
diff --git a/libclamav/bytecode_api_decl.c b/libclamav/bytecode_api_decl.c
new file mode 100644
index 0000000..fe23bbe
--- /dev/null
+++ b/libclamav/bytecode_api_decl.c
@@ -0,0 +1,51 @@
+/*
+ *  ClamAV bytecode internal API
+ *  This is an automatically generated file!
+ *
+ *  Copyright (C) 2009 Sourcefire, Inc.
+ *
+ *  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.
+ */
+
+#include "cltypes.h"
+#include "type_desc.h"
+#include "bytecode_api.h"
+
+static uint16_t cli_tmp0[]={32, 70, 32};
+static uint16_t cli_tmp1[]={71};
+static uint16_t cli_tmp2[]={70};
+static uint16_t cli_tmp3[]={32, 32, 32};
+
+const struct cli_bc_type cli_apicall_types[]={
+	{FunctionType, cli_tmp0, 3},
+	{PointerType, cli_tmp1, 1},
+	{StructType, cli_tmp2, 1},
+	{FunctionType, cli_tmp3, 3}
+};
+
+const unsigned cli_apicall_maxtypes=sizeof(cli_apicall_types)/sizeof(cli_apicall_types[0]);
+const struct cli_apicall cli_apicalls[]={
+/* Bytecode APIcalls BEGIN */
+	{"cli_bcapi_test0", 0, 0, 1},
+	{"cli_bcapi_test1", 3, 0, 0}
+/* Bytecode APIcalls END */
+};
+const cli_apicall_int2 cli_apicalls0[] = {
+	cli_bcapi_test1
+};
+const cli_apicall_pointer cli_apicalls1[] = {
+	(cli_apicall_pointer)cli_bcapi_test0
+};
+const unsigned cli_apicall_maxapi = sizeof(cli_apicalls)/sizeof(cli_apicalls[0]);
diff --git a/libclamav/bytecode_vm.c b/libclamav/bytecode_vm.c
index caa62dc..672cec2 100644
--- a/libclamav/bytecode_vm.c
+++ b/libclamav/bytecode_vm.c
@@ -26,6 +26,7 @@
 #include "others.h"
 #include "bytecode.h"
 #include "bytecode_priv.h"
+#include "type_desc.h"
 #include "readdb.h"
 #include <string.h>
 
@@ -42,6 +43,8 @@ static int bcfail(const char *msg, long a, long b,
 #define CHECK_UNREACHABLE do { cli_dbgmsg("bytecode: unreachable executed!\n"); return CL_EBYTECODE; } while(0)
 #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_APIID(funcid) do { if (funcid >= cli_apicall_maxapi) return \
+    bcfail("APIid out of bounds!",funcid, cli_apicall_maxapi,__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 \
@@ -55,6 +58,7 @@ static int bcfail(const char *msg, long a, long b,
 #define TRACE_EXEC(id, dest, ty, stack)
 #define CHECK_UNREACHABLE return CL_EBYTECODE
 #define CHECK_FUNCID(x);
+#define CHECK_APIID(x);
 #define CHECK_EQ(a,b)
 #define CHECK_GT(a,b)
 #endif
@@ -553,6 +557,34 @@ int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct
 		break;
 	    }
 
+	    DEFINE_OP(OP_CALL_API) {
+		const struct cli_apicall *api = &cli_apicalls[inst->u.ops.funcid];
+		int32_t res;
+		CHECK_APIID(inst->u.ops.funcid);
+		TRACE_EXEC(-inst->u.ops.funcid, inst->dest, inst->type, stack_depth);
+	        switch (api->kind) {
+		    case 0: {
+			int32_t a, b, r;
+			READ32(a, inst->u.ops.ops[0]);
+			READ32(b, inst->u.ops.ops[1]);
+			res = cli_apicalls0[api->idx](a, b);
+			break;
+		    }
+		    case 1: {
+			cli_errmsg("bytecode: type 1 apicalls not yet implemented!\n");
+			stop = CL_EBYTECODE;
+		/*	void *p;
+			uint32_t u;
+			p = ...;
+			u = READ32(v, inst->u.ops.ops[1]);
+			res =  cli_apicalls1[api->idx](p, u);
+			break;*/
+		    }
+		}
+		WRITE32(inst->dest, res);
+		break;
+	    }
+
 	    DEFINE_OP(OP_CALL_DIRECT)
 		CHECK_FUNCID(inst->u.ops.funcid);
 		func2 = &bc->funcs[inst->u.ops.funcid];
diff --git a/libclamav/type_desc.h b/libclamav/type_desc.h
index 966644f..c90451b 100644
--- a/libclamav/type_desc.h
+++ b/libclamav/type_desc.h
@@ -1,3 +1,27 @@
+/*
+ *  ClamAV bytecode internal API
+ *
+ *  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 TYPE_DESC_H
+#define TYPE_DESC_H
+
 enum derived_t {
   FunctionType,
   PointerType,
@@ -17,13 +41,16 @@ typedef int32_t (*cli_apicall_pointer)(void*, uint32_t);
 
 struct cli_apicall {
     const char *name;
-    const struct cli_bc_type *type;
+    uint16_t type;/* type id in cli_apicall_types array */
+    uint16_t idx;
     uint8_t kind;
 };
 
 extern const struct cli_bc_type cli_apicall_types[];
+extern const unsigned cli_apicall_maxtypes;
 
 extern const struct cli_apicall cli_apicalls[];
 extern const cli_apicall_int2 cli_apicalls0[];
 extern const cli_apicall_pointer cli_apicalls1[];
 extern const unsigned cli_apicall_maxapi;
+#endif
diff --git a/unit_tests/check_bytecode.c b/unit_tests/check_bytecode.c
index c80165a..9fc0eee 100644
--- a/unit_tests/check_bytecode.c
+++ b/unit_tests/check_bytecode.c
@@ -81,6 +81,14 @@ START_TEST (test_arith)
     runtest("input/arith.cbc", 0xd5555555);
 }
 END_TEST
+
+START_TEST (test_apicalls)
+{
+    runtest("input/apicalls.cbc", 0xf00d);
+}
+END_TEST
+
+
 Suite *test_bytecode_suite(void)
 {
     Suite *s = suite_create("bytecode");
@@ -89,5 +97,6 @@ Suite *test_bytecode_suite(void)
 
     tcase_add_test(tc_cli_arith, test_retmagic);
     tcase_add_test(tc_cli_arith, test_arith);
+    tcase_add_test(tc_cli_arith, test_apicalls);
     return s;
 }
diff --git a/unit_tests/input/apicalls.cbc b/unit_tests/input/apicalls.cbc
new file mode 100644
index 0000000..ace9167
--- /dev/null
+++ b/unit_tests/input/apicalls.cbc
@@ -0,0 +1,15 @@
+ClamBCaa`|`````|`agafp`clamcoincidencejb
+Tedebfdacb`bb`bb`b
+Eabaaabbed|b`acflfifoebfcfaf`gifoedgefcgdgac``
+A`Lacb`baab`bFadaa
+Bb`b``bbabHonnkm``odHm``oonnkdaaaadab`b`Hhgfedcbadb`babnaaaDm``odDmjnmdTcab`babE
+AaLabahaab`bFacaa
+Baaaadaah`Bgaab`babnaaaDm``odDmjnmdTcab`babE
+AaLabb`aaab`bFacaa
+Baaaadab`a`Dhbgabb`babnaaaDm``odDmjnmdTcab`babE
+AaLabb`baab`bFacaa
+Baaaadab`b`Fichbgadb`babnaaaDm``odDmjnmdTcab`babE
+AaLabb`daab`bFacaa
+Baaaadab`d`Ncgbfae`dichbgahb`babnaaaDm``odDmjnmdTcab`babE
+AbLadahb`aaaaaaab`bFaeaa
+Baaabdaah`Bhbaaaacdab`aaaDdcbabaaadk`acabb`baenaadDm``odDmjnmdTcab`baeE

-- 
Debian repository for ClamAV



More information about the Pkg-clamav-commits mailing list