From 0052500c1ed5bf8263b26b9fd7773dbdc6f170c4 Mon Sep 17 00:00:00 2001 From: pancake Date: Tue, 22 Mar 2022 16:56:27 +0100 Subject: [PATCH] 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 Co-authored-by: Francesco Tamagni --- libr/bin/format/mach0/mach0.c | 10 ++++++---- libr/bin/format/mach0/mach0.h | 1 + libr/core/cmd_api.c | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/libr/bin/format/mach0/mach0.c b/libr/bin/format/mach0/mach0.c index 679198ed62069..033f2e83b0cad 100644 --- a/libr/bin/format/mach0/mach0.c +++ b/libr/bin/format/mach0/mach0.c @@ -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; } diff --git a/libr/bin/format/mach0/mach0.h b/libr/bin/format/mach0/mach0.h index 442b4f1a3f0a1..0ad79a794e70c 100644 --- a/libr/bin/format/mach0/mach0.h +++ b/libr/bin/format/mach0/mach0.h @@ -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; diff --git a/libr/core/cmd_api.c b/libr/core/cmd_api.c index 14cd7fa97b579..71c4136405cb8 100644 --- a/libr/core/cmd_api.c +++ b/libr/core/cmd_api.c @@ -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) {