authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-01 17:49:38+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-01 18:03:04+01:00
logabb697e751cb0febf4e5e26f0190c01d7c5fd922
tree90e863418f37e9333b11cc9bdd788b36f4db06ba
parent1f7fb560ab5a3a82af24ab7abe11dce8f877c7fe

macho: unify code signature between stage1 and stage2


3 files changed, 28 insertions(+), 98 deletions(-)

src/link/MachO.zig+11-5
...@@ -773,7 +773,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -773,7 +773,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
773 var signature = CodeSignature.init(self.base.allocator);773 var signature = CodeSignature.init(self.base.allocator);
774 defer signature.deinit();774 defer signature.deinit();
775 const emit = self.base.options.emit.?;775 const emit = self.base.options.emit.?;
776 try signature.calcAdhocSignatureFile(776 try signature.calcAdhocSignature(
777 out_file,777 out_file,
778 emit.sub_path,778 emit.sub_path,
779 text_cmd,779 text_cmd,
...@@ -1741,15 +1741,21 @@ fn writeCodeSignaturePadding(self: *MachO) !void {...@@ -1741,15 +1741,21 @@ fn writeCodeSignaturePadding(self: *MachO) !void {
1741}1741}
17421742
1743fn writeCodeSignature(self: *MachO) !void {1743fn writeCodeSignature(self: *MachO) !void {
1744 const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;1744 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1745 const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;
1746
1745 var code_sig = CodeSignature.init(self.base.allocator);1747 var code_sig = CodeSignature.init(self.base.allocator);
1746 defer code_sig.deinit();1748 defer code_sig.deinit();
17471749 try code_sig.calcAdhocSignature(
1748 try code_sig.calcAdhocSignature(self);1750 self.base.file.?,
1751 self.base.options.emit.?.sub_path,
1752 text_segment.inner,
1753 code_sig_cmd,
1754 self.base.options.output_mode,
1755 );
17491756
1750 var buffer = try self.base.allocator.alloc(u8, code_sig.size());1757 var buffer = try self.base.allocator.alloc(u8, code_sig.size());
1751 defer self.base.allocator.free(buffer);1758 defer self.base.allocator.free(buffer);
1752
1753 code_sig.write(buffer);1759 code_sig.write(buffer);
17541760
1755 log.debug("writing code signature from 0x{x} to 0x{x}\n", .{ code_sig_cmd.dataoff, code_sig_cmd.dataoff + buffer.len });1761 log.debug("writing code signature from 0x{x} to 0x{x}\n", .{ code_sig_cmd.dataoff, code_sig_cmd.dataoff + buffer.len });
src/link/MachO/CodeSignature.zig+8-86
...@@ -10,8 +10,6 @@ const testing = std.testing;...@@ -10,8 +10,6 @@ const testing = std.testing;
10const Allocator = mem.Allocator;10const Allocator = mem.Allocator;
11const Sha256 = std.crypto.hash.sha2.Sha256;11const Sha256 = std.crypto.hash.sha2.Sha256;
1212
13const MachO = @import("../MachO.zig");
14
15const hash_size: u8 = 32;13const hash_size: u8 = 32;
16const page_size: u16 = 0x1000;14const page_size: u16 = 0x1000;
1715
...@@ -52,7 +50,7 @@ const CodeDirectory = struct {...@@ -52,7 +50,7 @@ const CodeDirectory = struct {
52 }50 }
53};51};
5452
55alloc: *Allocator,53allocator: *Allocator,
56inner: macho.SuperBlob = .{54inner: macho.SuperBlob = .{
57 .magic = macho.CSMAGIC_EMBEDDED_SIGNATURE,55 .magic = macho.CSMAGIC_EMBEDDED_SIGNATURE,
58 .length = @sizeOf(macho.SuperBlob),56 .length = @sizeOf(macho.SuperBlob),
...@@ -60,13 +58,11 @@ inner: macho.SuperBlob = .{...@@ -60,13 +58,11 @@ inner: macho.SuperBlob = .{
60},58},
61cdir: ?CodeDirectory = null,59cdir: ?CodeDirectory = null,
6260
63pub fn init(alloc: *Allocator) CodeSignature {61pub fn init(allocator: *Allocator) CodeSignature {
64 return .{62 return .{ .allocator = allocator };
65 .alloc = alloc,
66 };
67}63}
6864
69pub fn calcAdhocSignatureFile(65pub fn calcAdhocSignature(
70 self: *CodeSignature,66 self: *CodeSignature,
71 file: fs.File,67 file: fs.File,
72 id: []const u8,68 id: []const u8,
...@@ -107,10 +103,10 @@ pub fn calcAdhocSignatureFile(...@@ -107,10 +103,10 @@ pub fn calcAdhocSignatureFile(
107 const total_pages = mem.alignForward(file_size, page_size) / page_size;103 const total_pages = mem.alignForward(file_size, page_size) / page_size;
108104
109 var hash: [hash_size]u8 = undefined;105 var hash: [hash_size]u8 = undefined;
110 var buffer = try self.alloc.alloc(u8, page_size);106 var buffer = try self.allocator.alloc(u8, page_size);
111 defer self.alloc.free(buffer);107 defer self.allocator.free(buffer);
112108
113 try cdir.data.ensureCapacity(self.alloc, total_pages * hash_size + id.len + 1);109 try cdir.data.ensureCapacity(self.allocator, total_pages * hash_size + id.len + 1);
114110
115 // 1. Save the identifier and update offsets111 // 1. Save the identifier and update offsets
116 cdir.inner.identOffset = cdir.inner.length;112 cdir.inner.identOffset = cdir.inner.length;
...@@ -142,80 +138,6 @@ pub fn calcAdhocSignatureFile(...@@ -142,80 +138,6 @@ pub fn calcAdhocSignatureFile(
142 self.cdir = cdir;138 self.cdir = cdir;
143}139}
144140
145pub fn calcAdhocSignature(self: *CodeSignature, bin_file: *const MachO) !void {
146 const text_segment = bin_file.load_commands.items[bin_file.text_segment_cmd_index.?].Segment;
147 const code_sig_cmd = bin_file.load_commands.items[bin_file.code_signature_cmd_index.?].LinkeditData;
148
149 const execSegBase: u64 = text_segment.inner.fileoff;
150 const execSegLimit: u64 = text_segment.inner.filesize;
151 const execSegFlags: u64 = if (bin_file.base.options.output_mode == .Exe) macho.CS_EXECSEG_MAIN_BINARY else 0;
152 const file_size = code_sig_cmd.dataoff;
153 var cdir = CodeDirectory{
154 .inner = .{
155 .magic = macho.CSMAGIC_CODEDIRECTORY,
156 .length = @sizeOf(macho.CodeDirectory),
157 .version = macho.CS_SUPPORTSEXECSEG,
158 .flags = macho.CS_ADHOC,
159 .hashOffset = 0,
160 .identOffset = 0,
161 .nSpecialSlots = 0,
162 .nCodeSlots = 0,
163 .codeLimit = @intCast(u32, file_size),
164 .hashSize = hash_size,
165 .hashType = macho.CS_HASHTYPE_SHA256,
166 .platform = 0,
167 .pageSize = @truncate(u8, std.math.log2(page_size)),
168 .spare2 = 0,
169 .scatterOffset = 0,
170 .teamOffset = 0,
171 .spare3 = 0,
172 .codeLimit64 = 0,
173 .execSegBase = execSegBase,
174 .execSegLimit = execSegLimit,
175 .execSegFlags = execSegFlags,
176 },
177 };
178
179 const total_pages = mem.alignForward(file_size, page_size) / page_size;
180
181 var hash: [hash_size]u8 = undefined;
182 var buffer = try bin_file.base.allocator.alloc(u8, page_size);
183 defer bin_file.base.allocator.free(buffer);
184 const macho_file = bin_file.base.file.?;
185
186 const id = bin_file.base.options.emit.?.sub_path;
187 try cdir.data.ensureCapacity(self.alloc, total_pages * hash_size + id.len + 1);
188
189 // 1. Save the identifier and update offsets
190 cdir.inner.identOffset = cdir.inner.length;
191 cdir.data.appendSliceAssumeCapacity(id);
192 cdir.data.appendAssumeCapacity(0);
193
194 // 2. Calculate hash for each page (in file) and write it to the buffer
195 // TODO figure out how we can cache several hashes since we won't update
196 // every page during incremental linking
197 cdir.inner.hashOffset = cdir.inner.identOffset + @intCast(u32, id.len) + 1;
198 var i: usize = 0;
199 while (i < total_pages) : (i += 1) {
200 const fstart = i * page_size;
201 const fsize = if (fstart + page_size > file_size) file_size - fstart else page_size;
202 const len = try macho_file.preadAll(buffer, fstart);
203 assert(fsize <= len);
204
205 Sha256.hash(buffer[0..fsize], &hash, .{});
206
207 cdir.data.appendSliceAssumeCapacity(hash[0..]);
208 cdir.inner.nCodeSlots += 1;
209 }
210
211 // 3. Update CodeDirectory length
212 cdir.inner.length += @intCast(u32, cdir.data.items.len);
213
214 self.inner.length += @sizeOf(macho.BlobIndex) + cdir.size();
215 self.inner.count = 1;
216 self.cdir = cdir;
217}
218
219pub fn size(self: CodeSignature) u32 {141pub fn size(self: CodeSignature) u32 {
220 return self.inner.length;142 return self.inner.length;
221}143}
...@@ -230,7 +152,7 @@ pub fn write(self: CodeSignature, buffer: []u8) void {...@@ -230,7 +152,7 @@ pub fn write(self: CodeSignature, buffer: []u8) void {
230152
231pub fn deinit(self: *CodeSignature) void {153pub fn deinit(self: *CodeSignature) void {
232 if (self.cdir) |*cdir| {154 if (self.cdir) |*cdir| {
233 cdir.data.deinit(self.alloc);155 cdir.data.deinit(self.allocator);
234 }156 }
235}157}
236158
src/link/MachO/Parser.zig+9-7
...@@ -18,9 +18,9 @@ header: ?macho.mach_header_64 = null,...@@ -18,9 +18,9 @@ header: ?macho.mach_header_64 = null,
18/// Load commands18/// Load commands
19load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},19load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
2020
21text_cmd_index: ?usize = null,21text_cmd_index: ?u16 = null,
2222
23linkedit_cmd_index: ?usize = null,23linkedit_cmd_index: ?u16 = null,
24linkedit_cmd_offset: ?u64 = null,24linkedit_cmd_offset: ?u64 = null,
2525
26code_sig_cmd_offset: ?u64 = null,26code_sig_cmd_offset: ?u64 = null,
...@@ -28,9 +28,7 @@ code_sig_cmd_offset: ?u64 = null,...@@ -28,9 +28,7 @@ code_sig_cmd_offset: ?u64 = null,
28end_pos: ?u64 = null,28end_pos: ?u64 = null,
2929
30pub fn init(allocator: *Allocator) Parser {30pub fn init(allocator: *Allocator) Parser {
31 return .{31 return .{ .allocator = allocator };
32 .allocator = allocator,
33 };
34}32}
3533
36pub fn parse(self: *Parser, reader: anytype) !void {34pub fn parse(self: *Parser, reader: anytype) !void {
...@@ -46,10 +44,10 @@ pub fn parse(self: *Parser, reader: anytype) !void {...@@ -46,10 +44,10 @@ pub fn parse(self: *Parser, reader: anytype) !void {
46 switch (cmd.cmd()) {44 switch (cmd.cmd()) {
47 macho.LC_SEGMENT_64 => {45 macho.LC_SEGMENT_64 => {
48 const x = cmd.Segment;46 const x = cmd.Segment;
49 if (mem.eql(u8, mem.trimRight(u8, x.inner.segname[0..], &[_]u8{0}), "__LINKEDIT")) {47 if (mem.eql(u8, parseName(&x.inner.segname), "__LINKEDIT")) {
50 self.linkedit_cmd_index = i;48 self.linkedit_cmd_index = i;
51 self.linkedit_cmd_offset = off;49 self.linkedit_cmd_offset = off;
52 } else if (mem.eql(u8, mem.trimRight(u8, x.inner.segname[0..], &[_]u8{0}), "__TEXT")) {50 } else if (mem.eql(u8, parseName(&x.inner.segname), "__TEXT")) {
53 self.text_cmd_index = i;51 self.text_cmd_index = i;
54 }52 }
55 },53 },
...@@ -78,3 +76,7 @@ pub fn deinit(self: *Parser) void {...@@ -78,3 +76,7 @@ pub fn deinit(self: *Parser) void {
78 }76 }
79 self.load_commands.deinit(self.allocator);77 self.load_commands.deinit(self.allocator);
80}78}
79
80fn parseName(name: *const [16]u8) []const u8 {
81 return mem.trimRight(u8, name.*[0..], &[_]u8{0});
82}