mirror of
https://github.com/Cisco-Talos/clamav.git
synced 2026-02-04 20:11:56 -05:00
bytecode: allocate proper stack for functions.
This commit is contained in:
@@ -123,7 +123,7 @@ int main(int argc, char *argv[])
|
||||
uint64_t v;
|
||||
printf("Bytecode run finished\n");
|
||||
v = cli_bytecode_context_getresult_int(ctx);
|
||||
printf("Bytecode returned: %llx\n", (long long)v);
|
||||
printf("Bytecode returned: 0x%llx\n", (long long)v);
|
||||
}
|
||||
cli_bytecode_context_destroy(ctx);
|
||||
cli_bytecode_destroy(bc);
|
||||
|
||||
@@ -167,25 +167,23 @@ static inline operand_t readOperand(struct cli_bc_func *func, unsigned char *p,
|
||||
unsigned *off, unsigned len, char *ok)
|
||||
{
|
||||
uint64_t v;
|
||||
unsigned numValues = func->numArgs + func->numInsts + func->numConstants;
|
||||
if ((p[*off]&0xf0) == 0x40 || p[*off] == 0x50) {
|
||||
p[*off] |= 0x20;
|
||||
/* TODO: unique constants */
|
||||
func->values = cli_realloc2(func->values, (numValues+1)*sizeof(*func->values));
|
||||
if (!func->values) {
|
||||
func->constants = cli_realloc2(func->constants, (func->numConstants+1)*sizeof(*func->constants));
|
||||
if (!func->constants) {
|
||||
*ok = 0;
|
||||
return MAX_OP;
|
||||
}
|
||||
func->numConstants++;
|
||||
func->values[numValues].v = readNumber(p, off, len, ok);
|
||||
func->values[numValues].ref = CONSTANT_OP;
|
||||
return numValues;
|
||||
func->constants[func->numConstants].v = readNumber(p, off, len, ok);
|
||||
func->constants[func->numConstants].ref = CONSTANT_OP;
|
||||
return func->numValues + func->numConstants++;
|
||||
}
|
||||
v = readNumber(p, off, len, ok);
|
||||
if (!*ok)
|
||||
return MAX_OP;
|
||||
if (v >= numValues) {
|
||||
cli_errmsg("Operand index exceeds bounds: %u >= %u!\n", (unsigned)v, (unsigned)numValues);
|
||||
if (v >= func->numValues) {
|
||||
cli_errmsg("Operand index exceeds bounds: %u >= %u!\n", (unsigned)v, (unsigned)func->numValues);
|
||||
*ok = 0;
|
||||
return MAX_OP;
|
||||
}
|
||||
@@ -380,6 +378,7 @@ static int parseFunctionHeader(struct cli_bc *bc, unsigned fn, unsigned char *bu
|
||||
cli_errmsg("Invalid instructions count\n");
|
||||
return CL_EMALFDB;
|
||||
}
|
||||
func->numValues = func->numArgs + func->numLocals;
|
||||
func->insn_idx = 0;
|
||||
func->numConstants=0;
|
||||
func->allinsts = cli_calloc(func->numInsts, sizeof(*func->allinsts));
|
||||
@@ -387,19 +386,6 @@ static int parseFunctionHeader(struct cli_bc *bc, unsigned fn, unsigned char *bu
|
||||
cli_errmsg("Out of memory allocating instructions\n");
|
||||
return CL_EMEM;
|
||||
}
|
||||
func->values = cli_calloc(func->numInsts+func->numArgs, sizeof(*func->values));
|
||||
if (!func->values) {
|
||||
cli_errmsg("Out of memory allocating values\n");
|
||||
return CL_EMEM;
|
||||
}
|
||||
for (i=0;i<func->numArgs;i++) {
|
||||
func->values[i].v = 0xdeadbeef;
|
||||
func->values[i].ref = ARG_OP;
|
||||
}
|
||||
for(;i<func->numInsts+func->numArgs;i++) {
|
||||
func->values[i].v = 0xdeadbeef;
|
||||
func->values[i].ref = i-func->numArgs;
|
||||
}
|
||||
func->numBB = readNumber(buffer, &offset, len, &ok);
|
||||
if (!ok) {
|
||||
cli_errmsg("Invalid basic block count\n");
|
||||
@@ -643,8 +629,8 @@ int cli_bytecode_run(struct cli_bc *bc, struct cli_bc_ctx *ctx)
|
||||
}
|
||||
}
|
||||
memset(&func, 0, sizeof(func));
|
||||
func.values = ctx->values;
|
||||
func.numInsts = 1;
|
||||
func.numValues = 1;
|
||||
|
||||
inst.opcode = OP_CALL_DIRECT;
|
||||
inst.dest = func.numArgs;
|
||||
@@ -680,7 +666,6 @@ void cli_bytecode_destroy(struct cli_bc *bc)
|
||||
}
|
||||
free(f->BB);
|
||||
free(f->allinsts);
|
||||
free(f->values);
|
||||
}
|
||||
free(bc->funcs);
|
||||
}
|
||||
|
||||
@@ -74,13 +74,14 @@ struct cli_bc_func {
|
||||
uint8_t numArgs;
|
||||
uint16_t numLocals;
|
||||
uint32_t numInsts;
|
||||
uint32_t numValues;//without constants
|
||||
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_value *constants;
|
||||
};
|
||||
|
||||
struct cli_bc_ctx {
|
||||
@@ -93,5 +94,5 @@ struct cli_bc_ctx {
|
||||
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);
|
||||
int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct cli_bc_func *func, const struct cli_bc_inst *inst);
|
||||
#endif
|
||||
|
||||
@@ -32,18 +32,18 @@
|
||||
/* 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,
|
||||
static int bcfail(const char *msg, long a, long b,
|
||||
const char *file, unsigned line)
|
||||
{
|
||||
cli_errmsg("bytecode: check failed %s (%u and %u) at %s:%u\n", msg, a, b, file, line);
|
||||
cli_errmsg("bytecode: check failed %s (%lx and %lx) 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)
|
||||
#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)
|
||||
@@ -51,8 +51,9 @@ static int bcfail(const char *msg, unsigned a, unsigned b,
|
||||
#endif
|
||||
|
||||
struct stack_entry {
|
||||
struct cli_bc_func *func;
|
||||
const struct cli_bc_func *func;
|
||||
struct cli_bc_value *ret;
|
||||
struct cli_bc_value *values;
|
||||
struct cli_bc_bb *bb;
|
||||
unsigned bb_inst;
|
||||
};
|
||||
@@ -79,28 +80,39 @@ struct stack_entry {
|
||||
#define SIGNEXT(a) CLI_SRS(((int64_t)(a)) << (64-inst->type), (64-inst->type))
|
||||
#define BINOPS(i) SIGNEXT(BINOPNOMOD(i))
|
||||
|
||||
static void jump(struct cli_bc_func *func, uint16_t bbid, struct cli_bc_bb **bb, struct cli_bc_inst **inst,
|
||||
struct cli_bc_value **value, unsigned *bb_inst)
|
||||
static int jump(const struct cli_bc_func *func, uint16_t bbid, struct cli_bc_bb **bb, const struct cli_bc_inst **inst,
|
||||
unsigned *bb_inst)
|
||||
{
|
||||
CHECK_GT(func->numBB, bbid);
|
||||
*bb = &func->BB[bbid];
|
||||
*inst = (*bb)->insts;
|
||||
*value = &func->values[*inst - func->allinsts];
|
||||
*bb_inst = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func *func, struct cli_bc_inst *inst)
|
||||
static struct cli_bc_value *allocate_stack(const struct cli_bc_func *func)
|
||||
{
|
||||
unsigned i;
|
||||
struct cli_bc_value *values = cli_calloc(func->numValues+func->numConstants, sizeof(*values));
|
||||
if (!values)
|
||||
return NULL;
|
||||
for (i=func->numValues;i<func->numValues+func->numConstants;i++)
|
||||
values[i] = func->constants[i-func->numValues];
|
||||
return values;
|
||||
}
|
||||
|
||||
int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct cli_bc_func *func, const struct cli_bc_inst *inst)
|
||||
{
|
||||
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 = func->values;
|
||||
struct cli_bc_value *value;
|
||||
struct cli_bc_value *values = ctx->values;
|
||||
struct cli_bc_value *value, *old_values;
|
||||
|
||||
do {
|
||||
value = &values[inst->dest];
|
||||
CHECK_GT(func->values + func->numArgs+func->numInsts+func->numConstants, value);
|
||||
CHECK_GT(func->numValues+func->numConstants, value - values);
|
||||
switch (inst->opcode) {
|
||||
case OP_ADD:
|
||||
value->v = BINOPNOMOD(0) + BINOPNOMOD(1);
|
||||
@@ -175,22 +187,23 @@ int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func
|
||||
value->v = values[inst->u.cast.source].v & values[inst->u.cast.mask].v;
|
||||
break;
|
||||
case OP_BRANCH:
|
||||
jump(func, (values[inst->u.branch.condition].v&1) ?
|
||||
inst->u.branch.br_true : inst->u.branch.br_false,
|
||||
&bb, &inst, &value, &bb_inst);
|
||||
stop = jump(func, (values[inst->u.branch.condition].v&1) ?
|
||||
inst->u.branch.br_true : inst->u.branch.br_false,
|
||||
&bb, &inst, &bb_inst);
|
||||
continue;
|
||||
case OP_JMP:
|
||||
jump(func, inst->u.jump, &bb, &inst, &value, &bb_inst);
|
||||
stop = jump(func, inst->u.jump, &bb, &inst, &bb_inst);
|
||||
continue;
|
||||
case OP_RET:
|
||||
CHECK_GT(stack_depth, 0);
|
||||
stack_depth--;
|
||||
value = stack[stack_depth].ret;
|
||||
func = stack[stack_depth].func;
|
||||
CHECK_GT(func->values + func->numArgs+func->numInsts+func->numConstants, value);
|
||||
CHECK_GT(value, &func->values[-1]);
|
||||
value->v = values[inst->u.unaryop].v;
|
||||
values = func->values;
|
||||
free(values);
|
||||
values = stack[stack_depth].values;
|
||||
CHECK_GT(func->numValues+func->numConstants, value-values);
|
||||
CHECK_GT(value-values, -1);
|
||||
if (!stack[stack_depth].bb) {
|
||||
stop = CL_BREAK;
|
||||
bb_inst--;
|
||||
@@ -238,8 +251,6 @@ int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func
|
||||
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;
|
||||
@@ -247,12 +258,18 @@ int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func
|
||||
stack[stack_depth].ret = value;
|
||||
stack[stack_depth].bb = bb;
|
||||
stack[stack_depth].bb_inst = bb_inst;
|
||||
stack[stack_depth].values = values;
|
||||
stack_depth++;
|
||||
cli_dbgmsg("Executing %d\n", inst->u.ops.funcid);
|
||||
old_values = values;
|
||||
values = allocate_stack(func2);
|
||||
if (!values)
|
||||
return CL_EMEM;
|
||||
for (i=0;i<func2->numArgs;i++)
|
||||
values[i] = old_values[inst->u.ops.ops[i]];
|
||||
func = func2;
|
||||
values = func->values;
|
||||
CHECK_GT(func->numBB, 0);
|
||||
jump(func, 0, &bb, &inst, &value, &bb_inst);
|
||||
stop = jump(func, 0, &bb, &inst, &bb_inst);
|
||||
continue;
|
||||
case OP_COPY:
|
||||
BINOPNOMOD(1) = BINOPNOMOD(0);
|
||||
@@ -260,6 +277,7 @@ int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func
|
||||
default:
|
||||
cli_errmsg("Opcode %u is not implemented yet!\n", inst->opcode);
|
||||
stop = CL_EARG;
|
||||
break;
|
||||
}
|
||||
bb_inst++;
|
||||
inst++;
|
||||
|
||||
Reference in New Issue
Block a user