Commit message: Fix bug #73831 - NULL Pointer Dereference while unserialize php object
CVE: CVE-2016-10162
CWE: CWE-476
Vulnerability description: The php_wddx_pop_element function in ext/wddx/wddx.c in PHP 7.0.x before 7.0.15 and 7.1.x before 7.1.1 allows remote attackers to cause a denial of service (NULL pointer dereference and application crash) via an inapplicable class name in a wddxPacket XML document, leading to mishandling in a wddx_deserialize call.

Project: php-src

int php_wddx_deserialize_ex(const char *value, size_t vallen, zval *return_value)
{
	wddx_stack stack;
	XML_Parser parser;
	st_entry *ent;
	int retval;

	wddx_stack_init(&stack);
	parser = XML_ParserCreate((XML_Char *) "UTF-8");

	XML_SetUserData(parser, &stack);
	XML_SetElementHandler(parser, php_wddx_push_element, php_wddx_pop_element);
	XML_SetCharacterDataHandler(parser, php_wddx_process_data);

	/* XXX value should be parsed in the loop to exhaust size_t */
	XML_Parse(parser, (const XML_Char *) value, (int)vallen, 1);

	XML_ParserFree(parser);

	if (stack.top == 1) {
		wddx_stack_top(&stack, (void**)&ent);
		if (Z_ISUNDEF(ent->data)) {
			retval = FAILURE;
		} else {
			ZVAL_COPY(return_value, &ent->data);
			retval = SUCCESS;
		}
	} else {
		retval = FAILURE;
	}

	wddx_stack_destroy(&stack);

	return retval;
}

Project: php-src

void php_wddx_serialize_var(wddx_packet *packet, zval *var, zend_string *name)
{
	HashTable *ht;

	if (name) {
		char *tmp_buf;
		zend_string *name_esc = php_escape_html_entities((unsigned char *) ZSTR_VAL(name), ZSTR_LEN(name), 0, ENT_QUOTES, NULL);
		tmp_buf = emalloc(ZSTR_LEN(name_esc) + sizeof(WDDX_VAR_S));
		snprintf(tmp_buf, ZSTR_LEN(name_esc) + sizeof(WDDX_VAR_S), WDDX_VAR_S, ZSTR_VAL(name_esc));
		php_wddx_add_chunk(packet, tmp_buf);
		efree(tmp_buf);
		zend_string_release(name_esc);
	}

	if (Z_TYPE_P(var) == IS_INDIRECT) {
		var = Z_INDIRECT_P(var);
	}
	ZVAL_DEREF(var);
	switch (Z_TYPE_P(var)) {
		case IS_STRING:
			php_wddx_serialize_string(packet, var);
			break;

		case IS_LONG:
		case IS_DOUBLE:
			php_wddx_serialize_number(packet, var);
			break;

		case IS_TRUE:
		case IS_FALSE:
			php_wddx_serialize_boolean(packet, var);
			break;

		case IS_NULL:
			php_wddx_serialize_unset(packet);
			break;

		case IS_ARRAY:
			ht = Z_ARRVAL_P(var);
			if (ht->u.v.nApplyCount > 1) {
				php_error_docref(NULL, E_RECOVERABLE_ERROR, "WDDX doesn't support circular references");
				return;
			}
			if (ZEND_HASH_APPLY_PROTECTION(ht)) {
				ht->u.v.nApplyCount++;
			}
			php_wddx_serialize_array(packet, var);
			if (ZEND_HASH_APPLY_PROTECTION(ht)) {
				ht->u.v.nApplyCount--;
			}
			break;

		case IS_OBJECT:
			ht = Z_OBJPROP_P(var);
			if (ht->u.v.nApplyCount > 1) {
				php_error_docref(NULL, E_RECOVERABLE_ERROR, "WDDX doesn't support circular references");
				return;
			}
			ht->u.v.nApplyCount++;
 			php_wddx_serialize_object(packet, var);
			ht->u.v.nApplyCount--;
			break;
	}

	if (name) {
		php_wddx_add_chunk_static(packet, WDDX_VAR_E);
	}
}

Project: php-src

static int wddx_stack_destroy(wddx_stack *stack)
{
	register int i;

	if (stack->elements) {
		for (i = 0; i < stack->top; i++) {
			if (Z_TYPE(((st_entry *)stack->elements[i])->data) != IS_UNDEF
					&& ((st_entry *)stack->elements[i])->type != ST_FIELD)	{
				zval_ptr_dtor(&((st_entry *)stack->elements[i])->data);
			}
			if (((st_entry *)stack->elements[i])->varname) {
				efree(((st_entry *)stack->elements[i])->varname);
			}
			efree(stack->elements[i]);
		}
		efree(stack->elements);
	}
	return SUCCESS;
}