Skip to content

Commit 8cbf864

Browse files
sstricklCommit Queue
authored andcommitted
[vm] Add LC_ENCRYPTION_INFO(_64) load command to iOS snapshots.
When uploading to the App Store, the program must contain an LC_ENCRYPTION_INFO segment in the Mach-O header so the App Store can appropriately modify it for its purposes without changing the header size and/or offsets/addresses in the rest of the shared object. By default, the load command is only added to iOS snapshots, but it can be added to any Mach-O snapshot using the --macho-encryptable command line option. TEST=vm/dart/use_macho_options_test Cq-Include-Trybots: luci.dart.try:vm-aot-mac-debug-x64-try,vm-aot-mac-debug-arm64-try,vm-aot-linux-debug-x64-try Change-Id: I4e79fd9cfb9ba9d49707ec209eca3fee1cefc28c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/475040 Reviewed-by: Alexander Markov <[email protected]> Commit-Queue: Tess Strickland <[email protected]>
1 parent 87005f5 commit 8cbf864

4 files changed

Lines changed: 208 additions & 16 deletions

File tree

pkg/native_stack_traces/lib/src/macho.dart

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ class LoadCommand {
130130
static const LC_UUID = 0x1b;
131131
static const LC_RPATH = 0x1c | LC_REQ_DYLD;
132132
static const LC_CODE_SIGNATURE = 0x1d; // Only used in vm/dart tests.
133+
static const LC_ENCRYPTION_INFO = 0x21;
134+
static const LC_ENCRYPTION_INFO_64 = 0x2c;
133135
static const LC_BUILD_VERSION = 0x32;
134136

135137
static LoadCommand fromReader(Reader reader) {
@@ -156,6 +158,9 @@ class LoadCommand {
156158
command = DylibCommand.fromReader(reader, cmd, cmdsize);
157159
case LC_RPATH:
158160
command = RunPathCommand.fromReader(reader, cmd, cmdsize);
161+
case LC_ENCRYPTION_INFO:
162+
case LC_ENCRYPTION_INFO_64:
163+
command = EncryptionInfoCommand.fromReader(reader, cmd, cmdsize);
159164
default:
160165
break;
161166
}
@@ -602,6 +607,38 @@ class BuildVersionCommand extends LoadCommand {
602607
}
603608
}
604609

610+
class EncryptionInfoCommand extends LoadCommand {
611+
final int fileOffset;
612+
final int fileSize;
613+
final int cryptId;
614+
615+
EncryptionInfoCommand._(
616+
super.cmd, super.cmdsize, this.fileOffset, this.fileSize, this.cryptId)
617+
: super._();
618+
619+
static EncryptionInfoCommand fromReader(Reader reader, int cmd, int cmdsize) {
620+
final fileOffset = _readMachOUint32(reader);
621+
final fileSize = _readMachOUint32(reader);
622+
final cryptId = _readMachOUint32(reader);
623+
if (cmd == LoadCommand.LC_ENCRYPTION_INFO_64) {
624+
_readMachOUint32(reader); // padding
625+
}
626+
return EncryptionInfoCommand._(cmd, cmdsize, fileOffset, fileSize, cryptId);
627+
}
628+
629+
@override
630+
void writeToStringBuffer(StringBuffer buffer) {
631+
buffer
632+
..writeln('Encryption info: ')
633+
..write(' File offset: ')
634+
..writeln(paddedHex(fileOffset, 4))
635+
..write(' File size: ')
636+
..writeln(fileSize)
637+
..write(' Crypt id: ')
638+
..writeln(cryptId);
639+
}
640+
}
641+
605642
class MachOHeader {
606643
final int magic;
607644
final int cputype;

runtime/platform/mach_o.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,14 @@ static constexpr uint32_t LC_RPATH = (0x1c | LC_REQ_DYLD);
140140
// The code signature which protects the preceding portion of the object file.
141141
// Must be the last contents in the object file. (linkedit_data_command)
142142
static constexpr uint32_t LC_CODE_SIGNATURE = 0x1d;
143+
// Information about encrypted segments for 32-bit targets. Must also be present
144+
// for programs with no encrypted segments that are uploaded to the App Store
145+
// so it can be updated appropriately.
146+
static constexpr uint32_t LC_ENCRYPTION_INFO = 0x21;
147+
// Information about encrypted segments for 64-bit targets. Must also be present
148+
// for programs with no encrypted segments that are uploaded to the App Store
149+
// so it can be updated appropriately.
150+
static constexpr uint32_t LC_ENCRYPTION_INFO_64 = 0x2c;
143151
// An arbitrary piece of data not specified by the Mach-O format. (note_command)
144152
static constexpr uint32_t LC_NOTE = 0x31;
145153
// The target platform and minimum and target OS versions for this object file.
@@ -743,6 +751,23 @@ static constexpr uint32_t RELOC_TYPE_ARM64_UNSIGNED = 0 << 28;
743751
// _before_ the target (UNSIGNED) entry that it is subtracted from.
744752
static constexpr uint32_t RELOC_TYPE_ARM64_SUBTRACTOR = 1 << 28;
745753

754+
struct encryption_info_command {
755+
uint32_t cmd; // LC_ENCRYPTION_INFO
756+
uint32_t cmdsize;
757+
uint32_t cryptoff; // file offset of the encrypted segment(s)
758+
uint32_t cryptsize; // file size of the encrypted segment(s)
759+
uint32_t cryptid; // encryption cypher used (0 == not encrypted)
760+
};
761+
762+
struct encryption_info_command_64 {
763+
uint32_t cmd; // LC_ENCRYPTION_INFO_64
764+
uint32_t cmdsize;
765+
uint32_t cryptoff; // file offset of the encrypted segment(s)
766+
uint32_t cryptsize; // file size of the encrypted segment(s)
767+
uint32_t cryptid; // encryption cypher used (0 == not encrypted)
768+
uint32_t pad; // padding to a multiple of 64 bits
769+
};
770+
746771
#pragma pack(pop)
747772

748773
} // namespace mach_o

runtime/tests/vm/dart/use_macho_options_test.dart

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ enum TestType {
129129
MinOSVersion,
130130
NoLinkerSignature,
131131
ReplaceInstallName,
132+
Encryptable,
132133
}
133134

134135
@pragma('vm:platform-const')
@@ -156,6 +157,7 @@ Future<void> checkCases(List<TestCase> testCases) async {
156157
checkRunPaths(c);
157158
checkBuildVersion(c);
158159
checkCodeSignature(c);
160+
checkEncryptionInfo(c);
159161
}
160162
// Unsigned snapshots are not runnable.
161163
final runnableCases = testCases
@@ -329,6 +331,21 @@ void checkCodeSignature(TestCase testCase) {
329331
}
330332
}
331333

334+
void checkEncryptionInfo(TestCase testCase) {
335+
final encryptionInfoCommands = testCase.snapshot.commands
336+
.whereType<macho.EncryptionInfoCommand>();
337+
if (testCase.type == TestType.Encryptable) {
338+
Expect.equals(1, encryptionInfoCommands.length);
339+
final cmd = encryptionInfoCommands.singleOrNull;
340+
if (cmd != null) {
341+
// gen_snapshot doesn't encrypt any segments.
342+
Expect.equals(0, cmd.cryptId);
343+
}
344+
} else {
345+
Expect.isEmpty(encryptionInfoCommands);
346+
}
347+
}
348+
332349
void checkBuildVersion(TestCase testCase) {
333350
final buildVersion = testCase.snapshot
334351
.commandsWhereType<macho.BuildVersionCommand>()

0 commit comments

Comments
 (0)