POSTED BY: Angelos T. Kalaitzidis / 24.05.2022

Multiple vulnerabilities in radare2

CENSUS ID:CENSUS-2022-0001
CVE IDs:CVE-2022-0419, CVE-2021-44974, CVE-2021-44975
Affected Products:radare2 versions prior to 5.6.0
Class:NULL pointer dereference (CWE-476), Heap-based buffer overflow (CWE-122)
Discovered by:Angelos T. Kalaitzidis

CENSUS identified a number of NULL pointer dereference and Heap buffer overflow bugs in the radare2 project code. Radare2 is a popular reverse engineering framework. CENSUS has verified that release 5.6.0 of radare2 carries the appropriate fixes to remediate all of the identified issues.

CVE-2022-0419 Vulnerability Details

Function load_buffer of radare2/libr/bin/p/bin_xnu_kernelcache.c uses a pointer (obj) which remains initialized to NULL, when a call to function get_prelink_info_range_from_mach0() fails (i.e. returns NULL). The code snippet below shows this problematic code path:


static bool load_buffer(RBinFile *bf, void **bin_obj, RBuffer *buf, ut64 loadaddr, Sdb *sdb) {
    ...
189 RKernelCacheObj *obj = NULL; // 1

191 RPrelinkRange *prelink_range = get_prelink_info_range_from_mach0 (main_mach0);
192 if (!prelink_range) {
193     goto beach;              // 2
194 }
....
243 beach:
244 r_buf_free (fbuf);
245 obj->cache_buf = NULL;       // 3
244 MACH0_(mach0_free) (main_mach0);
245 return false;

When get_prelink_info_range_from_mach0() returns NULL, obj remains NULL and the code branches to line 243. There an access to the obj pointer is made on line 245, resulting to a NULL pointer dereference and a program crash.

The issue has been patched in version 5.6.0 of radare2.

CVE-2021-44975 Vulnerability Details

The objc_build_refs function is responsible for building the references of a mach-o file as its name suggests. The function can be found out at /radare2/libr/core/anal_objc.c


static bool objc_build_refs(RCoreObjc *objc) {
	...

	size_t ss_selrefs = objc->_selrefs->vsize;

	size_t maxsize = R_MAX (ss_const, ss_selrefs); // 1
	maxsize = R_MIN (maxsize, objc->file_size);    

	ut8 *buf = calloc (1, maxsize);				   
	if (!buf) {
		return false;
	}

	...
	if (!r_io_read_at (objc->core->io, va_selrefs, buf, ss_selrefs)) { // 2
		eprintf ("aao: Cannot read the whole selrefs section\n");
		return false;
	}
	...
	free (buf);
	return true;
}

At comment #1 the maxsize quantity is calculated based on the largest value between ss_const and ss_selrefs (see R_MAX macro). Lets consider that the largest of the two is ss_selrefs. Then maxsize is recalculated based on the lowest value (see R_MIN macro) between the previously calculated maxsize and objc->file_size. Therefore, there may be a case where ss_selrefs will be greater than objc->file_size and in that case maxsize will be equal to objc->file_size.

In the above case, buffer buf is dynamically allocated with maxsize (i.e. objc->file_size) bytes. However the r_io_read_at() operation at comment #2 will copy ss_selrefs bytes to the buffer, resulting to a heap buffer overflow as ss_selrefs would be greater than objc->file_size.

A similar vulnerability also exists in other code of the same function:



	size_t ss_const = objc->_const->vsize;
....
	if (!r_io_read_at (objc->core->io, objc->_const->vaddr, buf, ss_const)) {
		eprintf ("aao: Cannot read the whole const section %zu\n", ss_const);
		return false;
	}

Again, ss_const can be greater than objc->file_size resulting to a heap buffer overflow.

Version 5.6.0 of radare2 comes with the appropriate fix for these issues.

CVE-2021-44974 Vulnerability Details

A NULL pointer dereference vulnerability exists in the symbols() function of /radare2/libr/bin/bin_symbols.c.


static RList *symbols(RBinFile *bf) {
	RCoreSymCacheElement *element = bf->o->bin_obj;
	...
	// Parse symbols to a hash table
	for (i = 0; i < element->hdr->n_symbols; i++) {
		RCoreSymCacheElementSymbol *sym = &element->symbols[i]; // 1
		ht_uu_find (hash, sym->paddr, &found);                  
		if (found) {
			continue;
		}
		RBinSymbol *s = bin_symbol_from_symbol (element, sym);
		if (s) {
			r_list_append (res, s);
		}
	}
	ht_uu_free (hash);
	return res;
}

As illustrated in the code snippet above, the element pointer points to adversary-controlled data (as bf->o->bin_obj essentially points to data of the binary file). The element->symbols array, is an array of symbols for an object of the file that is being loaded for analysis. In the case where the pointer element->symbols[0] is NULL (which is possible as we are talking about adversary-controlled data) the sym pointer would also be set to NULL (see comment #1). Then in the next line sym is accessed through the sym->paddr expression and this leads to a NULL pointer dereference and a program crash.

This issue has been patched in version 5.5.4 of radare2.

Recommendation

CENSUS advises users to use a radare2 version greater or equal to 5.6.0, as this version carries appropriate patches that remediate correctly all of the aforementioned issues.

Disclosure Timeline

Vendor Contact:December 7, 2021
CVE Allocation:December 13, 2021
Vendor Fix Released:February 2, 2022
Public Advisory:May 24, 2022