CVE-2022-1052 (published 2022-03-24T13:15Z)

Heap Buffer Overflow in iterate_chained_fixups in GitHub repository radareorg/radare2 prior to 5.6.6.

Severity: LOW
CVSS v2 base score: 2.1 (AV:L/AC:L/Au:N/C:N/I:N/A:P)
CVSS v3 base score: 5.5, MEDIUM (CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: CWE-787
cwe_name: Out-of-bounds Write
description: The product writes data past the end, or before the beginning, of the intended buffer.
extended_description: 
            
            
             
			 
         
         

Fix information:
repo_url: https://github.com/radareorg/radare2
commit_details: repo_url: https://github.com/radareorg/radare2
author: pancake
author_date: 2022-03-22 16:56:27+01:00
msg: Fix heap OOB read in macho.iterate_chained_fixups ##crash

* Reported by peacock-doris via huntr.dev
* Reproducer 'tests_65305'

mrmacete:
* Return early if segs_count is 0
* Initialize segs_count also for reconstructed fixups

Co-authored-by: pancake <pancake@nopcode.org>
Co-authored-by: Francesco Tamagni <mrmacete@protonmail.ch>
repository: repo_url: https://github.com/radareorg/radare2
repo_name: radareorg/radare2
description: UNIX-like reverse engineering framework and command-line toolset
repo_language: C
owner: radareorg
file_changes: filename: mach0.c
change_type: ModificationType.MODIFY
diff: @@ -1510,10 +1510,11 @@ static bool parse_chained_fixups(struct MACH0_(obj_t) *bin, ut32 offset, ut32 si
 	if (header.starts_offset > size) {
 		return false;
 	}
-	ut32 segs_count;
-	if ((segs_count = r_buf_read_le32_at (bin->b, starts_at)) == UT32_MAX) {
+	ut32 segs_count = r_buf_read_le32_at (bin->b, starts_at);
+	if (segs_count == UT32_MAX || segs_count == 0) {
 		return false;
 	}
+	bin->segs_count = segs_count;
 	bin->chained_starts = R_NEWS0 (struct r_dyld_chained_starts_in_segment *, segs_count);
 	if (!bin->chained_starts) {
 		return false;
@@ -1699,6 +1700,7 @@ static bool reconstruct_chained_fixup(struct MACH0_(obj_t) *bin) {
 	}
 	R_FREE (opcodes);
 
+	bin->segs_count = bin->nsegs;
 	return true;
 }
 
@@ -2124,7 +2126,7 @@ void *MACH0_(mach0_free)(struct MACH0_(obj_t) *mo) {
 	free (mo->intrp);
 	free (mo->compiler);
 	if (mo->chained_starts) {
-		for (i = 0; i < mo->nsegs; i++) {
+		for (i = 0; i < mo->nsegs && i < mo->segs_count; i++) {
 			if (mo->chained_starts[i]) {
 				free (mo->chained_starts[i]->page_start);
 				free (mo->chained_starts[i]);
@@ -4558,7 +4560,7 @@ struct MACH0_(mach_header) *MACH0_(get_hdr)(RBuffer *buf) {
 
 void MACH0_(iterate_chained_fixups)(struct MACH0_(obj_t) *bin, ut64 limit_start, ut64 limit_end, ut32 event_mask, RFixupCallback callback, void * context) {
 	int i = 0;
-	for (; i < bin->nsegs; i++) {
+	for (; i < bin->nsegs && i < bin->segs_count; i++) {
 		if (!bin->chained_starts[i]) {
 			continue;
 		}

programming_language: C
filename: mach0.h
change_type: ModificationType.MODIFY
diff: @@ -130,6 +130,7 @@ struct MACH0_(obj_t) {
 	char *intrp;
 	char *compiler;
 	int nsegs;
+	int segs_count;
 	struct r_dyld_chained_starts_in_segment **chained_starts;
 	struct dyld_chained_fixups_header fixups_header;
 	ut64 fixups_offset;

programming_language: C
filename: cmd_api.c
change_type: ModificationType.MODIFY
diff: @@ -391,7 +391,7 @@ R_API int r_cmd_alias_set_raw(RCmd *cmd, const char *k, const ut8 *v, int sz) {
 
 R_API RCmdAliasVal *r_cmd_alias_get(RCmd *cmd, const char *k) {
 	r_return_val_if_fail (cmd && cmd->aliases && k, NULL);
-	return ht_pp_find(cmd->aliases, k, NULL);
+	return ht_pp_find (cmd->aliases, k, NULL);
 }
 
 static ut8 *alias_append_internal(int *out_szp, const RCmdAliasVal *first, const ut8 *second, int second_sz) {

programming_language: C