CVE-2022-0695: Uncontrolled Resource Consumption (CWE-400)
value: Denial of Service in GitHub repository radareorg/radare2 prior to 5.6.4.
CWE description: The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources.
CVSS v3 base score: 5.5
Published: 2022-02-24T13:15Z
Repository: https://github.com/radareorg/radare2
Language: C
Files changed: libr/bin/format/pe/pe.c, libr/bin/p/bin_dyldcache.c, libr/bin/p/bin_psxexe.c, libr/bin/p/bin_qnx.c, libr/util/buf.c
Commit date: 2022-02-24 04:53:06 +0100
Commit message: Fix DoS in PE/QNX/DYLDCACHE/PSX parsers ##crash

* Reported by lazymio
* Reproducer: AAA4AAAAAB4=

Diff: diff --git a/libr/bin/format/pe/pe.c b/libr/bin/format/pe/pe.c
index e133451d084..7718abebca8 100644
--- a/libr/bin/format/pe/pe.c
+++ b/libr/bin/format/pe/pe.c
@@ -1,6 +1,6 @@
-/* radare - LGPL - Copyright 2008-2021 nibble, pancake, inisider */
+/* radare - LGPL - Copyright 2008-2022 nibble, pancake, inisider */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <r_hash.h>
@@ -276,19 +276,17 @@ struct r_bin_pe_addr_t *PE_(check_msvcseh)(RBinPEObj *pe) {
 	free (entry);
 	return NULL;
 }
 
 struct r_bin_pe_addr_t *PE_(check_mingw)(RBinPEObj *pe) {
-	struct r_bin_pe_addr_t* entry;
 	bool sw = false;
-	ut8 b[1024];
+	ut8 b[1024] = {0};
 	size_t n = 0;
 	if (!pe || !pe->b) {
 		return 0LL;
 	}
-	entry = PE_(r_bin_pe_get_entrypoint) (pe);
-	ZERO_FILL (b);
+	struct r_bin_pe_addr_t* entry = PE_(r_bin_pe_get_entrypoint) (pe);
 	if (r_buf_read_at (pe->b, entry->paddr, b, sizeof (b)) < 0) {
 		pe_printf ("Warning: Cannot read entry at 0x%08"PFMT64x "\n", entry->paddr);
 		free (entry);
 		return NULL;
 	}
@@ -337,15 +335,15 @@ struct r_bin_pe_addr_t *PE_(check_mingw)(RBinPEObj *pe) {
 struct r_bin_pe_addr_t *PE_(check_unknow)(RBinPEObj *pe) {
 	struct r_bin_pe_addr_t *entry;
 	if (!pe || !pe->b) {
 		return 0LL;
 	}
-	ut8 b[512];
+	ut8 b[512] = {0};
 	ZERO_FILL (b);
 	entry = PE_ (r_bin_pe_get_entrypoint) (pe);
 	// option2: /x 8bff558bec83ec20
-	if (r_buf_read_at (pe->b, entry->paddr, b, 512) < 1) {
+	if (r_buf_read_at (pe->b, entry->paddr, b, sizeof (b)) != sizeof (b)) {
 		pe_printf ("Warning: Cannot read entry at 0x%08"PFMT64x"\n", entry->paddr);
 		free (entry);
 		return NULL;
 	}
 	/* Decode the jmp instruction, this gets the address of the 'main'
@@ -535,11 +533,12 @@ static int bin_pe_parse_imports(RBinPEObj* pe,
 				name[0] = '\0';
 				len = r_buf_read_at (pe->b, off + sizeof (PE_Word), (ut8*) name, PE_NAME_LENGTH);
 				if (len < 1) {
 					pe_printf ("Warning: read (import name)\n");
 					goto error;
-				} else if (!*name) {
+				}
+				if (!*name) {
 					break;
 				}
 				name[PE_NAME_LENGTH] = '\0';
 				int len = snprintf (import_name, sizeof (import_name), "%s" , name);
 				if (len >= sizeof (import_name)) {
@@ -1256,11 +1255,10 @@ static bool bin_pe_init_metadata_hdr(RBinPEObj* pe) {
 	}
 
 	// read the header after the string
 	rr = r_buf_fread_at (pe->b, metadata_directory + 16 + metadata->VersionStringLength,
 		(ut8*) (&metadata->Flags), pe->big_endian? "2S": "2s", 1);
-
 	if (rr < 1) {
 		goto fail;
 	}
 
 	eprintf ("Number of Metadata Streams: %d\n", metadata->NumberOfStreams);
@@ -1818,11 +1816,11 @@ static Var* Pe_r_bin_pe_parse_var(RBinPEObj* pe, PE_DWord* curAddr) {
 	if (!var->szKey) {
 		pe_printf ("Warning: malloc (Var szKey)\n");
 		free_Var (var);
 		return NULL;
 	}
-	if (r_buf_read_at (pe->b, *curAddr, (ut8*) var->szKey, TRANSLATION_UTF_16_LEN) < 1) {
+	if (r_buf_read_at (pe->b, *curAddr, (ut8*) var->szKey, TRANSLATION_UTF_16_LEN) != TRANSLATION_UTF_16_LEN) {
 		pe_printf ("Warning: read (Var szKey)\n");
 		free_Var (var);
 		return NULL;
 	}
 	*curAddr += TRANSLATION_UTF_16_LEN;
diff --git a/libr/bin/p/bin_dyldcache.c b/libr/bin/p/bin_dyldcache.c
index 6b7b512b713..d5700f16821 100644
--- a/libr/bin/p/bin_dyldcache.c
+++ b/libr/bin/p/bin_dyldcache.c
@@ -585,11 +585,11 @@ static ut64 estimate_slide(RBinFile *bf, RDyldCache *cache, ut64 value_mask, ut6
 
 		int classlist_sample_size = R_MIN (64, sections[classlist_idx].size);
 		int n_classes = classlist_sample_size / 8;
 		ut64 sect_offset = sections[classlist_idx].offset + bin->hdr_offset;
 
-		if (r_buf_fread_at (cache->buf, sect_offset, (ut8*) classlist, "l", n_classes) < classlist_sample_size) {
+		if (r_buf_fread_at (cache->buf, sect_offset, (ut8*) classlist, "l", n_classes) != classlist_sample_size) {
 			goto next_bin;
 		}
 
 		ut64 data_addr = sections[data_idx].addr;
 		ut64 data_tail = data_addr & 0xfff;
diff --git a/libr/bin/p/bin_psxexe.c b/libr/bin/p/bin_psxexe.c
index 56e90384a86..5865bf0677b 100644
--- a/libr/bin/p/bin_psxexe.c
+++ b/libr/bin/p/bin_psxexe.c
@@ -55,11 +55,11 @@ static RList* sections(RBinFile* bf) {
 	if (!(sect = R_NEW0 (RBinSection))) {
 		r_list_free (ret);
 		return NULL;
 	}
 
-	if (r_buf_fread_at (bf->buf, 0, (ut8*)&psxheader, "8c17i", 1) < sizeof (psxexe_header)) {
+	if (r_buf_fread_at (bf->buf, 0, (ut8*)&psxheader, "8c17i", 1) != sizeof (psxexe_header)) {
 		eprintf ("Truncated Header\n");
 		free (sect);
 		r_list_free (ret);
 		return NULL;
 	}
@@ -91,11 +91,11 @@ static RList* entries(RBinFile* bf) {
 	if (!(addr = R_NEW0 (RBinAddr))) {
 		r_list_free (ret);
 		return NULL;
 	}
 
-	if (r_buf_fread_at (bf->buf, 0, (ut8*)&psxheader, "8c17i", 1) < sizeof (psxexe_header)) {
+	if (r_buf_fread_at (bf->buf, 0, (ut8*)&psxheader, "8c17i", 1) != sizeof (psxexe_header)) {
 		eprintf ("PSXEXE Header truncated\n");
 		r_list_free (ret);
 		free (addr);
 		return NULL;
 	}
diff --git a/libr/bin/p/bin_qnx.c b/libr/bin/p/bin_qnx.c
index c3e93c930a3..a00e2631faf 100644
--- a/libr/bin/p/bin_qnx.c
+++ b/libr/bin/p/bin_qnx.c
@@ -5,11 +5,11 @@
 
 static int lmf_header_load(lmf_header *lmfh, RBuffer *buf, Sdb *db) {
 	if (r_buf_size (buf) < sizeof (lmf_header)) {
 		return false;
 	}
-	if (r_buf_fread_at (buf, QNX_HEADER_ADDR, (ut8 *) lmfh, "iiiiiiiicccciiiicc", 1) < QNX_HDR_SIZE) {
+	if (r_buf_fread_at (buf, QNX_HEADER_ADDR, (ut8 *) lmfh, "iiiiiiiicccciiiicc", 1) != QNX_HDR_SIZE) {
 		return false;
 	}
 	r_strf_buffer (32);
 	sdb_set (db, "qnx.version", r_strf ("0x%xH", lmfh->version), 0);
 	sdb_set (db, "qnx.cflags", r_strf ("0x%xH", lmfh->cflags), 0);
@@ -62,19 +62,19 @@ static bool load_buffer(RBinFile *bf, void **bin_obj, RBuffer *buf, ut64 loadadd
 	qo->kv = sdb_new0 ();
 	if (!qo->kv) {
 		goto beach;
 	}
 	// Read the first record
-	if (r_buf_fread_at (bf->buf, 0, (ut8 *)&lrec, "ccss", 1) < QNX_RECORD_SIZE) {
+	if (r_buf_fread_at (bf->buf, 0, (ut8 *)&lrec, "ccss", 1) != QNX_RECORD_SIZE) {
 		goto beach;
 	}
 	// Load the header
 	lmf_header_load (&qo->lmfh, bf->buf, qo->kv);
 	offset += lrec.data_nbytes;
 
 	for (;;) {
-		if (r_buf_fread_at (bf->buf, offset, (ut8 *)&lrec, "ccss", 1) < QNX_RECORD_SIZE) {
+		if (r_buf_fread_at (bf->buf, offset, (ut8 *)&lrec, "ccss", 1) != QNX_RECORD_SIZE) {
 			goto beach;
 		}
 		offset += sizeof (lmf_record);
 
 		if (lrec.rec_type == LMF_IMAGE_END_REC) {
@@ -82,22 +82,22 @@ static bool load_buffer(RBinFile *bf, void **bin_obj, RBuffer *buf, ut64 loadadd
 		} else if (lrec.rec_type == LMF_RESOURCE_REC) {
 			RBinSection *ptr = R_NEW0 (RBinSection);
 			if (!ptr) {
 				goto beach;
 			}
-			if (r_buf_fread_at (bf->buf, offset, (ut8 *)&lres, "ssss", 1) < sizeof (lmf_resource)) {
+			if (r_buf_fread_at (bf->buf, offset, (ut8 *)&lres, "ssss", 1) != sizeof (lmf_resource)) {
 				goto beach;
 			}
 			ptr->name = strdup ("LMF_RESOURCE");
 			ptr->paddr = offset;
 			ptr->vsize = lrec.data_nbytes - sizeof (lmf_resource);
 			ptr->size = ptr->vsize;
 			ptr->add = true;
 		 	r_list_append (sections, ptr);
 		} else if (lrec.rec_type == LMF_LOAD_REC) {
 			RBinSection *ptr = R_NEW0 (RBinSection);
-			if (r_buf_fread_at (bf->buf, offset, (ut8 *)&ldata, "si", 1) < sizeof (lmf_data)) {
+			if (r_buf_fread_at (bf->buf, offset, (ut8 *)&ldata, "si", 1) != sizeof (lmf_data)) {
 				goto beach;
 			}
 			if (!ptr) {
 				goto beach;
 			}
@@ -108,19 +108,19 @@ static bool load_buffer(RBinFile *bf, void **bin_obj, RBuffer *buf, ut64 loadadd
 			ptr->size = ptr->vsize;
 			ptr->add = true;
 		 	r_list_append (sections, ptr);
 		} else if (lrec.rec_type == LMF_FIXUP_REC) {
 			RBinReloc *ptr = R_NEW0 (RBinReloc);
-			if (!ptr || r_buf_fread_at (bf->buf, offset, (ut8 *)&ldata, "si", 1) < sizeof (lmf_data)) {
+			if (!ptr || r_buf_fread_at (bf->buf, offset, (ut8 *)&ldata, "si", 1) != sizeof (lmf_data)) {
 				goto beach;
 			}
 			ptr->vaddr = ptr->paddr = ldata.offset;
 			ptr->type = 'f'; // "LMF_FIXUP";
 			r_list_append (fixups, ptr);
 		} else if (lrec.rec_type == LMF_8087_FIXUP_REC) {
 			RBinReloc *ptr = R_NEW0 (RBinReloc);
-			if (!ptr || r_buf_fread_at (bf->buf, offset, (ut8 *)&ldata, "si", 1) < sizeof (lmf_data)) {
+			if (!ptr || r_buf_fread_at (bf->buf, offset, (ut8 *)&ldata, "si", 1) != sizeof (lmf_data)) {
 				goto beach;
 			}
 			ptr->vaddr = ptr->paddr = ldata.offset;
 			ptr->type = 'F'; // "LMF_8087_FIXUP";
 			r_list_append (fixups, ptr);
diff --git a/libr/util/buf.c b/libr/util/buf.c
index b20e481d470..5aa93ca64bc 100644
--- a/libr/util/buf.c
+++ b/libr/util/buf.c
@@ -514,14 +514,13 @@ static st64 buf_format(RBuffer *dst, RBuffer *src, const char *fmt, int n) {
 				ut8 d1;
 				ut16 d2;
 				ut32 d3;
 				ut64 d4;
 				st64 r = r_buf_read (src, tmp, tsize);
-				if (r < tsize) {
+				if (r != tsize) {
 					return -1;
 				}
-
 				switch (tsize) {
 				case 1:
 					d1 = r_read_ble8 (tmp);
 					r = r_buf_write (dst, (ut8 *)&d1, 1);
 					break;
@@ -564,11 +563,11 @@ R_API st64 r_buf_fread_at(RBuffer *b, ut64 addr, ut8 *buf, const char *fmt, int
 	st64 r = r_buf_seek (b, addr, R_BUF_SET);
 	if (r < 0) {
 		return r;
 	}
 	r = r_buf_fread (b, buf, fmt, n);
-	r_buf_seek (b, o_addr, R_BUF_SET);
+	(void)r_buf_seek (b, o_addr, R_BUF_SET);
 	return r;
 }
 
 R_API st64 r_buf_fwrite(RBuffer *b, const ut8 *buf, const char *fmt, int n) {
 	r_return_val_if_fail (b && buf && fmt && !b->readonly, -1);
@@ -596,11 +595,10 @@ R_API st64 r_buf_read_at(RBuffer *b, ut64 addr, ut8 *buf, ut64 len) {
 	st64 o_addr = r_buf_seek (b, 0, R_BUF_CUR);
 	st64 r = r_buf_seek (b, addr, R_BUF_SET);
 	if (r < 0) {
 		return r;
 	}
-
 	r = r_buf_read (b, buf, len);
 	r_buf_seek (b, o_addr, R_BUF_SET);
 	return r;
 }
 

Vulnerable code: /* radare - LGPL - Copyright 2008-2021 nibble, pancake, inisider */
	struct r_bin_pe_addr_t* entry;
	ut8 b[1024];
	entry = PE_(r_bin_pe_get_entrypoint) (pe);
	ZERO_FILL (b);
	ut8 b[512];
	if (r_buf_read_at (pe->b, entry->paddr, b, 512) < 1) {
				} else if (!*name) {

	if (r_buf_read_at (pe->b, *curAddr, (ut8*) var->szKey, TRANSLATION_UTF_16_LEN) < 1) {
		if (r_buf_fread_at (cache->buf, sect_offset, (ut8*) classlist, "l", n_classes) < classlist_sample_size) {
	if (r_buf_fread_at (bf->buf, 0, (ut8*)&psxheader, "8c17i", 1) < sizeof (psxexe_header)) {
	if (r_buf_fread_at (bf->buf, 0, (ut8*)&psxheader, "8c17i", 1) < sizeof (psxexe_header)) {
	if (r_buf_fread_at (buf, QNX_HEADER_ADDR, (ut8 *) lmfh, "iiiiiiiicccciiiicc", 1) < QNX_HDR_SIZE) {
	if (r_buf_fread_at (bf->buf, 0, (ut8 *)&lrec, "ccss", 1) < QNX_RECORD_SIZE) {
		if (r_buf_fread_at (bf->buf, offset, (ut8 *)&lrec, "ccss", 1) < QNX_RECORD_SIZE) {
			if (r_buf_fread_at (bf->buf, offset, (ut8 *)&lres, "ssss", 1) < sizeof (lmf_resource)) {
			if (r_buf_fread_at (bf->buf, offset, (ut8 *)&ldata, "si", 1) < sizeof (lmf_data)) {
			if (!ptr || r_buf_fread_at (bf->buf, offset, (ut8 *)&ldata, "si", 1) < sizeof (lmf_data)) {
			if (!ptr || r_buf_fread_at (bf->buf, offset, (ut8 *)&ldata, "si", 1) < sizeof (lmf_data)) {
				if (r < tsize) {

	r_buf_seek (b, o_addr, R_BUF_SET);

Fixed code: /* radare - LGPL - Copyright 2008-2022 nibble, pancake, inisider */
	ut8 b[1024] = {0};
	struct r_bin_pe_addr_t* entry = PE_(r_bin_pe_get_entrypoint) (pe);
	ut8 b[512] = {0};
	if (r_buf_read_at (pe->b, entry->paddr, b, sizeof (b)) != sizeof (b)) {
				}
				if (!*name) {
	if (r_buf_read_at (pe->b, *curAddr, (ut8*) var->szKey, TRANSLATION_UTF_16_LEN) != TRANSLATION_UTF_16_LEN) {
		if (r_buf_fread_at (cache->buf, sect_offset, (ut8*) classlist, "l", n_classes) != classlist_sample_size) {
	if (r_buf_fread_at (bf->buf, 0, (ut8*)&psxheader, "8c17i", 1) != sizeof (psxexe_header)) {
	if (r_buf_fread_at (bf->buf, 0, (ut8*)&psxheader, "8c17i", 1) != sizeof (psxexe_header)) {
	if (r_buf_fread_at (buf, QNX_HEADER_ADDR, (ut8 *) lmfh, "iiiiiiiicccciiiicc", 1) != QNX_HDR_SIZE) {
	if (r_buf_fread_at (bf->buf, 0, (ut8 *)&lrec, "ccss", 1) != QNX_RECORD_SIZE) {
		if (r_buf_fread_at (bf->buf, offset, (ut8 *)&lrec, "ccss", 1) != QNX_RECORD_SIZE) {
			if (r_buf_fread_at (bf->buf, offset, (ut8 *)&lres, "ssss", 1) != sizeof (lmf_resource)) {
			if (r_buf_fread_at (bf->buf, offset, (ut8 *)&ldata, "si", 1) != sizeof (lmf_data)) {
			if (!ptr || r_buf_fread_at (bf->buf, offset, (ut8 *)&ldata, "si", 1) != sizeof (lmf_data)) {
			if (!ptr || r_buf_fread_at (bf->buf, offset, (ut8 *)&ldata, "si", 1) != sizeof (lmf_data)) {
				if (r != tsize) {
	(void)r_buf_seek (b, o_addr, R_BUF_SET);