diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2020-11-28 14:51:31 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2020-12-01 10:49:31 +0100 |
| commit | c25b3593e726108cb7f208ef538df6979aeb41e1 (patch) | |
| tree | 27f8d6d0e77f694fae18cb460c57cafdf2cb7e63 /src | |
| parent | 545721ccd1e7297719fc53dfde99fa046fb3edef (diff) | |
| download | zig-c25b3593e726108cb7f208ef538df6979aeb41e1.tar.gz zig-c25b3593e726108cb7f208ef538df6979aeb41e1.zip | |
lld: add code signature to lld output
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/MachO.zig | 27 | ||||
| -rw-r--r-- | src/link/MachO/CodeSignature.zig | 77 |
2 files changed, 95 insertions, 9 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig index b0cc535916..23b21c20dd 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -812,28 +812,23 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { try parser.parseFile(out_file); // Pad out space for code signature const text_cmd = parser.load_commands.items[parser.text_cmd_index.?].Segment.inner; - std.debug.print("end_pos={},text_fileoff={},text_filesize={}\n", .{ - parser.end_pos, - text_cmd.fileoff, - text_cmd.filesize, - }); const dataoff = @intCast(u32, mem.alignForward(parser.end_pos.?, @sizeOf(u64))); + const datasize = 0x1000; const code_sig = macho.linkedit_data_command{ .cmd = macho.LC_CODE_SIGNATURE, .cmdsize = @sizeOf(macho.linkedit_data_command), .dataoff = dataoff, - .datasize = 0x1000, + .datasize = datasize, }; - const linkedit_seg = parser.load_commands.items[parser.linkedit_cmd_index.?].Segment.inner; const linkedit = macho.segment_command_64{ .cmd = linkedit_seg.cmd, .cmdsize = linkedit_seg.cmdsize, .segname = linkedit_seg.segname, .vmaddr = linkedit_seg.vmaddr, - .vmsize = mem.alignForwardGeneric(u64, linkedit_seg.vmsize + 0x1000, self.page_size), + .vmsize = mem.alignForwardGeneric(u64, linkedit_seg.vmsize + datasize, self.page_size), .fileoff = linkedit_seg.fileoff, - .filesize = linkedit_seg.filesize + (dataoff - parser.end_pos.?) + 0x1000, + .filesize = linkedit_seg.filesize + (dataoff - parser.end_pos.?) + datasize, .maxprot = linkedit_seg.maxprot, .initprot = linkedit_seg.initprot, .nsects = linkedit_seg.nsects, @@ -854,6 +849,20 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { try out_file.pwriteAll(mem.sliceAsBytes(&[_]macho.linkedit_data_command{code_sig}), parser.code_sig_cmd_offset.?); try out_file.pwriteAll(mem.sliceAsBytes(&[_]macho.segment_command_64{linkedit}), parser.linkedit_cmd_offset.?); try out_file.pwriteAll(mem.sliceAsBytes(&[_]macho.mach_header_64{header}), 0); + // Generate adhoc code signature + var signature = CodeSignature.init(self.base.allocator); + defer signature.deinit(); + try signature.calcAdhocSignatureFile( + out_file, + self.base.options.emit.?.sub_path, + text_cmd, + code_sig, + self.base.options.output_mode, + ); + var buffer = try self.base.allocator.alloc(u8, signature.size()); + defer self.base.allocator.free(buffer); + signature.write(buffer); + try out_file.pwriteAll(buffer, code_sig.dataoff); } } diff --git a/src/link/MachO/CodeSignature.zig b/src/link/MachO/CodeSignature.zig index 6262315eb8..1cef7803f5 100644 --- a/src/link/MachO/CodeSignature.zig +++ b/src/link/MachO/CodeSignature.zig @@ -2,6 +2,7 @@ const CodeSignature = @This(); const std = @import("std"); const assert = std.debug.assert; +const fs = std.fs; const log = std.log.scoped(.link); const macho = std.macho; const mem = std.mem; @@ -65,6 +66,82 @@ pub fn init(alloc: *Allocator) CodeSignature { }; } +pub fn calcAdhocSignatureFile( + self: *CodeSignature, + file: fs.File, + id: []const u8, + text_segment: macho.segment_command_64, + code_sig_cmd: macho.linkedit_data_command, + output_mode: std.builtin.OutputMode, +) !void { + const execSegBase: u64 = text_segment.fileoff; + const execSegLimit: u64 = text_segment.filesize; + const execSegFlags: u64 = if (output_mode == .Exe) macho.CS_EXECSEG_MAIN_BINARY else 0; + const file_size = code_sig_cmd.dataoff; + var cdir = CodeDirectory{ + .inner = .{ + .magic = macho.CSMAGIC_CODEDIRECTORY, + .length = @sizeOf(macho.CodeDirectory), + .version = macho.CS_SUPPORTSEXECSEG, + .flags = macho.CS_ADHOC, + .hashOffset = 0, + .identOffset = 0, + .nSpecialSlots = 0, + .nCodeSlots = 0, + .codeLimit = @intCast(u32, file_size), + .hashSize = hash_size, + .hashType = macho.CS_HASHTYPE_SHA256, + .platform = 0, + .pageSize = @truncate(u8, std.math.log2(page_size)), + .spare2 = 0, + .scatterOffset = 0, + .teamOffset = 0, + .spare3 = 0, + .codeLimit64 = 0, + .execSegBase = execSegBase, + .execSegLimit = execSegLimit, + .execSegFlags = execSegFlags, + }, + }; + + const total_pages = mem.alignForward(file_size, page_size) / page_size; + + var hash: [hash_size]u8 = undefined; + var buffer = try self.alloc.alloc(u8, page_size); + defer self.alloc.free(buffer); + + try cdir.data.ensureCapacity(self.alloc, total_pages * hash_size + id.len + 1); + + // 1. Save the identifier and update offsets + cdir.inner.identOffset = cdir.inner.length; + cdir.data.appendSliceAssumeCapacity(id); + cdir.data.appendAssumeCapacity(0); + + // 2. Calculate hash for each page (in file) and write it to the buffer + // TODO figure out how we can cache several hashes since we won't update + // every page during incremental linking + cdir.inner.hashOffset = cdir.inner.identOffset + @intCast(u32, id.len) + 1; + var i: usize = 0; + while (i < total_pages) : (i += 1) { + const fstart = i * page_size; + const fsize = if (fstart + page_size > file_size) file_size - fstart else page_size; + const len = try file.preadAll(buffer, fstart); + assert(fsize <= len); + + Sha256.hash(buffer[0..fsize], &hash, .{}); + + cdir.data.appendSliceAssumeCapacity(hash[0..]); + cdir.inner.nCodeSlots += 1; + } + + // 3. Update CodeDirectory length + cdir.inner.length += @intCast(u32, cdir.data.items.len); + + self.inner.length += @sizeOf(macho.BlobIndex) + cdir.size(); + self.inner.count = 1; + self.cdir = cdir; +} + pub fn calcAdhocSignature(self: *CodeSignature, bin_file: *const MachO) !void { const text_segment = bin_file.load_commands.items[bin_file.text_segment_cmd_index.?].Segment; const code_sig_cmd = bin_file.load_commands.items[bin_file.code_signature_cmd_index.?].LinkeditData; |
