xorl %eax, %eax

NetBSD-SA2009-003: proplib XML Parsing NULL Pointer Dereference

leave a comment »

This bug was disclosed by NetBSD on 22 June 2009 and affects all the releases of NetBSD up to 30 March 2009’s NetBSD-current one. This library is widely used in device drivers for communication between kernel and user space. The bug can be found at src/common/lib/libprop/prop_object.c. Here is the vulnerable routine.

/*
 * _prop_object_internalize_by_tag --
 *	Determine the object type from the tag in the context and
 *	internalize it.
 */
prop_object_t
_prop_object_internalize_by_tag(struct _prop_object_internalize_context *ctx)
{
	const struct _prop_object_internalizer *poi;
	prop_object_t obj, parent_obj;
	void *data, *iter;
	prop_object_internalizer_continue_t iter_func;
	struct _prop_stack stack;

	_prop_stack_init(&stack);

match_start:
	for (poi = _prop_object_internalizer_table;
	     poi->poi_tag != NULL; poi++) {
		if (_prop_object_internalize_match(ctx->poic_tagname,
						   ctx->poic_tagname_len,
						   poi->poi_tag,
						   poi->poi_taglen))
			break;
	}
	if (poi == NULL) {
		while (_prop_stack_pop(&stack, &obj, &iter, &data, NULL)) {
			iter_func = (prop_object_internalizer_continue_t)iter;
			(*iter_func)(&stack, &obj, ctx, data, NULL);
		}

		return (NULL);
	}

	obj = NULL;
	if (!(*poi->poi_intern)(&stack, &obj, ctx))
		goto match_start;

	parent_obj = obj;
	while (_prop_stack_pop(&stack, &parent_obj, &iter, &data, NULL)) {
		iter_func = (prop_object_internalizer_continue_t)iter;
		if (!(*iter_func)(&stack, &parent_obj, ctx, data, obj))
			goto match_start;
		obj = parent_obj;
	}

	return (parent_obj);
}

As you can see, _prop_object_internalize_by_tag() initializes a stack using _prop_stack_init() and then, it enters the main loop. Then, it iterates through every tag and attempts to find matches between context tag name (ctx->poinc_tagname) and the current tag name (poi->poi_tag) using _prop_object_internalize_match(). If poi object is NULL, thus it has reached the end, it will pop the objects from the stack and return NULL. However, even though poi might not be NULL, if there is no tag matched, then poi->poi_tag will be NULL and it will lead to a NULL pointer dereference when poi_intern() is invoked in the last if statement. For completeness, here is its structure.

static const struct _prop_object_internalizer {
	const char			*poi_tag;
	size_t				poi_taglen;
	prop_object_internalizer_t	poi_intern;
} _prop_object_internalizer_table[] = {
	INTERNALIZER("array", _prop_array_internalize),
	INTERNALIZER("true", _prop_bool_internalize),
	INTERNALIZER("false", _prop_bool_internalize),
	INTERNALIZER("data", _prop_data_internalize),
	INTERNALIZER("dict", _prop_dictionary_internalize),
	INTERNALIZER("integer", _prop_number_internalize),
	INTERNALIZER("string", _prop_string_internalize),
	{ 0, 0, NULL }
};

This could be triggered when non-existing data type tag such as is declared in an XML file. To fix this, the following patch was applied.

        }
-       if (poi == NULL) {
+       if ((poi == NULL) || (poi->poi_tag == NULL)) {
                while (_prop_stack_pop(&stack, &obj, &iter, &data, NULL)) {

Using this, non existing data types in the XML file are handled correctly.

Written by xorl

June 23, 2009 at 21:02

Posted in bugs, netbsd

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s