diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2023-08-31 07:50:29 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-08-31 07:50:29 +0200 |
| commit | f4c9e19bc3213c2bc7e03d7b06d7129882f39f6c (patch) | |
| tree | 79d343002bb63a44f8ab0dbac0c9f4ec54078c3a /src/link/MachO/CodeSignature.zig | |
| parent | e2ff486de5f3aceb21730e1feabbaf9b03432660 (diff) | |
| parent | 19a1332ca140274d03e57d31fda7748a8a3641ba (diff) | |
| download | zig-f4c9e19bc3213c2bc7e03d7b06d7129882f39f6c.tar.gz zig-f4c9e19bc3213c2bc7e03d7b06d7129882f39f6c.zip | |
Merge pull request #17020 from ziglang/macho-versions
macho: big-ish refactor and report errors to the user using Zig's API
Diffstat (limited to 'src/link/MachO/CodeSignature.zig')
| -rw-r--r-- | src/link/MachO/CodeSignature.zig | 364 |
1 files changed, 182 insertions, 182 deletions
diff --git a/src/link/MachO/CodeSignature.zig b/src/link/MachO/CodeSignature.zig index f527ca3581..973d9a2591 100644 --- a/src/link/MachO/CodeSignature.zig +++ b/src/link/MachO/CodeSignature.zig @@ -1,17 +1,175 @@ -const CodeSignature = @This(); +page_size: u16, +code_directory: CodeDirectory, +requirements: ?Requirements = null, +entitlements: ?Entitlements = null, +signature: ?Signature = null, -const std = @import("std"); -const assert = std.debug.assert; -const fs = std.fs; -const log = std.log.scoped(.link); -const macho = std.macho; -const mem = std.mem; -const testing = std.testing; +pub fn init(page_size: u16) CodeSignature { + return .{ + .page_size = page_size, + .code_directory = CodeDirectory.init(page_size), + }; +} -const Allocator = mem.Allocator; -const Compilation = @import("../../Compilation.zig"); -const Hasher = @import("hasher.zig").ParallelHasher; -const Sha256 = std.crypto.hash.sha2.Sha256; +pub fn deinit(self: *CodeSignature, allocator: Allocator) void { + self.code_directory.deinit(allocator); + if (self.requirements) |*req| { + req.deinit(allocator); + } + if (self.entitlements) |*ents| { + ents.deinit(allocator); + } + if (self.signature) |*sig| { + sig.deinit(allocator); + } +} + +pub fn addEntitlements(self: *CodeSignature, allocator: Allocator, path: []const u8) !void { + const file = try fs.cwd().openFile(path, .{}); + defer file.close(); + const inner = try file.readToEndAlloc(allocator, std.math.maxInt(u32)); + self.entitlements = .{ .inner = inner }; +} + +pub const WriteOpts = struct { + file: fs.File, + exec_seg_base: u64, + exec_seg_limit: u64, + file_size: u32, + output_mode: std.builtin.OutputMode, +}; + +pub fn writeAdhocSignature( + self: *CodeSignature, + comp: *const Compilation, + opts: WriteOpts, + writer: anytype, +) !void { + const gpa = comp.gpa; + + var header: macho.SuperBlob = .{ + .magic = macho.CSMAGIC_EMBEDDED_SIGNATURE, + .length = @sizeOf(macho.SuperBlob), + .count = 0, + }; + + var blobs = std.ArrayList(Blob).init(gpa); + defer blobs.deinit(); + + self.code_directory.inner.execSegBase = opts.exec_seg_base; + self.code_directory.inner.execSegLimit = opts.exec_seg_limit; + self.code_directory.inner.execSegFlags = if (opts.output_mode == .Exe) macho.CS_EXECSEG_MAIN_BINARY else 0; + self.code_directory.inner.codeLimit = opts.file_size; + + const total_pages = @as(u32, @intCast(mem.alignForward(usize, opts.file_size, self.page_size) / self.page_size)); + + try self.code_directory.code_slots.ensureTotalCapacityPrecise(gpa, total_pages); + self.code_directory.code_slots.items.len = total_pages; + self.code_directory.inner.nCodeSlots = total_pages; + + // Calculate hash for each page (in file) and write it to the buffer + var hasher = Hasher(Sha256){ .allocator = gpa, .thread_pool = comp.thread_pool }; + try hasher.hash(opts.file, self.code_directory.code_slots.items, .{ + .chunk_size = self.page_size, + .max_file_size = opts.file_size, + }); + + try blobs.append(.{ .code_directory = &self.code_directory }); + header.length += @sizeOf(macho.BlobIndex); + header.count += 1; + + var hash: [hash_size]u8 = undefined; + + if (self.requirements) |*req| { + var buf = std.ArrayList(u8).init(gpa); + defer buf.deinit(); + try req.write(buf.writer()); + Sha256.hash(buf.items, &hash, .{}); + self.code_directory.addSpecialHash(req.slotType(), hash); + + try blobs.append(.{ .requirements = req }); + header.count += 1; + header.length += @sizeOf(macho.BlobIndex) + req.size(); + } + + if (self.entitlements) |*ents| { + var buf = std.ArrayList(u8).init(gpa); + defer buf.deinit(); + try ents.write(buf.writer()); + Sha256.hash(buf.items, &hash, .{}); + self.code_directory.addSpecialHash(ents.slotType(), hash); + + try blobs.append(.{ .entitlements = ents }); + header.count += 1; + header.length += @sizeOf(macho.BlobIndex) + ents.size(); + } + + if (self.signature) |*sig| { + try blobs.append(.{ .signature = sig }); + header.count += 1; + header.length += @sizeOf(macho.BlobIndex) + sig.size(); + } + + self.code_directory.inner.hashOffset = + @sizeOf(macho.CodeDirectory) + @as(u32, @intCast(self.code_directory.ident.len + 1 + self.code_directory.inner.nSpecialSlots * hash_size)); + self.code_directory.inner.length = self.code_directory.size(); + header.length += self.code_directory.size(); + + try writer.writeIntBig(u32, header.magic); + try writer.writeIntBig(u32, header.length); + try writer.writeIntBig(u32, header.count); + + var offset: u32 = @sizeOf(macho.SuperBlob) + @sizeOf(macho.BlobIndex) * @as(u32, @intCast(blobs.items.len)); + for (blobs.items) |blob| { + try writer.writeIntBig(u32, blob.slotType()); + try writer.writeIntBig(u32, offset); + offset += blob.size(); + } + + for (blobs.items) |blob| { + try blob.write(writer); + } +} + +pub fn size(self: CodeSignature) u32 { + var ssize: u32 = @sizeOf(macho.SuperBlob) + @sizeOf(macho.BlobIndex) + self.code_directory.size(); + if (self.requirements) |req| { + ssize += @sizeOf(macho.BlobIndex) + req.size(); + } + if (self.entitlements) |ent| { + ssize += @sizeOf(macho.BlobIndex) + ent.size(); + } + if (self.signature) |sig| { + ssize += @sizeOf(macho.BlobIndex) + sig.size(); + } + return ssize; +} + +pub fn estimateSize(self: CodeSignature, file_size: u64) u32 { + var ssize: u64 = @sizeOf(macho.SuperBlob) + @sizeOf(macho.BlobIndex) + self.code_directory.size(); + // Approx code slots + const total_pages = mem.alignForward(u64, file_size, self.page_size) / self.page_size; + ssize += total_pages * hash_size; + var n_special_slots: u32 = 0; + if (self.requirements) |req| { + ssize += @sizeOf(macho.BlobIndex) + req.size(); + n_special_slots = @max(n_special_slots, req.slotType()); + } + if (self.entitlements) |ent| { + ssize += @sizeOf(macho.BlobIndex) + ent.size() + hash_size; + n_special_slots = @max(n_special_slots, ent.slotType()); + } + if (self.signature) |sig| { + ssize += @sizeOf(macho.BlobIndex) + sig.size(); + } + ssize += n_special_slots * hash_size; + return @as(u32, @intCast(mem.alignForward(u64, ssize, @sizeOf(u64)))); +} + +pub fn clear(self: *CodeSignature, allocator: Allocator) void { + self.code_directory.deinit(allocator); + self.code_directory = CodeDirectory.init(self.page_size); +} const hash_size = Sha256.digest_length; @@ -218,175 +376,17 @@ const Signature = struct { } }; -page_size: u16, -code_directory: CodeDirectory, -requirements: ?Requirements = null, -entitlements: ?Entitlements = null, -signature: ?Signature = null, - -pub fn init(page_size: u16) CodeSignature { - return .{ - .page_size = page_size, - .code_directory = CodeDirectory.init(page_size), - }; -} - -pub fn deinit(self: *CodeSignature, allocator: Allocator) void { - self.code_directory.deinit(allocator); - if (self.requirements) |*req| { - req.deinit(allocator); - } - if (self.entitlements) |*ents| { - ents.deinit(allocator); - } - if (self.signature) |*sig| { - sig.deinit(allocator); - } -} - -pub fn addEntitlements(self: *CodeSignature, allocator: Allocator, path: []const u8) !void { - const file = try fs.cwd().openFile(path, .{}); - defer file.close(); - const inner = try file.readToEndAlloc(allocator, std.math.maxInt(u32)); - self.entitlements = .{ .inner = inner }; -} - -pub const WriteOpts = struct { - file: fs.File, - exec_seg_base: u64, - exec_seg_limit: u64, - file_size: u32, - output_mode: std.builtin.OutputMode, -}; - -pub fn writeAdhocSignature( - self: *CodeSignature, - comp: *const Compilation, - opts: WriteOpts, - writer: anytype, -) !void { - const gpa = comp.gpa; - - var header: macho.SuperBlob = .{ - .magic = macho.CSMAGIC_EMBEDDED_SIGNATURE, - .length = @sizeOf(macho.SuperBlob), - .count = 0, - }; - - var blobs = std.ArrayList(Blob).init(gpa); - defer blobs.deinit(); - - self.code_directory.inner.execSegBase = opts.exec_seg_base; - self.code_directory.inner.execSegLimit = opts.exec_seg_limit; - self.code_directory.inner.execSegFlags = if (opts.output_mode == .Exe) macho.CS_EXECSEG_MAIN_BINARY else 0; - self.code_directory.inner.codeLimit = opts.file_size; - - const total_pages = @as(u32, @intCast(mem.alignForward(usize, opts.file_size, self.page_size) / self.page_size)); - - try self.code_directory.code_slots.ensureTotalCapacityPrecise(gpa, total_pages); - self.code_directory.code_slots.items.len = total_pages; - self.code_directory.inner.nCodeSlots = total_pages; - - // Calculate hash for each page (in file) and write it to the buffer - var hasher = Hasher(Sha256){ .allocator = gpa, .thread_pool = comp.thread_pool }; - try hasher.hash(opts.file, self.code_directory.code_slots.items, .{ - .chunk_size = self.page_size, - .max_file_size = opts.file_size, - }); - - try blobs.append(.{ .code_directory = &self.code_directory }); - header.length += @sizeOf(macho.BlobIndex); - header.count += 1; - - var hash: [hash_size]u8 = undefined; - - if (self.requirements) |*req| { - var buf = std.ArrayList(u8).init(gpa); - defer buf.deinit(); - try req.write(buf.writer()); - Sha256.hash(buf.items, &hash, .{}); - self.code_directory.addSpecialHash(req.slotType(), hash); - - try blobs.append(.{ .requirements = req }); - header.count += 1; - header.length += @sizeOf(macho.BlobIndex) + req.size(); - } - - if (self.entitlements) |*ents| { - var buf = std.ArrayList(u8).init(gpa); - defer buf.deinit(); - try ents.write(buf.writer()); - Sha256.hash(buf.items, &hash, .{}); - self.code_directory.addSpecialHash(ents.slotType(), hash); - - try blobs.append(.{ .entitlements = ents }); - header.count += 1; - header.length += @sizeOf(macho.BlobIndex) + ents.size(); - } - - if (self.signature) |*sig| { - try blobs.append(.{ .signature = sig }); - header.count += 1; - header.length += @sizeOf(macho.BlobIndex) + sig.size(); - } - - self.code_directory.inner.hashOffset = - @sizeOf(macho.CodeDirectory) + @as(u32, @intCast(self.code_directory.ident.len + 1 + self.code_directory.inner.nSpecialSlots * hash_size)); - self.code_directory.inner.length = self.code_directory.size(); - header.length += self.code_directory.size(); - - try writer.writeIntBig(u32, header.magic); - try writer.writeIntBig(u32, header.length); - try writer.writeIntBig(u32, header.count); - - var offset: u32 = @sizeOf(macho.SuperBlob) + @sizeOf(macho.BlobIndex) * @as(u32, @intCast(blobs.items.len)); - for (blobs.items) |blob| { - try writer.writeIntBig(u32, blob.slotType()); - try writer.writeIntBig(u32, offset); - offset += blob.size(); - } - - for (blobs.items) |blob| { - try blob.write(writer); - } -} - -pub fn size(self: CodeSignature) u32 { - var ssize: u32 = @sizeOf(macho.SuperBlob) + @sizeOf(macho.BlobIndex) + self.code_directory.size(); - if (self.requirements) |req| { - ssize += @sizeOf(macho.BlobIndex) + req.size(); - } - if (self.entitlements) |ent| { - ssize += @sizeOf(macho.BlobIndex) + ent.size(); - } - if (self.signature) |sig| { - ssize += @sizeOf(macho.BlobIndex) + sig.size(); - } - return ssize; -} +const CodeSignature = @This(); -pub fn estimateSize(self: CodeSignature, file_size: u64) u32 { - var ssize: u64 = @sizeOf(macho.SuperBlob) + @sizeOf(macho.BlobIndex) + self.code_directory.size(); - // Approx code slots - const total_pages = mem.alignForward(u64, file_size, self.page_size) / self.page_size; - ssize += total_pages * hash_size; - var n_special_slots: u32 = 0; - if (self.requirements) |req| { - ssize += @sizeOf(macho.BlobIndex) + req.size(); - n_special_slots = @max(n_special_slots, req.slotType()); - } - if (self.entitlements) |ent| { - ssize += @sizeOf(macho.BlobIndex) + ent.size() + hash_size; - n_special_slots = @max(n_special_slots, ent.slotType()); - } - if (self.signature) |sig| { - ssize += @sizeOf(macho.BlobIndex) + sig.size(); - } - ssize += n_special_slots * hash_size; - return @as(u32, @intCast(mem.alignForward(u64, ssize, @sizeOf(u64)))); -} +const std = @import("std"); +const assert = std.debug.assert; +const fs = std.fs; +const log = std.log.scoped(.link); +const macho = std.macho; +const mem = std.mem; +const testing = std.testing; -pub fn clear(self: *CodeSignature, allocator: Allocator) void { - self.code_directory.deinit(allocator); - self.code_directory = CodeDirectory.init(self.page_size); -} +const Allocator = mem.Allocator; +const Compilation = @import("../../Compilation.zig"); +const Hasher = @import("hasher.zig").ParallelHasher; +const Sha256 = std.crypto.hash.sha2.Sha256; |
