| author | |
| committer | |
| log | c25b3593e726108cb7f208ef538df6979aeb41e1 |
| tree | 27f8d6d0e77f694fae18cb460c57cafdf2cb7e63 |
| parent | 545721ccd1e7297719fc53dfde99fa046fb3edef |
2 files changed, 95 insertions(+), 9 deletions(-)
src/link/MachO.zig+18-9| ... | @@ -812,28 +812,23 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -812,28 +812,23 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 812 | try parser.parseFile(out_file); | 812 | try parser.parseFile(out_file); |
| 813 | // Pad out space for code signature | 813 | // Pad out space for code signature |
| 814 | const text_cmd = parser.load_commands.items[parser.text_cmd_index.?].Segment.inner; | 814 | const text_cmd = parser.load_commands.items[parser.text_cmd_index.?].Segment.inner; |
| 815 | std.debug.print("end_pos={},text_fileoff={},text_filesize={}\n", .{ | ||
| 816 | parser.end_pos, | ||
| 817 | text_cmd.fileoff, | ||
| 818 | text_cmd.filesize, | ||
| 819 | }); | ||
| 820 | const dataoff = @intCast(u32, mem.alignForward(parser.end_pos.?, @sizeOf(u64))); | 815 | const dataoff = @intCast(u32, mem.alignForward(parser.end_pos.?, @sizeOf(u64))); |
| 816 | const datasize = 0x1000; | ||
| 821 | const code_sig = macho.linkedit_data_command{ | 817 | const code_sig = macho.linkedit_data_command{ |
| 822 | .cmd = macho.LC_CODE_SIGNATURE, | 818 | .cmd = macho.LC_CODE_SIGNATURE, |
| 823 | .cmdsize = @sizeOf(macho.linkedit_data_command), | 819 | .cmdsize = @sizeOf(macho.linkedit_data_command), |
| 824 | .dataoff = dataoff, | 820 | .dataoff = dataoff, |
| 825 | .datasize = 0x1000, | 821 | .datasize = datasize, |
| 826 | }; | 822 | }; |
| 827 | |||
| 828 | const linkedit_seg = parser.load_commands.items[parser.linkedit_cmd_index.?].Segment.inner; | 823 | const linkedit_seg = parser.load_commands.items[parser.linkedit_cmd_index.?].Segment.inner; |
| 829 | const linkedit = macho.segment_command_64{ | 824 | const linkedit = macho.segment_command_64{ |
| 830 | .cmd = linkedit_seg.cmd, | 825 | .cmd = linkedit_seg.cmd, |
| 831 | .cmdsize = linkedit_seg.cmdsize, | 826 | .cmdsize = linkedit_seg.cmdsize, |
| 832 | .segname = linkedit_seg.segname, | 827 | .segname = linkedit_seg.segname, |
| 833 | .vmaddr = linkedit_seg.vmaddr, | 828 | .vmaddr = linkedit_seg.vmaddr, |
| 834 | .vmsize = mem.alignForwardGeneric(u64, linkedit_seg.vmsize + 0x1000, self.page_size), | 829 | .vmsize = mem.alignForwardGeneric(u64, linkedit_seg.vmsize + datasize, self.page_size), |
| 835 | .fileoff = linkedit_seg.fileoff, | 830 | .fileoff = linkedit_seg.fileoff, |
| 836 | .filesize = linkedit_seg.filesize + (dataoff - parser.end_pos.?) + 0x1000, | 831 | .filesize = linkedit_seg.filesize + (dataoff - parser.end_pos.?) + datasize, |
| 837 | .maxprot = linkedit_seg.maxprot, | 832 | .maxprot = linkedit_seg.maxprot, |
| 838 | .initprot = linkedit_seg.initprot, | 833 | .initprot = linkedit_seg.initprot, |
| 839 | .nsects = linkedit_seg.nsects, | 834 | .nsects = linkedit_seg.nsects, |
| ... | @@ -854,6 +849,20 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -854,6 +849,20 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 854 | try out_file.pwriteAll(mem.sliceAsBytes(&[_]macho.linkedit_data_command{code_sig}), parser.code_sig_cmd_offset.?); | 849 | try out_file.pwriteAll(mem.sliceAsBytes(&[_]macho.linkedit_data_command{code_sig}), parser.code_sig_cmd_offset.?); |
| 855 | try out_file.pwriteAll(mem.sliceAsBytes(&[_]macho.segment_command_64{linkedit}), parser.linkedit_cmd_offset.?); | 850 | try out_file.pwriteAll(mem.sliceAsBytes(&[_]macho.segment_command_64{linkedit}), parser.linkedit_cmd_offset.?); |
| 856 | try out_file.pwriteAll(mem.sliceAsBytes(&[_]macho.mach_header_64{header}), 0); | 851 | try out_file.pwriteAll(mem.sliceAsBytes(&[_]macho.mach_header_64{header}), 0); |
| 852 | // Generate adhoc code signature | ||
| 853 | var signature = CodeSignature.init(self.base.allocator); | ||
| 854 | defer signature.deinit(); | ||
| 855 | try signature.calcAdhocSignatureFile( | ||
| 856 | out_file, | ||
| 857 | self.base.options.emit.?.sub_path, | ||
| 858 | text_cmd, | ||
| 859 | code_sig, | ||
| 860 | self.base.options.output_mode, | ||
| 861 | ); | ||
| 862 | var buffer = try self.base.allocator.alloc(u8, signature.size()); | ||
| 863 | defer self.base.allocator.free(buffer); | ||
| 864 | signature.write(buffer); | ||
| 865 | try out_file.pwriteAll(buffer, code_sig.dataoff); | ||
| 857 | } | 866 | } |
| 858 | } | 867 | } |
| 859 | 868 |
src/link/MachO/CodeSignature.zig+77| ... | @@ -2,6 +2,7 @@ const CodeSignature = @This(); | ... | @@ -2,6 +2,7 @@ const CodeSignature = @This(); |
| 2 | 2 | ||
| 3 | const std = @import("std"); | 3 | const std = @import("std"); |
| 4 | const assert = std.debug.assert; | 4 | const assert = std.debug.assert; |
| 5 | const fs = std.fs; | ||
| 5 | const log = std.log.scoped(.link); | 6 | const log = std.log.scoped(.link); |
| 6 | const macho = std.macho; | 7 | const macho = std.macho; |
| 7 | const mem = std.mem; | 8 | const mem = std.mem; |
| ... | @@ -65,6 +66,82 @@ pub fn init(alloc: *Allocator) CodeSignature { | ... | @@ -65,6 +66,82 @@ pub fn init(alloc: *Allocator) CodeSignature { |
| 65 | }; | 66 | }; |
| 66 | } | 67 | } |
| 67 | 68 | ||
| 69 | pub fn calcAdhocSignatureFile( | ||
| 70 | self: *CodeSignature, | ||
| 71 | file: fs.File, | ||
| 72 | id: []const u8, | ||
| 73 | text_segment: macho.segment_command_64, | ||
| 74 | code_sig_cmd: macho.linkedit_data_command, | ||
| 75 | output_mode: std.builtin.OutputMode, | ||
| 76 | ) !void { | ||
| 77 | const execSegBase: u64 = text_segment.fileoff; | ||
| 78 | const execSegLimit: u64 = text_segment.filesize; | ||
| 79 | const execSegFlags: u64 = if (output_mode == .Exe) macho.CS_EXECSEG_MAIN_BINARY else 0; | ||
| 80 | const file_size = code_sig_cmd.dataoff; | ||
| 81 | var cdir = CodeDirectory{ | ||
| 82 | .inner = .{ | ||
| 83 | .magic = macho.CSMAGIC_CODEDIRECTORY, | ||
| 84 | .length = @sizeOf(macho.CodeDirectory), | ||
| 85 | .version = macho.CS_SUPPORTSEXECSEG, | ||
| 86 | .flags = macho.CS_ADHOC, | ||
| 87 | .hashOffset = 0, | ||
| 88 | .identOffset = 0, | ||
| 89 | .nSpecialSlots = 0, | ||
| 90 | .nCodeSlots = 0, | ||
| 91 | .codeLimit = @intCast(u32, file_size), | ||
| 92 | .hashSize = hash_size, | ||
| 93 | .hashType = macho.CS_HASHTYPE_SHA256, | ||
| 94 | .platform = 0, | ||
| 95 | .pageSize = @truncate(u8, std.math.log2(page_size)), | ||
| 96 | .spare2 = 0, | ||
| 97 | .scatterOffset = 0, | ||
| 98 | .teamOffset = 0, | ||
| 99 | .spare3 = 0, | ||
| 100 | .codeLimit64 = 0, | ||
| 101 | .execSegBase = execSegBase, | ||
| 102 | .execSegLimit = execSegLimit, | ||
| 103 | .execSegFlags = execSegFlags, | ||
| 104 | }, | ||
| 105 | }; | ||
| 106 | |||
| 107 | const total_pages = mem.alignForward(file_size, page_size) / page_size; | ||
| 108 | |||
| 109 | var hash: [hash_size]u8 = undefined; | ||
| 110 | var buffer = try self.alloc.alloc(u8, page_size); | ||
| 111 | defer self.alloc.free(buffer); | ||
| 112 | |||
| 113 | try cdir.data.ensureCapacity(self.alloc, total_pages * hash_size + id.len + 1); | ||
| 114 | |||
| 115 | // 1. Save the identifier and update offsets | ||
| 116 | cdir.inner.identOffset = cdir.inner.length; | ||
| 117 | cdir.data.appendSliceAssumeCapacity(id); | ||
| 118 | cdir.data.appendAssumeCapacity(0); | ||
| 119 | |||
| 120 | // 2. Calculate hash for each page (in file) and write it to the buffer | ||
| 121 | // TODO figure out how we can cache several hashes since we won't update | ||
| 122 | // every page during incremental linking | ||
| 123 | cdir.inner.hashOffset = cdir.inner.identOffset + @intCast(u32, id.len) + 1; | ||
| 124 | var i: usize = 0; | ||
| 125 | while (i < total_pages) : (i += 1) { | ||
| 126 | const fstart = i * page_size; | ||
| 127 | const fsize = if (fstart + page_size > file_size) file_size - fstart else page_size; | ||
| 128 | const len = try file.preadAll(buffer, fstart); | ||
| 129 | assert(fsize <= len); | ||
| 130 | |||
| 131 | Sha256.hash(buffer[0..fsize], &hash, .{}); | ||
| 132 | |||
| 133 | cdir.data.appendSliceAssumeCapacity(hash[0..]); | ||
| 134 | cdir.inner.nCodeSlots += 1; | ||
| 135 | } | ||
| 136 | |||
| 137 | // 3. Update CodeDirectory length | ||
| 138 | cdir.inner.length += @intCast(u32, cdir.data.items.len); | ||
| 139 | |||
| 140 | self.inner.length += @sizeOf(macho.BlobIndex) + cdir.size(); | ||
| 141 | self.inner.count = 1; | ||
| 142 | self.cdir = cdir; | ||
| 143 | } | ||
| 144 | |||
| 68 | pub fn calcAdhocSignature(self: *CodeSignature, bin_file: *const MachO) !void { | 145 | pub fn calcAdhocSignature(self: *CodeSignature, bin_file: *const MachO) !void { |
| 69 | const text_segment = bin_file.load_commands.items[bin_file.text_segment_cmd_index.?].Segment; | 146 | const text_segment = bin_file.load_commands.items[bin_file.text_segment_cmd_index.?].Segment; |
| 70 | const code_sig_cmd = bin_file.load_commands.items[bin_file.code_signature_cmd_index.?].LinkeditData; | 147 | const code_sig_cmd = bin_file.load_commands.items[bin_file.code_signature_cmd_index.?].LinkeditData; |