kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit f46d3c17738e810ae2964e5691842c90c19ce200
parent 4b204dc57ee22c8bbd6b4e2a5912c297abf0ca8b
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Thu, 16 Jul 2026 10:28:13 -0700

strip: reject malformed Mach-O debug ranges

Diffstat:
Mdoc/RELEASE_AUDIT_2026_6_0.md | 2+-
Msrc/obj/macho/rewrite.c | 19++++++++++++++++++-
Mtest/api/object_rewrite_test.c | 42++++++++++++++++++++++++++++++++++++++++++
3 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/doc/RELEASE_AUDIT_2026_6_0.md b/doc/RELEASE_AUDIT_2026_6_0.md @@ -500,7 +500,7 @@ Implementation checkpoint (updated 2026-07-16): | KIT-P2-001 | **Complete** | `test-driver-stack-protector`: 133 pass, 0 fail; cJSON build/test passes | | KIT-P1-015 | **Complete** | 21 multi-source dependency assertions pass in the driver suite | | KIT-P2-003 | **Complete** | `test-driver-diagnostics`: 15 pass, 0 fail | -| KIT-P1-007 | **Complete** | `test-driver-strip`: object API 23/0, relocatable/archive 5/0, linked ELF/Mach-O/PE matrix 91/0 | +| KIT-P1-007 | **Complete** | `test-driver-strip`: object API 26/0, relocatable/archive 5/0, linked ELF/Mach-O/PE matrix 91/0 | | KIT-P1-017 | In progress | implementation under focused CLI audit | | KIT-P2-002 | In progress | implementation under focused CLI audit | | KIT-P3-003 | **Complete** | `test-link-macho-symbols` passes aarch64 and x86-64 Kit/platform oracles | diff --git a/src/obj/macho/rewrite.c b/src/obj/macho/rewrite.c @@ -87,12 +87,29 @@ static KitStatus macho_validate(MachoRewriteView* v, const KitContext* ctx, if (size < 8 || pos + size > end) return macho_bad(v, "load-command size"); if (kind == LC_SEGMENT_64) { - u32 nsects; + u32 nsects, j; if (size < MACHO_SEGCMD64_SIZE) return macho_bad(v, "segment command"); nsects = obj_rw_u32(cmd + 64, 0); if ((u64)MACHO_SEGCMD64_SIZE + (u64)nsects * MACHO_SECT64_SIZE > size) return macho_bad(v, "segment sections"); + for (j = 0; j < nsects; ++j) { + const u8* sec = cmd + MACHO_SEGCMD64_SIZE + + (size_t)j * MACHO_SECT64_SIZE; + u64 sec_size = obj_rw_u64(sec + 40, 0); + u32 sec_off = obj_rw_u32(sec + 48, 0); + u32 reloc_off = obj_rw_u32(sec + 56, 0); + u32 nreloc = obj_rw_u32(sec + 60, 0); + u32 sec_type = obj_rw_u32(sec + 64, 0) & SECTION_TYPE; + int zerofill = sec_type == S_ZEROFILL || sec_type == 0x0cu || + sec_type == S_THREAD_LOCAL_ZEROFILL; + if (!zerofill && sec_size && + !obj_rw_range(v->rw.len, sec_off, sec_size)) + return macho_bad(v, "section contents"); + if (nreloc && + !obj_rw_range(v->rw.len, reloc_off, (u64)nreloc * 8u)) + return macho_bad(v, "section relocations"); + } } else if (kind == LC_SYMTAB) { u32 symoff, nsyms, stroff, strsize; if (size < MACHO_SYMTAB_CMD_SIZE) diff --git a/test/api/object_rewrite_test.c b/test/api/object_rewrite_test.c @@ -28,6 +28,11 @@ static void put32(uint8_t* p, uint32_t v) { p[3] = (uint8_t)(v >> 24); } +static void put64(uint8_t* p, uint64_t v) { + put32(p, (uint32_t)v); + put32(p + 4, (uint32_t)(v >> 32)); +} + static uint32_t get32(const uint8_t* p) { return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24); @@ -204,6 +209,42 @@ static void check_strip_all(KitUnit* u, const uint8_t* pe) { kit_writer_close(out); } +static void check_malformed_macho_section(KitUnit* u) { + uint8_t macho[184]; + KitSlice input; + KitLinkedRewriteOptions opts; + KitWriter* out = NULL; + size_t out_len = 99u; + KitStatus st; + memset(macho, 0, sizeof macho); + put32(macho, 0xfeedfacfu); /* MH_MAGIC_64 */ + put32(macho + 12, 2u); /* MH_EXECUTE */ + put32(macho + 16, 1u); /* ncmds */ + put32(macho + 20, 152u); /* sizeofcmds */ + put32(macho + 32, 0x19u); /* LC_SEGMENT_64 */ + put32(macho + 36, 152u); + memcpy(macho + 40, "__DWARF", 7u); + put32(macho + 96, 1u); /* nsects */ + memcpy(macho + 104, "__debug_info", 12u); + memcpy(macho + 120, "__DWARF", 7u); + put64(macho + 144, 16u); /* section size */ + put32(macho + 152, 4096u); /* impossible file offset */ + put32(macho + 168, 0x02000000u); /* S_ATTR_DEBUG */ + input.data = macho; + input.len = sizeof macho; + memset(&opts, 0, sizeof opts); + opts.strip_level = KIT_LINKED_STRIP_DEBUG; + CU_EXPECT(u, kit_writer_mem(&u->heap, &out) == KIT_OK && out, + "malformed Mach-O memory writer"); + st = kit_obj_rewrite_linked(&u->ctx, KIT_SLICE_LIT("bad-macho"), &input, + &opts, out, NULL); + CU_EXPECT(u, st == KIT_MALFORMED, + "out-of-range Mach-O debug section is malformed (%d)", (int)st); + (void)kit_writer_mem_bytes(out, &out_len); + CU_EXPECT(u, out_len == 0u, "malformed Mach-O emits no bytes"); + kit_writer_close(out); +} + int main(void) { KitUnit u; uint8_t pe[PE_SIZE]; @@ -212,6 +253,7 @@ int main(void) { check_signed_transaction(&u, pe); check_strip_debug(&u, pe); check_strip_all(&u, pe); + check_malformed_macho_section(&u); kit_unit_summary(&u, "object_rewrite_test"); return kit_unit_status(&u); }