authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-12-23 12:49:59+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-12-23 12:50:03+01:00
log550ebcce9abe9db9453509b38820756a1fff8391
tree41398a47cd5ea6a95f4bd4abdc5f0708b16ba525
parent4aa8462cc936820bc2c81ea1f3cfc613ff07a9f7

macho+zld: write code signature padding before commiting LCs

Otherwise, we were prematurely committing `__LINKEDIT` segment LC with outdated size (i.e., without code signature being taken into account). This would scaffold into strict validation failures by Apple tooling.

2 files changed, 47 insertions(+), 41 deletions(-)

src/link/MachO.zig+24-21
......@@ -558,6 +558,28 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
558558
559559 try self.writeLinkeditSegmentData();
560560
561 const target = self.base.options.target;
562 const requires_codesig = blk: {
563 if (self.base.options.entitlements) |_| break :blk true;
564 if (target.cpu.arch == .aarch64 and (target.os.tag == .macos or target.abi == .simulator))
565 break :blk true;
566 break :blk false;
567 };
568 var codesig: ?CodeSignature = if (requires_codesig) blk: {
569 // Preallocate space for the code signature.
570 // We need to do this at this stage so that we have the load commands with proper values
571 // written out to the file.
572 // The most important here is to have the correct vm and filesize of the __LINKEDIT segment
573 // where the code signature goes into.
574 var codesig = CodeSignature.init(self.page_size);
575 codesig.code_directory.ident = self.base.options.emit.?.sub_path;
576 if (self.base.options.entitlements) |path| {
577 try codesig.addEntitlements(arena, path);
578 }
579 try self.writeCodeSignaturePadding(&codesig);
580 break :blk codesig;
581 } else null;
582
561583 // Write load commands
562584 var lc_buffer = std.ArrayList(u8).init(arena);
563585 const lc_writer = lc_buffer.writer();
......@@ -606,28 +628,9 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
606628
607629 try load_commands.writeLoadDylibLCs(self.dylibs.items, self.referenced_dylibs.keys(), lc_writer);
608630
609 const target = self.base.options.target;
610 const requires_codesig = blk: {
611 if (self.base.options.entitlements) |_| break :blk true;
612 if (target.cpu.arch == .aarch64 and (target.os.tag == .macos or target.abi == .simulator))
613 break :blk true;
614 break :blk false;
615 };
616 var codesig: ?CodeSignature = if (requires_codesig) blk: {
617 // Preallocate space for the code signature.
618 // We need to do this at this stage so that we have the load commands with proper values
619 // written out to the file.
620 // The most important here is to have the correct vm and filesize of the __LINKEDIT segment
621 // where the code signature goes into.
622 var codesig = CodeSignature.init(self.page_size);
623 codesig.code_directory.ident = self.base.options.emit.?.sub_path;
624 if (self.base.options.entitlements) |path| {
625 try codesig.addEntitlements(arena, path);
626 }
627 try self.writeCodeSignaturePadding(&codesig);
631 if (requires_codesig) {
628632 try lc_writer.writeStruct(self.codesig_cmd);
629 break :blk codesig;
630 } else null;
633 }
631634
632635 try self.base.file.?.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64));
633636
src/link/MachO/zld.zig+23-20
......@@ -4100,6 +4100,27 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
41004100 }
41014101 }
41024102
4103 // Write code signature padding if required
4104 const requires_codesig = blk: {
4105 if (options.entitlements) |_| break :blk true;
4106 if (cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator)) break :blk true;
4107 break :blk false;
4108 };
4109 var codesig: ?CodeSignature = if (requires_codesig) blk: {
4110 // Preallocate space for the code signature.
4111 // We need to do this at this stage so that we have the load commands with proper values
4112 // written out to the file.
4113 // The most important here is to have the correct vm and filesize of the __LINKEDIT segment
4114 // where the code signature goes into.
4115 var codesig = CodeSignature.init(page_size);
4116 codesig.code_directory.ident = fs.path.basename(full_out_path);
4117 if (options.entitlements) |path| {
4118 try codesig.addEntitlements(arena, path);
4119 }
4120 try zld.writeCodeSignaturePadding(&codesig);
4121 break :blk codesig;
4122 } else null;
4123
41034124 // Write load commands
41044125 var lc_buffer = std.ArrayList(u8).init(arena);
41054126 const lc_writer = lc_buffer.writer();
......@@ -4142,29 +4163,11 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
41424163
41434164 try load_commands.writeLoadDylibLCs(zld.dylibs.items, zld.referenced_dylibs.keys(), lc_writer);
41444165
4145 const requires_codesig = blk: {
4146 if (options.entitlements) |_| break :blk true;
4147 if (cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator)) break :blk true;
4148 break :blk false;
4149 };
41504166 var codesig_cmd_offset: ?u32 = null;
4151 var codesig: ?CodeSignature = if (requires_codesig) blk: {
4152 // Preallocate space for the code signature.
4153 // We need to do this at this stage so that we have the load commands with proper values
4154 // written out to the file.
4155 // The most important here is to have the correct vm and filesize of the __LINKEDIT segment
4156 // where the code signature goes into.
4157 var codesig = CodeSignature.init(page_size);
4158 codesig.code_directory.ident = fs.path.basename(full_out_path);
4159 if (options.entitlements) |path| {
4160 try codesig.addEntitlements(gpa, path);
4161 }
4162 try zld.writeCodeSignaturePadding(&codesig);
4167 if (requires_codesig) {
41634168 codesig_cmd_offset = @sizeOf(macho.mach_header_64) + @intCast(u32, lc_buffer.items.len);
41644169 try lc_writer.writeStruct(zld.codesig_cmd);
4165 break :blk codesig;
4166 } else null;
4167 defer if (codesig) |*csig| csig.deinit(gpa);
4170 }
41684171
41694172 const ncmds = load_commands.calcNumOfLCs(lc_buffer.items);
41704173 try zld.file.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64));