On Mon, Nov 24, 2014 at 01:38:40PM +0100, S??bastien Marie wrote:
> Hi,
>
> Starting to play with afl-fuzz, I test it with dc(1), and it found a "Bus
> error".
>
> Basically:
> $ echo '1 2:x1Lx1:x1:x' | dc
> Bus error (core dumped)
>
> I traced the bug, and the code before do a double-free (resulting the
> Bus error). Thanks to malloc(3) junk :)
>
> The problem is a lack of initialisation in stack_pushnumber function.
>
> The code before will:
> - allocate an array on register (call it A)
> A[1] = 2
>
> - push it on the stack
> (the array A arrive on stack)
>
> - store it in a new array on register (call it B)
> (the stack is just reduced, the value.array is keeped as it, so
> address of A is here)
> B[1] = A
>
> - push a number on stack
> (as the value isn't properly reinitialized, the number is allocated,
> but the value.array A is keeped)
>
> - allocate an array on register
> - it pops the number (with value.array setted to A), and as it pops,
> it free the value on stack, and the array A too (as != NULL)
> - it pops the array B
> - it will try to set B[1] = 1, so it free B[1], which is A, which is
> already freed: *boom*.
>
> The patch just ensure a push_number (or push_string) properly initialize
> the value, by set value.array to NULL.
> --
> S??bastien Marie
>
> Index: stack.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/dc/stack.c,v
> retrieving revision 1.11
> diff -u -p -r1.11 stack.c
> --- stack.c 27 Oct 2009 23:59:37 -0000 1.11
> +++ stack.c 24 Nov 2014 12:31:53 -0000
> @@ -147,6 +147,7 @@ stack_pushnumber(struct stack *stack, st
> stack_grow(stack);
> stack->stack[stack->sp].type = BCODE_NUMBER;
> stack->stack[stack->sp].u.num = b;
> + stack->stack[stack->sp].array = NULL;
> }
>
> void
> @@ -155,6 +156,7 @@ stack_pushstring(struct stack *stack, ch
> stack_grow(stack);
> stack->stack[stack->sp].type = BCODE_STRING;
> stack->stack[stack->sp].u.string = string;
> + stack->stack[stack->sp].array = NULL;
> }
>
> void
Actually, with this, the init in stack_grow can be left out, I believe.
Regress tests still succeed. I wil be adding you case to them.
-Otto
Index: stack.c
===================================================================
RCS file: /cvs/src/usr.bin/dc/stack.c,v
retrieving revision 1.11
diff -u -p -r1.11 stack.c
--- stack.c 27 Oct 2009 23:59:37 -0000 1.11
+++ stack.c 24 Nov 2014 16:57:09 -0000
@@ -129,14 +129,12 @@ stack_swap(struct stack *stack)
static void
stack_grow(struct stack *stack)
{
- size_t new_size, i;
+ size_t new_size;
if (++stack->sp == stack->size) {
new_size = stack->size * 2 + 1;
stack->stack = brealloc(stack->stack,
new_size * sizeof(*stack->stack));
- for (i = stack->size; i < new_size; i++)
- stack->stack[i].array = NULL;
stack->size = new_size;
}
}
@@ -147,6 +145,7 @@ stack_pushnumber(struct stack *stack, st
stack_grow(stack);
stack->stack[stack->sp].type = BCODE_NUMBER;
stack->stack[stack->sp].u.num = b;
+ stack->stack[stack->sp].array = NULL;
}
void
@@ -155,6 +154,7 @@ stack_pushstring(struct stack *stack, ch
stack_grow(stack);
stack->stack[stack->sp].type = BCODE_STRING;
stack->stack[stack->sp].u.string = string;
+ stack->stack[stack->sp].array = NULL;
}
void