From 35b7d0ca883788c175f155eb8306436df9d12c87 Mon Sep 17 00:00:00 2001 From: Fabio Arnold Date: Mon, 30 Sep 2024 15:16:53 +0200 Subject: [PATCH 1/2] Package fetch: add executable detection for Mach-O file headers --- src/Package/Fetch.zig | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/Package/Fetch.zig b/src/Package/Fetch.zig index 1229ca524c1c..24911187f88d 100644 --- a/src/Package/Fetch.zig +++ b/src/Package/Fetch.zig @@ -1789,12 +1789,9 @@ test { _ = UnpackResult; } -// Detects executable header: ELF magic header or shebang line. +// Detects executable header: ELF or Macho-O magic header or shebang line. const FileHeader = struct { - const elf_magic = std.elf.MAGIC; - const shebang = "#!"; - - header: [@max(elf_magic.len, shebang.len)]u8 = undefined, + header: [4]u8 = undefined, bytes_read: usize = 0, pub fn update(self: *FileHeader, buf: []const u8) void { @@ -1804,9 +1801,27 @@ const FileHeader = struct { self.bytes_read += n; } + fn isScript(self: *FileHeader) bool { + const shebang = "#!"; + return std.mem.eql(u8, self.header[0..@min(self.bytes_read, shebang.len)], shebang); + } + + fn isElf(self: *FileHeader) bool { + const elf_magic = std.elf.MAGIC; + return std.mem.eql(u8, self.header[0..@min(self.bytes_read, elf_magic.len)], elf_magic); + } + + fn isMachO(self: *FileHeader) bool { + if (self.bytes_read < 4) return false; + const magic_number = std.mem.readInt(u32, &self.header, builtin.cpu.arch.endian()); + return magic_number == std.macho.MH_MAGIC or + magic_number == std.macho.MH_MAGIC_64 or + magic_number == std.macho.FAT_MAGIC or + magic_number == std.macho.FAT_MAGIC_64; + } + pub fn isExecutable(self: *FileHeader) bool { - return std.mem.eql(u8, self.header[0..@min(self.bytes_read, shebang.len)], shebang) or - std.mem.eql(u8, self.header[0..@min(self.bytes_read, elf_magic.len)], elf_magic); + return self.isScript() or self.isElf() or self.isMachO(); } }; @@ -1821,6 +1836,11 @@ test FileHeader { h.update(FileHeader.elf_magic[2..4]); try std.testing.expect(h.isExecutable()); + + const macho64_magic_bytes = [_]u8{ 0xCF, 0xFA, 0xED, 0xFE }; + h.bytes_read = 0; + h.update(&macho64_magic_bytes); + try std.testing.expect(h.isExecutable()); } // Result of the `unpackResource` operation. Enables collecting errors from From b410f9d65cd8d5f9b0d30bc5fccbcb43a8dd5657 Mon Sep 17 00:00:00 2001 From: Fabio Arnold Date: Tue, 14 Jan 2025 14:12:40 +0100 Subject: [PATCH 2/2] Update `FileHeader` test --- src/Package/Fetch.zig | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Package/Fetch.zig b/src/Package/Fetch.zig index 24911187f88d..4d14b23d9dce 100644 --- a/src/Package/Fetch.zig +++ b/src/Package/Fetch.zig @@ -1829,12 +1829,13 @@ test FileHeader { var h: FileHeader = .{}; try std.testing.expect(!h.isExecutable()); - h.update(FileHeader.elf_magic[0..2]); + const elf_magic = std.elf.MAGIC; + h.update(elf_magic[0..2]); try std.testing.expect(!h.isExecutable()); - h.update(FileHeader.elf_magic[2..4]); + h.update(elf_magic[2..4]); try std.testing.expect(h.isExecutable()); - h.update(FileHeader.elf_magic[2..4]); + h.update(elf_magic[2..4]); try std.testing.expect(h.isExecutable()); const macho64_magic_bytes = [_]u8{ 0xCF, 0xFA, 0xED, 0xFE };