Skip to content

Commit 1a830aa

Browse files
authored
[ObjCopy] Respect requirements of LC_ENCRYPTION_INFO commands (#120995)
LLD (and other Mach-O linkers) when preparing an encryptable binary make space to leave all the load commands in an non-encrypted page (see [1]) When using objcopy of a small encryptable binary, the code was not respecting this fact, and the encryptable segments were not kept beyond the first page. This was obvious for small or empty binaries. The changes introduced here keep track if a `LC_ENCRYPTION_INFO` or `LC_ENCRYPTION_INFO_64` has been seen, and in such case, it adds a full page of offset in order to leave the load commands in its own page (similar to what LLD is doing). [1]: https://github.com/llvm/llvm-project/blob/d8e792931226b15d9d2424ecd24ccfe13adc2367/lld/MachO/SyntheticSections.cpp#L90-L93
1 parent e540546 commit 1a830aa

File tree

5 files changed

+233
-0
lines changed

5 files changed

+233
-0
lines changed

llvm/lib/ObjCopy/MachO/MachOLayoutBuilder.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ uint64_t MachOLayoutBuilder::layoutSegments() {
116116
const bool IsObjectFile =
117117
O.Header.FileType == MachO::HeaderFileType::MH_OBJECT;
118118
uint64_t Offset = IsObjectFile ? (HeaderSize + O.Header.SizeOfCmds) : 0;
119+
if (O.EncryptionInfoCommandIndex) {
120+
// If we are emitting an encryptable binary, our load commands must have a
121+
// separate (non-encrypted) page to themselves.
122+
Offset = alignToPowerOf2(HeaderSize + O.Header.SizeOfCmds, PageSize);
123+
}
119124
for (LoadCommand &LC : O.LoadCommands) {
120125
auto &MLC = LC.MachOLoadCommand;
121126
StringRef Segname;

llvm/lib/ObjCopy/MachO/MachOObject.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ void Object::updateLoadCommandIndexes() {
9898
case MachO::LC_DYLD_EXPORTS_TRIE:
9999
ExportsTrieCommandIndex = Index;
100100
break;
101+
case MachO::LC_ENCRYPTION_INFO:
102+
case MachO::LC_ENCRYPTION_INFO_64:
103+
EncryptionInfoCommandIndex = Index;
104+
break;
101105
}
102106
}
103107
}

llvm/lib/ObjCopy/MachO/MachOObject.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,9 @@ struct Object {
341341
/// The index of the LC_SEGMENT or LC_SEGMENT_64 load command
342342
/// corresponding to the __TEXT segment.
343343
std::optional<size_t> TextSegmentCommandIndex;
344+
/// The index of the LC_ENCRYPTION_INFO or LC_ENCRYPTION_INFO_64 load command
345+
/// if present.
346+
std::optional<size_t> EncryptionInfoCommandIndex;
344347

345348
BumpPtrAllocator Alloc;
346349
StringSaver NewSectionsContents;

llvm/lib/ObjCopy/MachO/MachOReader.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ Error MachOReader::readLoadCommands(Object &O) const {
184184
case MachO::LC_DYLD_CHAINED_FIXUPS:
185185
O.ChainedFixupsCommandIndex = O.LoadCommands.size();
186186
break;
187+
case MachO::LC_ENCRYPTION_INFO:
188+
case MachO::LC_ENCRYPTION_INFO_64:
189+
O.EncryptionInfoCommandIndex = O.LoadCommands.size();
190+
break;
187191
}
188192
#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
189193
case MachO::LCName: \
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
# RUN: rm -rf %t && mkdir %t
2+
# RUN: yaml2obj %s -o %t/original
3+
# RUN: llvm-strip --strip-all %t/original -o %t/stripped
4+
# RUN: llvm-readobj --macho-segment %t/stripped | FileCheck %s
5+
6+
# CHECK-LABEL: Name: __PAGEZERO
7+
# CHECK: fileoff: 16384
8+
9+
# CHECK-LABEL: Name: __TEXT
10+
# CHECK: fileoff: 16384
11+
12+
# The YAML below is the following code
13+
# int main(int argc, char **argv) { return 0; }
14+
# Compiled on macOS against the macOS SDK and passing `-Wl,-encryptable`
15+
# Contents are removed, since they are not important for the test. We need a
16+
# small text segment (smaller than a page).
17+
--- !mach-o
18+
FileHeader:
19+
magic: 0xFEEDFACF
20+
cputype: 0x100000C
21+
cpusubtype: 0x0
22+
filetype: 0x2
23+
ncmds: 15
24+
sizeofcmds: 696
25+
flags: 0x200085
26+
reserved: 0x0
27+
LoadCommands:
28+
- cmd: LC_SEGMENT_64
29+
cmdsize: 72
30+
segname: __PAGEZERO
31+
vmaddr: 0
32+
vmsize: 4294967296
33+
fileoff: 0
34+
filesize: 0
35+
maxprot: 0
36+
initprot: 0
37+
nsects: 0
38+
flags: 0
39+
- cmd: LC_SEGMENT_64
40+
cmdsize: 232
41+
segname: __TEXT
42+
vmaddr: 4294967296
43+
vmsize: 32768
44+
fileoff: 0
45+
filesize: 32768
46+
maxprot: 5
47+
initprot: 5
48+
nsects: 2
49+
flags: 0
50+
Sections:
51+
- sectname: __text
52+
segname: __TEXT
53+
addr: 0x100004000
54+
size: 32
55+
offset: 0x4000
56+
align: 2
57+
reloff: 0x0
58+
nreloc: 0
59+
flags: 0x80000400
60+
reserved1: 0x0
61+
reserved2: 0x0
62+
reserved3: 0x0
63+
- sectname: __unwind_info
64+
segname: __TEXT
65+
addr: 0x100004020
66+
size: 4152
67+
offset: 0x4020
68+
align: 2
69+
reloff: 0x0
70+
nreloc: 0
71+
flags: 0x0
72+
reserved1: 0x0
73+
reserved2: 0x0
74+
reserved3: 0x0
75+
- cmd: LC_SEGMENT_64
76+
cmdsize: 72
77+
segname: __LINKEDIT
78+
vmaddr: 4295000064
79+
vmsize: 592
80+
fileoff: 32768
81+
filesize: 592
82+
maxprot: 1
83+
initprot: 1
84+
nsects: 0
85+
flags: 0
86+
- cmd: LC_DYLD_CHAINED_FIXUPS
87+
cmdsize: 16
88+
dataoff: 32768
89+
datasize: 48
90+
- cmd: LC_DYLD_EXPORTS_TRIE
91+
cmdsize: 16
92+
dataoff: 32816
93+
datasize: 48
94+
- cmd: LC_SYMTAB
95+
cmdsize: 24
96+
symoff: 32872
97+
nsyms: 2
98+
stroff: 32904
99+
strsize: 32
100+
- cmd: LC_DYSYMTAB
101+
cmdsize: 80
102+
ilocalsym: 0
103+
nlocalsym: 0
104+
iextdefsym: 0
105+
nextdefsym: 2
106+
iundefsym: 2
107+
nundefsym: 0
108+
tocoff: 0
109+
ntoc: 0
110+
modtaboff: 0
111+
nmodtab: 0
112+
extrefsymoff: 0
113+
nextrefsyms: 0
114+
indirectsymoff: 0
115+
nindirectsyms: 0
116+
extreloff: 0
117+
nextrel: 0
118+
locreloff: 0
119+
nlocrel: 0
120+
- cmd: LC_ENCRYPTION_INFO_64
121+
cmdsize: 24
122+
cryptoff: 16384
123+
cryptsize: 16384
124+
cryptid: 0
125+
pad: 0
126+
- cmd: LC_LOAD_DYLINKER
127+
cmdsize: 32
128+
name: 12
129+
Content: '/usr/lib/dyld'
130+
ZeroPadBytes: 7
131+
- cmd: LC_UUID
132+
cmdsize: 24
133+
uuid: 4C4C4447-5555-3144-A18A-01E9EB7E7D92
134+
- cmd: LC_BUILD_VERSION
135+
cmdsize: 32
136+
platform: 1
137+
minos: 983040
138+
sdk: 983552
139+
ntools: 1
140+
Tools:
141+
- tool: 4
142+
version: 1310720
143+
- cmd: LC_MAIN
144+
cmdsize: 24
145+
entryoff: 16384
146+
stacksize: 0
147+
- cmd: LC_FUNCTION_STARTS
148+
cmdsize: 16
149+
dataoff: 32864
150+
datasize: 8
151+
- cmd: LC_DATA_IN_CODE
152+
cmdsize: 16
153+
dataoff: 32872
154+
datasize: 0
155+
- cmd: LC_CODE_SIGNATURE
156+
cmdsize: 16
157+
dataoff: 32944
158+
datasize: 416
159+
LinkEditData:
160+
ExportTrie:
161+
TerminalSize: 0
162+
NodeOffset: 0
163+
Name: ''
164+
Flags: 0x0
165+
Address: 0x0
166+
Other: 0x0
167+
ImportName: ''
168+
Children:
169+
- TerminalSize: 0
170+
NodeOffset: 5
171+
Name: _
172+
Flags: 0x0
173+
Address: 0x0
174+
Other: 0x0
175+
ImportName: ''
176+
Children:
177+
- TerminalSize: 4
178+
NodeOffset: 33
179+
Name: main
180+
Flags: 0x0
181+
Address: 0x4000
182+
Other: 0x0
183+
ImportName: ''
184+
- TerminalSize: 2
185+
NodeOffset: 39
186+
Name: _mh_execute_header
187+
Flags: 0x0
188+
Address: 0x0
189+
Other: 0x0
190+
ImportName: ''
191+
NameList:
192+
- n_strx: 2
193+
n_type: 0xF
194+
n_sect: 1
195+
n_desc: 0
196+
n_value: 4294983680
197+
- n_strx: 8
198+
n_type: 0xF
199+
n_sect: 1
200+
n_desc: 16
201+
n_value: 4294967296
202+
StringTable:
203+
- ' '
204+
- _main
205+
- __mh_execute_header
206+
- ''
207+
- ''
208+
- ''
209+
- ''
210+
FunctionStarts: [ 0x4000 ]
211+
ChainedFixups: [ 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x30, 0x0,
212+
0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
213+
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
214+
0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
215+
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
216+
...
217+

0 commit comments

Comments
 (0)