| ... | ... | @@ -2,6 +2,7 @@ const CodeSignature = @This(); |
| 2 | 2 | |
| 3 | 3 | const std = @import("std"); |
| 4 | 4 | const assert = std.debug.assert; |
| 5 | const fs = std.fs; |
| 5 | 6 | const log = std.log.scoped(.link); |
| 6 | 7 | const macho = std.macho; |
| 7 | 8 | const mem = std.mem; |
| ... | ... | @@ -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 | 145 | pub fn calcAdhocSignature(self: *CodeSignature, bin_file: *const MachO) !void { |
| 69 | 146 | const text_segment = bin_file.load_commands.items[bin_file.text_segment_cmd_index.?].Segment; |
| 70 | 147 | const code_sig_cmd = bin_file.load_commands.items[bin_file.code_signature_cmd_index.?].LinkeditData; |