Commit 550ebcce9a

Jakub Konka <kubkon@jakubkonka.com>
2022-12-23 12:49:59
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.
1 parent 4aa8462
Changed files (2)
src
link
src/link/MachO/zld.zig
@@ -4100,6 +4100,27 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
             }
         }
 
+        // Write code signature padding if required
+        const requires_codesig = blk: {
+            if (options.entitlements) |_| break :blk true;
+            if (cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator)) break :blk true;
+            break :blk false;
+        };
+        var codesig: ?CodeSignature = if (requires_codesig) blk: {
+            // Preallocate space for the code signature.
+            // We need to do this at this stage so that we have the load commands with proper values
+            // written out to the file.
+            // The most important here is to have the correct vm and filesize of the __LINKEDIT segment
+            // where the code signature goes into.
+            var codesig = CodeSignature.init(page_size);
+            codesig.code_directory.ident = fs.path.basename(full_out_path);
+            if (options.entitlements) |path| {
+                try codesig.addEntitlements(arena, path);
+            }
+            try zld.writeCodeSignaturePadding(&codesig);
+            break :blk codesig;
+        } else null;
+
         // Write load commands
         var lc_buffer = std.ArrayList(u8).init(arena);
         const lc_writer = lc_buffer.writer();
@@ -4142,29 +4163,11 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
 
         try load_commands.writeLoadDylibLCs(zld.dylibs.items, zld.referenced_dylibs.keys(), lc_writer);
 
-        const requires_codesig = blk: {
-            if (options.entitlements) |_| break :blk true;
-            if (cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator)) break :blk true;
-            break :blk false;
-        };
         var codesig_cmd_offset: ?u32 = null;
-        var codesig: ?CodeSignature = if (requires_codesig) blk: {
-            // Preallocate space for the code signature.
-            // We need to do this at this stage so that we have the load commands with proper values
-            // written out to the file.
-            // The most important here is to have the correct vm and filesize of the __LINKEDIT segment
-            // where the code signature goes into.
-            var codesig = CodeSignature.init(page_size);
-            codesig.code_directory.ident = fs.path.basename(full_out_path);
-            if (options.entitlements) |path| {
-                try codesig.addEntitlements(gpa, path);
-            }
-            try zld.writeCodeSignaturePadding(&codesig);
+        if (requires_codesig) {
             codesig_cmd_offset = @sizeOf(macho.mach_header_64) + @intCast(u32, lc_buffer.items.len);
             try lc_writer.writeStruct(zld.codesig_cmd);
-            break :blk codesig;
-        } else null;
-        defer if (codesig) |*csig| csig.deinit(gpa);
+        }
 
         const ncmds = load_commands.calcNumOfLCs(lc_buffer.items);
         try zld.file.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64));
src/link/MachO.zig
@@ -558,6 +558,28 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
 
     try self.writeLinkeditSegmentData();
 
+    const target = self.base.options.target;
+    const requires_codesig = blk: {
+        if (self.base.options.entitlements) |_| break :blk true;
+        if (target.cpu.arch == .aarch64 and (target.os.tag == .macos or target.abi == .simulator))
+            break :blk true;
+        break :blk false;
+    };
+    var codesig: ?CodeSignature = if (requires_codesig) blk: {
+        // Preallocate space for the code signature.
+        // We need to do this at this stage so that we have the load commands with proper values
+        // written out to the file.
+        // The most important here is to have the correct vm and filesize of the __LINKEDIT segment
+        // where the code signature goes into.
+        var codesig = CodeSignature.init(self.page_size);
+        codesig.code_directory.ident = self.base.options.emit.?.sub_path;
+        if (self.base.options.entitlements) |path| {
+            try codesig.addEntitlements(arena, path);
+        }
+        try self.writeCodeSignaturePadding(&codesig);
+        break :blk codesig;
+    } else null;
+
     // Write load commands
     var lc_buffer = std.ArrayList(u8).init(arena);
     const lc_writer = lc_buffer.writer();
@@ -606,28 +628,9 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
 
     try load_commands.writeLoadDylibLCs(self.dylibs.items, self.referenced_dylibs.keys(), lc_writer);
 
-    const target = self.base.options.target;
-    const requires_codesig = blk: {
-        if (self.base.options.entitlements) |_| break :blk true;
-        if (target.cpu.arch == .aarch64 and (target.os.tag == .macos or target.abi == .simulator))
-            break :blk true;
-        break :blk false;
-    };
-    var codesig: ?CodeSignature = if (requires_codesig) blk: {
-        // Preallocate space for the code signature.
-        // We need to do this at this stage so that we have the load commands with proper values
-        // written out to the file.
-        // The most important here is to have the correct vm and filesize of the __LINKEDIT segment
-        // where the code signature goes into.
-        var codesig = CodeSignature.init(self.page_size);
-        codesig.code_directory.ident = self.base.options.emit.?.sub_path;
-        if (self.base.options.entitlements) |path| {
-            try codesig.addEntitlements(arena, path);
-        }
-        try self.writeCodeSignaturePadding(&codesig);
+    if (requires_codesig) {
         try lc_writer.writeStruct(self.codesig_cmd);
-        break :blk codesig;
-    } else null;
+    }
 
     try self.base.file.?.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64));