Backported from 5.5 for 5.4 by Remi Collet Backported from 5.5 for 5.4 by Remi Collet From b1bd4119bcafab6f9a8f84d92cd65eec3afeface Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Sun, 14 Feb 2016 22:34:39 -0800 Subject: [PATCH] Fixed bug #71587 - Use-After-Free / Double-Free in WDDX Deserialize --- ext/wddx/tests/bug71587.phpt | 43 +++++++++++++++++++++++++++++++++++++++++++ ext/wddx/wddx.c | 19 +++++++++++++++---- 2 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 ext/wddx/tests/bug71587.phpt diff --git a/ext/wddx/tests/bug71587.phpt b/ext/wddx/tests/bug71587.phpt new file mode 100644 index 0000000..3fdfc35 --- /dev/null +++ b/ext/wddx/tests/bug71587.phpt @@ -0,0 +1,43 @@ +--TEST-- +Bug #71587 (Use-After-Free / Double-Free in WDDX Deserialize) +--SKIPIF-- + +--FILE-- + + + + + + manhluat + + + + + +EOF; + +$wddx = wddx_deserialize($xml); +var_dump($wddx); +// Print mem leak +foreach($wddx as $k=>$v) + printf("Key: %s\nValue: %s\n",bin2hex($k),bin2hex($v)); + +?> +DONE +--EXPECTF-- +array(2) { + [0]=> + string(8) "manhluat" + [1]=> + bool(true) +} +Key: 30 +Value: 6d616e686c756174 +Key: 31 +Value: 31 +DONE diff --git a/ext/wddx/wddx.c b/ext/wddx/wddx.c index 7267ee1..da34246 100644 --- a/ext/wddx/wddx.c +++ b/ext/wddx/wddx.c @@ -936,6 +936,16 @@ static void php_wddx_pop_element(void *user_data, const XML_Char *name) !strcmp(name, EL_DATETIME)) { wddx_stack_top(stack, (void**)&ent1); + if (!ent1->data) { + if (stack->top > 1) { + stack->top--; + } else { + stack->done = 1; + } + efree(ent1); + return; + } + if (!strcmp(name, EL_BINARY)) { int new_len=0; unsigned char *new_str; @@ -1032,6 +1042,7 @@ static void php_wddx_pop_element(void *user_data, const XML_Char *name) } } else if (!strcmp(name, EL_VAR) && stack->varname) { efree(stack->varname); + stack->varname = NULL; } else if (!strcmp(name, EL_FIELD)) { st_entry *ent; wddx_stack_top(stack, (void **)&ent); @@ -1051,7 +1062,7 @@ static void php_wddx_process_data(void *user_data, const XML_Char *s, int len) if (!wddx_stack_is_empty(stack) && !stack->done) { wddx_stack_top(stack, (void**)&ent); - switch (Z_TYPE_P(ent)) { + switch (ent->type) { case ST_STRING: if (Z_STRLEN_P(ent->data) == 0) { STR_FREE(Z_STRVAL_P(ent->data)); @@ -1090,11 +1101,11 @@ static void php_wddx_process_data(void *user_data, const XML_Char *s, int len) } else if (!strcmp(s, "false")) { Z_LVAL_P(ent->data) = 0; } else { - stack->top--; zval_ptr_dtor(&ent->data); - if (ent->varname) + if (ent->varname) { efree(ent->varname); - efree(ent); + } + ent->data = NULL; } break;