authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-28 14:51:31+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-01 10:49:31+01:00
logc25b3593e726108cb7f208ef538df6979aeb41e1
tree27f8d6d0e77f694fae18cb460c57cafdf2cb7e63
parent545721ccd1e7297719fc53dfde99fa046fb3edef

lld: add code signature to lld output


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 signature813 // 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 }
859868
src/link/MachO/CodeSignature.zig+77
...@@ -2,6 +2,7 @@ const CodeSignature = @This();...@@ -2,6 +2,7 @@ const CodeSignature = @This();
22
3const std = @import("std");3const std = @import("std");
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const fs = std.fs;
5const log = std.log.scoped(.link);6const log = std.log.scoped(.link);
6const macho = std.macho;7const macho = std.macho;
7const mem = std.mem;8const 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}
6768
69pub 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
68pub fn calcAdhocSignature(self: *CodeSignature, bin_file: *const MachO) !void {145pub 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;