stage2 macho: generate a code sig (not valid yet)
parent
9dcf7ee9c9
commit
a6e93da717
|
@ -1384,10 +1384,10 @@ pub const CSTYPE_INDEX_REQUIREMENTS: u32 = 0x00000002;
|
|||
/// Compat with amfi
|
||||
pub const CSTYPE_INDEX_ENTITLEMENTS: u32 = 0x00000005;
|
||||
|
||||
pub const CS_HASHTYPE_SHA1: u32 = 1;
|
||||
pub const CS_HASHTYPE_SHA256: u32 = 2;
|
||||
pub const CS_HASHTYPE_SHA256_TRUNCATED: u32 = 3;
|
||||
pub const CS_HASHTYPE_SHA384: u32 = 4;
|
||||
pub const CS_HASHTYPE_SHA1: u8 = 1;
|
||||
pub const CS_HASHTYPE_SHA256: u8 = 2;
|
||||
pub const CS_HASHTYPE_SHA256_TRUNCATED: u8 = 3;
|
||||
pub const CS_HASHTYPE_SHA384: u8 = 4;
|
||||
|
||||
pub const CS_SHA1_LEN: u32 = 20;
|
||||
pub const CS_SHA256_LEN: u32 = 32;
|
||||
|
|
|
@ -385,8 +385,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
|
|||
try self.base.file.?.pwriteAll(mem.spanZ(LIB_SYSTEM_PATH), off);
|
||||
self.libsystem_cmd_dirty = false;
|
||||
}
|
||||
|
||||
try self.writecodeSignature();
|
||||
},
|
||||
.Obj => {},
|
||||
.Lib => return error.TODOImplementWritingLibFiles,
|
||||
|
@ -430,6 +428,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
|
|||
assert(!self.cmd_table_dirty);
|
||||
assert(!self.dylinker_cmd_dirty);
|
||||
assert(!self.libsystem_cmd_dirty);
|
||||
|
||||
switch (self.base.options.output_mode) {
|
||||
.Exe, .Lib => try self.writeCodeSignature(), // code signing always comes last
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
|
||||
|
@ -1486,6 +1489,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {
|
|||
log.debug("found code signature free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
|
||||
code_sig.dataoff = off;
|
||||
code_sig.datasize = file_size;
|
||||
|
||||
const segment_size = mem.alignForwardGeneric(u64, file_size, self.page_size);
|
||||
linkedit.vmsize += segment_size;
|
||||
}
|
||||
}
|
||||
if (self.dyld_stub_binder_index == null) {
|
||||
|
@ -1752,7 +1758,7 @@ fn writeAllUndefSymbols(self: *MachO) !void {
|
|||
try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undef_symbols.items), off);
|
||||
}
|
||||
|
||||
fn writecodeSignature(self: *MachO) !void {
|
||||
fn writeCodeSignature(self: *MachO) !void {
|
||||
const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;
|
||||
|
||||
var code_sig = CodeSignature.init(self.base.allocator);
|
||||
|
@ -1766,7 +1772,7 @@ fn writecodeSignature(self: *MachO) !void {
|
|||
code_sig.write(buffer);
|
||||
|
||||
try self.base.file.?.pwriteAll(buffer, code_sig_cmd.dataoff);
|
||||
try self.base.file.?.pwriteAll(&[_]u8{ 0 }, code_sig_cmd.dataoff + code_sig_cmd.datasize - 1);
|
||||
try self.base.file.?.pwriteAll(&[_]u8{0}, code_sig_cmd.dataoff + code_sig_cmd.datasize - 1);
|
||||
}
|
||||
|
||||
fn writeExportTrie(self: *MachO) !void {
|
||||
|
|
|
@ -7,19 +7,24 @@ const macho = std.macho;
|
|||
const mem = std.mem;
|
||||
const testing = std.testing;
|
||||
const Allocator = mem.Allocator;
|
||||
const Sha256 = std.crypto.hash.sha2.Sha256;
|
||||
|
||||
const MachO = @import("../MachO.zig");
|
||||
|
||||
const Blob = struct {
|
||||
const hash_size: u8 = 32;
|
||||
const page_size: u16 = 0x1000;
|
||||
|
||||
const CodeDirectory = struct {
|
||||
inner: macho.CodeDirectory,
|
||||
data: std.ArrayListUnmanaged(u8) = .{},
|
||||
|
||||
fn size(self: Blob) u32 {
|
||||
fn size(self: CodeDirectory) u32 {
|
||||
return self.inner.length;
|
||||
}
|
||||
|
||||
fn write(self: Blob, buffer: []u8) void {
|
||||
fn write(self: CodeDirectory, buffer: []u8) void {
|
||||
assert(buffer.len >= self.inner.length);
|
||||
|
||||
mem.writeIntBig(u32, buffer[0..4], self.inner.magic);
|
||||
mem.writeIntBig(u32, buffer[4..8], self.inner.length);
|
||||
mem.writeIntBig(u32, buffer[8..12], self.inner.version);
|
||||
|
@ -29,10 +34,10 @@ const Blob = struct {
|
|||
mem.writeIntBig(u32, buffer[24..28], self.inner.nSpecialSlots);
|
||||
mem.writeIntBig(u32, buffer[28..32], self.inner.nCodeSlots);
|
||||
mem.writeIntBig(u32, buffer[32..36], self.inner.codeLimit);
|
||||
mem.writeIntBig(u8, buffer[36..37], self.inner.hashSize);
|
||||
mem.writeIntBig(u8, buffer[37..38], self.inner.hashType);
|
||||
mem.writeIntBig(u8, buffer[38..39], self.inner.platform);
|
||||
mem.writeIntBig(u8, buffer[39..40], self.inner.pageSize);
|
||||
buffer[36] = self.inner.hashSize;
|
||||
buffer[37] = self.inner.hashType;
|
||||
buffer[38] = self.inner.platform;
|
||||
buffer[39] = self.inner.pageSize;
|
||||
mem.writeIntBig(u32, buffer[40..44], self.inner.spare2);
|
||||
mem.writeIntBig(u32, buffer[44..48], self.inner.scatterOffset);
|
||||
mem.writeIntBig(u32, buffer[48..52], self.inner.teamOffset);
|
||||
|
@ -41,6 +46,8 @@ const Blob = struct {
|
|||
mem.writeIntBig(u64, buffer[64..72], self.inner.execSegBase);
|
||||
mem.writeIntBig(u64, buffer[72..80], self.inner.execSegLimit);
|
||||
mem.writeIntBig(u64, buffer[80..88], self.inner.execSegFlags);
|
||||
|
||||
mem.copy(u8, buffer[88..], self.data.items);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -50,7 +57,7 @@ inner: macho.SuperBlob = .{
|
|||
.length = @sizeOf(macho.SuperBlob),
|
||||
.count = 0,
|
||||
},
|
||||
blob: ?Blob = null,
|
||||
cdir: ?CodeDirectory = null,
|
||||
|
||||
pub fn init(alloc: *Allocator) CodeSignature {
|
||||
return .{
|
||||
|
@ -60,10 +67,14 @@ pub fn init(alloc: *Allocator) CodeSignature {
|
|||
|
||||
pub fn calcAdhocSignature(self: *CodeSignature, bin_file: *const MachO) !void {
|
||||
const text_segment = bin_file.load_commands.items[bin_file.text_segment_cmd_index.?].Segment;
|
||||
const data_segment = bin_file.load_commands.items[bin_file.data_segment_cmd_index.?].Segment;
|
||||
const linkedit_segment = bin_file.load_commands.items[bin_file.linkedit_segment_cmd_index.?].Segment;
|
||||
const symtab = bin_file.load_commands.items[bin_file.symtab_cmd_index.?].Symtab;
|
||||
|
||||
const execSegBase: u64 = text_segment.fileoff;
|
||||
const execSegLimit: u64 = text_segment.filesize;
|
||||
const execSegFlags: u64 = text_segment.flags;
|
||||
var blob = Blob{
|
||||
const execSegFlags: u64 = if (bin_file.base.options.output_mode == .Exe) macho.CS_EXECSEG_MAIN_BINARY else 0;
|
||||
var cdir = CodeDirectory{
|
||||
.inner = .{
|
||||
.magic = macho.CSMAGIC_CODEDIRECTORY,
|
||||
.length = @sizeOf(macho.CodeDirectory),
|
||||
|
@ -74,10 +85,10 @@ pub fn calcAdhocSignature(self: *CodeSignature, bin_file: *const MachO) !void {
|
|||
.nSpecialSlots = 0,
|
||||
.nCodeSlots = 0,
|
||||
.codeLimit = 0,
|
||||
.hashSize = 0,
|
||||
.hashType = 0,
|
||||
.hashSize = hash_size,
|
||||
.hashType = macho.CS_HASHTYPE_SHA256,
|
||||
.platform = 0,
|
||||
.pageSize = 0,
|
||||
.pageSize = @truncate(u8, std.math.log2(page_size)),
|
||||
.spare2 = 0,
|
||||
.scatterOffset = 0,
|
||||
.teamOffset = 0,
|
||||
|
@ -88,9 +99,48 @@ pub fn calcAdhocSignature(self: *CodeSignature, bin_file: *const MachO) !void {
|
|||
.execSegFlags = execSegFlags,
|
||||
},
|
||||
};
|
||||
self.inner.length += @sizeOf(macho.BlobIndex) + blob.size();
|
||||
|
||||
const file_size = symtab.stroff + symtab.strsize;
|
||||
const total_pages = mem.alignForward(file_size, page_size) / page_size;
|
||||
log.debug("Total file size: {}; total number of pages: {}\n", .{ file_size, total_pages });
|
||||
|
||||
var hash: [hash_size]u8 = undefined;
|
||||
var buffer = try bin_file.base.allocator.alloc(u8, page_size);
|
||||
defer bin_file.base.allocator.free(buffer);
|
||||
const macho_file = bin_file.base.file.?;
|
||||
|
||||
const id = bin_file.base.options.emit.?.sub_path;
|
||||
try cdir.data.ensureCapacity(self.alloc, total_pages * hash_size + id.len + 1);
|
||||
|
||||
// 1. Save the identifier and update offsets
|
||||
cdir.inner.identOffset = cdir.inner.length;
|
||||
cdir.data.appendSliceAssumeCapacity(id);
|
||||
cdir.data.appendAssumeCapacity(0);
|
||||
|
||||
// 2. Calculate hash for each page (in file) and write it to the buffer
|
||||
// TODO figure out how we can cache several hashes since we won't update
|
||||
// every page during incremental linking
|
||||
cdir.inner.hashOffset = cdir.inner.identOffset + @intCast(u32, id.len) + 1;
|
||||
var i: usize = 0;
|
||||
while (i < total_pages) : (i += 1) {
|
||||
const fstart = i * page_size;
|
||||
const fsize = if (fstart + page_size > file_size) file_size - fstart else page_size;
|
||||
const len = try macho_file.preadAll(buffer, fstart);
|
||||
assert(fsize <= len);
|
||||
|
||||
Sha256.hash(buffer[0..fsize], &hash, .{});
|
||||
log.debug("Calculated hash for page 0x{x}-0x{x}: 0x{x}\n", .{ fstart, fstart + fsize, hash[0..] });
|
||||
|
||||
cdir.data.appendSliceAssumeCapacity(hash[0..]);
|
||||
cdir.inner.nCodeSlots += 1;
|
||||
}
|
||||
|
||||
// 3. Update CodeDirectory length
|
||||
cdir.inner.length += @intCast(u32, cdir.data.items.len);
|
||||
|
||||
self.inner.length += @sizeOf(macho.BlobIndex) + cdir.size();
|
||||
self.inner.count = 1;
|
||||
self.blob = blob;
|
||||
self.cdir = cdir;
|
||||
}
|
||||
|
||||
pub fn size(self: CodeSignature) u32 {
|
||||
|
@ -102,12 +152,12 @@ pub fn write(self: CodeSignature, buffer: []u8) void {
|
|||
self.writeHeader(buffer);
|
||||
const offset: u32 = @sizeOf(macho.SuperBlob) + @sizeOf(macho.BlobIndex);
|
||||
writeBlobIndex(macho.CSSLOT_CODEDIRECTORY, offset, buffer[@sizeOf(macho.SuperBlob)..]);
|
||||
self.blob.?.write(buffer[offset..]);
|
||||
self.cdir.?.write(buffer[offset..]);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *CodeSignature) void {
|
||||
if (self.blob) |*b| {
|
||||
b.data.deinit(self.alloc);
|
||||
if (self.cdir) |*cdir| {
|
||||
cdir.data.deinit(self.alloc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue