dyld-832.7.1.tar.gz
[apple/dyld.git] / testing / kernel-cache-tests / auxkc-pageablekc-vtable-patching-namespaces-locals / test.py
1 #!/usr/bin/python2.7
2
3 import os
4 import KernelCollection
5
6 # This is the same as auxkc-pageablekc-vtable-patching-namespaces
7 # but this test has all local symbols instead of global symbols
8
9
10 # The kernel has class OSObject and subclass KernelClass
11 # foo.kext sublclasses KernelClass to get Foo1, and subclasses that to get Foo2
12 # bar.kext sublclasses Foo1 to get Bar1, and subclasses that to get Bar2
13
14 # In KernelClass the vtable layout is:
15 # [ ..., foo() kernelClassUsed0() ]
16
17 # In Foo1, the layout is:
18 # [ ..., foo() kernelClass_RESERVED0(), foo1Used0(), foo1Used1() ]
19
20 # In Foo2, the layout is:
21 # [ ..., foo() kernelClass_RESERVED0(), foo1Used0(), foo1_RESERVED1(), foo1_RESERVED2(), foo1_RESERVED3() ]
22
23 # In Bar1, the layout is:
24 # [ ..., foo() kernelClass_RESERVED0(), foo1Used0(), foo1_RESERVED1(), foo1_RESERVED2(), foo1_RESERVED3() ]
25
26 # In Bar2, the layout is:
27 # [ ..., foo() kernelClass_RESERVED0(), foo1Used0(), foo1_RESERVED1(), foo1_RESERVED2(), foo1_RESERVED3() ]
28
29 # All kext's will end up getting the vtable entry after foo() patched to kernelClassUsed0()
30 # Foo2, Bar1, Bar2, will also get the vtable entry after foo1Used0() patched to foo1Used1()
31
32 def findGlobalSymbolVMAddr(kernel_cache, dylib_index, symbol_name):
33 for symbol_and_addr in kernel_cache.dictionary()["dylibs"][dylib_index]["global-symbols"]:
34 if symbol_and_addr["name"] == symbol_name:
35 return symbol_and_addr["vmAddr"]
36 return None
37
38 def findLocalSymbolVMAddr(kernel_cache, dylib_index, symbol_name):
39 for symbol_and_addr in kernel_cache.dictionary()["dylibs"][dylib_index]["local-symbols"]:
40 if symbol_and_addr["name"] == symbol_name:
41 return symbol_and_addr["vmAddr"]
42 return None
43
44 def findFixupVMAddr(kernel_cache, fixup_name):
45 for fixup_vmaddr, fixup_target in kernel_cache.dictionary()["fixups"].iteritems():
46 if fixup_target == fixup_name:
47 return fixup_vmaddr
48 return None
49
50 def findPagableFixupVMAddr(kernel_cache, dylib_index, fixup_name):
51 for fixup_vmaddr, fixup_target in kernel_cache.dictionary()["dylibs"][dylib_index]["fixups"].iteritems():
52 if fixup_target == fixup_name:
53 return fixup_vmaddr
54 return None
55
56 def findAuxFixupVMAddr(kernel_cache, dylib_index, fixup_name):
57 for fixup_vmaddr, fixup_target in kernel_cache.dictionary()["dylibs"][dylib_index]["fixups"].iteritems():
58 if fixup_target == fixup_name:
59 return fixup_vmaddr
60 return None
61
62 def offsetVMAddr(vmAddr, offset):
63 het_int = int(vmAddr, 16)
64 het_int = het_int + offset
65 return ''.join([ '0x', hex(het_int).upper()[2:] ])
66
67 def check(kernel_cache):
68 enableLogging = False
69 kernel_cache.buildKernelCollection("x86_64", "/auxkc-pageablekc-vtable-patching-namespaces-locals/main.kc", "/auxkc-pageablekc-vtable-patching-namespaces-locals/main.kernel", "", [], [])
70 kernel_cache.analyze("/auxkc-pageablekc-vtable-patching-namespaces-locals/main.kc", ["-layout", "-arch", "x86_64"])
71
72 assert len(kernel_cache.dictionary()["dylibs"]) == 1
73 assert kernel_cache.dictionary()["dylibs"][0]["name"] == "com.apple.kernel"
74
75 # Get the addresses for the symbols we are looking at. This will make it easier to work out the fixup slots
76 kernel_cache.analyze("/auxkc-pageablekc-vtable-patching-namespaces-locals/main.kc", ["-symbols", "-arch", "x86_64"])
77
78 # From kernel, we want to know where the vtable is, and the foo() and kernelClassUsed0() slots in that vtable
79 # KernelClass::foo()
80 kernelClassFooVMAddr = findGlobalSymbolVMAddr(kernel_cache, 0, "__ZN1X11KernelClass3fooEv")
81 if enableLogging:
82 print "kernelClassFooVMAddr: " + kernelClassFooVMAddr
83
84 # KernelClass::kernelClassUsed0()
85 kernelClassUsed0VMAddr = findGlobalSymbolVMAddr(kernel_cache, 0, "__ZN1X11KernelClass16kernelClassUsed0Ev")
86 if enableLogging:
87 print "kernelClassUsed0VMAddr: " + kernelClassUsed0VMAddr
88
89
90 # Check the fixups
91 kernel_cache.analyze("/auxkc-pageablekc-vtable-patching-namespaces-locals/main.kc", ["-fixups", "-arch", "x86_64"])
92
93 # In vtable for Foo, we match the entry for Foo::foo() by looking for its value on the RHS of the fixup
94 kernelFooFixupAddr = findFixupVMAddr(kernel_cache, "kc(0) + " + kernelClassFooVMAddr + " : pointer64")
95 if enableLogging:
96 print "kernelFooFixupAddr: " + kernelFooFixupAddr
97 # Then the following fixup should be to KernelClass::kernelClassUsed0()
98 kernelFooNextFixupAddr = offsetVMAddr(kernelFooFixupAddr, 8)
99 if enableLogging:
100 print "kernelFooNextFixupAddr: " + kernelFooNextFixupAddr
101 assert kernel_cache.dictionary()["fixups"][kernelFooNextFixupAddr] == "kc(0) + " + kernelClassUsed0VMAddr + " : pointer64"
102
103 # From this point on, the vmAddr for __ZN1X11KernelClass16kernelClassUsed0Ev is an offset in to kc(0)
104 # so we want to turn it from a vmAddr to vmOffset by subtracting the base address of 0x4000 which is on __HIB
105 kernelClassUsed0VMOffset = offsetVMAddr(kernelClassUsed0VMAddr, -0x4000)
106 if enableLogging:
107 print "kernelClassUsed0VMOffset: " + kernelClassUsed0VMOffset
108
109 # -----------------------------------------------------------
110 # Now build an pageable cache using the baseline kernel collection
111 kernel_cache.buildPageableKernelCollection("x86_64", "/auxkc-pageablekc-vtable-patching-namespaces-locals/pageable.kc", "/auxkc-pageablekc-vtable-patching-namespaces-locals/main.kc", "/auxkc-pageablekc-vtable-patching-namespaces-locals/extensions", ["com.apple.foo1", "com.apple.foo2"], [])
112 kernel_cache.analyze("/auxkc-pageablekc-vtable-patching-namespaces-locals/pageable.kc", ["-layout", "-arch", "x86_64"])
113
114 assert len(kernel_cache.dictionary()["dylibs"]) == 2
115 assert kernel_cache.dictionary()["dylibs"][0]["name"] == "com.apple.foo1"
116 assert kernel_cache.dictionary()["dylibs"][1]["name"] == "com.apple.foo2"
117
118
119 # Get the addresses for the symbols we are looking at. This will make it easier to work out the fixup slots
120 kernel_cache.analyze("/auxkc-pageablekc-vtable-patching-namespaces-locals/pageable.kc", ["-symbols", "-arch", "x86_64"])
121
122 # From foo1, find the vtable and its override of foo()
123 # Foo1::foo()
124 pageableFoo1FooVMAddr = findLocalSymbolVMAddr(kernel_cache, 0, "__ZN1X4Foo13fooEv")
125 if enableLogging:
126 print "pageableFoo1FooVMAddr: " + pageableFoo1FooVMAddr
127
128 pageableFoo1FooUsed0VMAddr = findLocalSymbolVMAddr(kernel_cache, 0, "__ZN1X4Foo19foo1Used0Ev")
129 if enableLogging:
130 print "pageableFoo1FooUsed0VMAddr: " + pageableFoo1FooUsed0VMAddr
131
132 pageableFoo1FooUsed1VMAddr = findLocalSymbolVMAddr(kernel_cache, 0, "__ZN1X4Foo19foo1Used1Ev")
133 if enableLogging:
134 print "pageableFoo1FooUsed1VMAddr: " + pageableFoo1FooUsed1VMAddr
135
136 # From foo2, find the vtable and its override of foo()
137 # Foo2::foo()
138 pageableFoo2FooVMAddr = findLocalSymbolVMAddr(kernel_cache, 1, "__ZN1X4Foo23fooEv")
139 if enableLogging:
140 print "pageableFoo2FooVMAddr: " + pageableFoo2FooVMAddr
141 # Also find Foo2::foo1Used0() as it overrides foo1Used0 from the superclass
142 pageableFoo2FooUsed0VMAddr = findLocalSymbolVMAddr(kernel_cache, 1, "__ZN1X4Foo29foo1Used0Ev")
143 if enableLogging:
144 print "pageableFoo2FooUsed0VMAddr: " + pageableFoo2FooUsed0VMAddr
145
146
147 # Check the fixups
148 kernel_cache.analyze("/auxkc-pageablekc-vtable-patching-namespaces-locals/pageable.kc", ["-fixups", "-arch", "x86_64"])
149 kernel_cache.dictionary()["fixups"] == "none"
150
151 # --- foo1.kext ---
152 # The vtable we have is [ ..., foo(), kernelClass_RESERVED0(), foo1Used0(), foo1Used1() ]
153 # and we want [ ..., foo(), kernelClassUsed0(), foo1Used0(), foo1Used1() ]
154
155 # In vtable for Foo1, we match the entry for Foo1::foo() by looking for its value on the RHS of the fixup
156 pageableFoo1FooFixupAddr = findPagableFixupVMAddr(kernel_cache, 0, "kc(1) + " + pageableFoo1FooVMAddr)
157 if enableLogging:
158 print "pageableFoo1FooFixupAddr: " + pageableFoo1FooFixupAddr
159
160 # Then the following fixup should be to KernelClass::kernelClassUsed0()
161 pageableFoo1FooNextFixupAddr = offsetVMAddr(pageableFoo1FooFixupAddr, 8)
162 if enableLogging:
163 print "pageableFoo1FooNextFixupAddr: " + pageableFoo1FooNextFixupAddr
164 assert kernel_cache.dictionary()["dylibs"][0]["fixups"][pageableFoo1FooNextFixupAddr] == "kc(0) + " + kernelClassUsed0VMOffset
165
166 # Then we should have foo1Used0()
167 pageableFoo1FooNextFixupAddr = offsetVMAddr(pageableFoo1FooFixupAddr, 16)
168 if enableLogging:
169 print "pageableFoo1FooNextFixupAddr: " + pageableFoo1FooNextFixupAddr
170 assert kernel_cache.dictionary()["dylibs"][0]["fixups"][pageableFoo1FooNextFixupAddr] == "kc(1) + " + pageableFoo1FooUsed0VMAddr
171
172 # And then foo1Used1()
173 pageableFoo1FooNextFixupAddr = offsetVMAddr(pageableFoo1FooFixupAddr, 24)
174 if enableLogging:
175 print "pageableFoo1FooNextFixupAddr: " + pageableFoo1FooNextFixupAddr
176 assert kernel_cache.dictionary()["dylibs"][0]["fixups"][pageableFoo1FooNextFixupAddr] == "kc(1) + " + pageableFoo1FooUsed1VMAddr
177
178 # --- foo2.kext ---
179 # The vtable we have is [ ..., foo(), kernelClass_RESERVED0(), foo1Used0(), foo1_RESERVED1() ]
180 # and we want [ ..., foo(), kernelClassUsed0(), foo1Used0(), foo1Used1() ]
181
182 # In vtable for Foo2, we match the entry for Foo2::foo() by looking for its value on the RHS of the fixup
183 pageableFoo2FooFixupAddr = findPagableFixupVMAddr(kernel_cache, 1, "kc(1) + " + pageableFoo2FooVMAddr)
184 if enableLogging:
185 print "pageableFoo2FooFixupAddr: " + pageableFoo2FooFixupAddr
186
187 # Then the following fixup should be to KernelClass::kernelClassUsed0()
188 pageableFoo2FooNextFixupAddr = offsetVMAddr(pageableFoo2FooFixupAddr, 8)
189 if enableLogging:
190 print "pageableFoo2FooNextFixupAddr: " + pageableFoo2FooNextFixupAddr
191 assert kernel_cache.dictionary()["dylibs"][1]["fixups"][pageableFoo2FooNextFixupAddr] == "kc(0) + " + kernelClassUsed0VMOffset
192
193 # Then we should have foo1Used0(), but Foo2 overrides that, so it should be the Foo2 implementation, not the Foo1 implementation
194 pageableFoo2FooNextFixupAddr = offsetVMAddr(pageableFoo2FooFixupAddr, 16)
195 if enableLogging:
196 print "pageableFoo2FooNextFixupAddr: " + pageableFoo2FooNextFixupAddr
197 assert kernel_cache.dictionary()["dylibs"][1]["fixups"][pageableFoo2FooNextFixupAddr] == "kc(1) + " + pageableFoo2FooUsed0VMAddr
198
199 # And then foo1Used1()
200 pageableFoo2FooNextFixupAddr = offsetVMAddr(pageableFoo2FooFixupAddr, 24)
201 if enableLogging:
202 print "pageableFoo2FooNextFixupAddr: " + pageableFoo2FooNextFixupAddr
203 assert kernel_cache.dictionary()["dylibs"][1]["fixups"][pageableFoo2FooNextFixupAddr] == "kc(1) + " + pageableFoo1FooUsed1VMAddr
204
205
206 # -----------------------------------------------------------
207 # Now build an aux cache using the baseline kernel collection
208 kernel_cache.buildAuxKernelCollection("x86_64", "/auxkc-pageablekc-vtable-patching-namespaces-locals/aux.kc", "/auxkc-pageablekc-vtable-patching-namespaces-locals/main.kc", "/auxkc-pageablekc-vtable-patching-namespaces-locals/pageable.kc", "/auxkc-pageablekc-vtable-patching-namespaces-locals/extensions", ["com.apple.bar1", "com.apple.bar2"], [])
209 kernel_cache.analyze("/auxkc-pageablekc-vtable-patching-namespaces-locals/aux.kc", ["-layout", "-arch", "x86_64"])
210
211 assert len(kernel_cache.dictionary()["dylibs"]) == 2
212 assert kernel_cache.dictionary()["dylibs"][0]["name"] == "com.apple.bar1"
213 assert kernel_cache.dictionary()["dylibs"][1]["name"] == "com.apple.bar2"
214
215
216 # Get the addresses for the symbols we are looking at. This will make it easier to work out the fixup slots
217 kernel_cache.analyze("/auxkc-pageablekc-vtable-patching-namespaces-locals/aux.kc", ["-symbols", "-arch", "x86_64"])
218
219 # From bar1, find the vtable and its override of foo()
220 # Bar1::foo()
221 auxBar1FooVMAddr = findLocalSymbolVMAddr(kernel_cache, 0, "__ZN1X4Bar13fooEv")
222 if enableLogging:
223 print "auxBar1FooVMAddr: " + auxBar1FooVMAddr
224
225 # From bar2, find the vtable and its override of foo()
226 # Bar1::foo()
227 auxBar2FooVMAddr = findLocalSymbolVMAddr(kernel_cache, 1, "__ZN4Bar23fooEv")
228 if enableLogging:
229 print "auxBar2FooVMAddr: " + auxBar2FooVMAddr
230
231
232 # Check the fixups
233 kernel_cache.analyze("/auxkc-pageablekc-vtable-patching-namespaces-locals/aux.kc", ["-fixups", "-arch", "x86_64"])
234
235 # --- foo1.kext ---
236 # The vtable we have is [ ..., foo(), kernelClass_RESERVED0(), foo1Used0(), foo1Used1() ]
237 # and we want [ ..., foo(), kernelClassUsed0(), foo1Used0(), foo1Used1() ]
238
239 # In vtable for Bar1, we match the entry for Bar1::foo() by looking for its value on the RHS of the fixup
240 auxBar1FooFixupAddr = findAuxFixupVMAddr(kernel_cache, 0, "kc(3) + " + auxBar1FooVMAddr)
241 if enableLogging:
242 print "auxBar1FooFixupAddr: " + auxBar1FooFixupAddr
243
244 # Then the following fixup should be to KernelClass::kernelClassUsed0()
245 auxBar1FooNextFixupAddr = offsetVMAddr(auxBar1FooFixupAddr, 8)
246 if enableLogging:
247 print "auxBar1FooNextFixupAddr: " + auxBar1FooNextFixupAddr
248 assert kernel_cache.dictionary()["dylibs"][0]["fixups"][auxBar1FooNextFixupAddr] == "kc(0) + " + kernelClassUsed0VMOffset
249
250 # Then we should have foo1Used0() from Foo2 as it overrides it from Foo1
251 auxBar1FooNextFixupAddr = offsetVMAddr(auxBar1FooFixupAddr, 16)
252 if enableLogging:
253 print "auxBar1FooNextFixupAddr: " + auxBar1FooNextFixupAddr
254 assert kernel_cache.dictionary()["dylibs"][0]["fixups"][auxBar1FooNextFixupAddr] == "kc(1) + " + pageableFoo2FooUsed0VMAddr
255
256 # And then foo1Used1()
257 auxBar1FooNextFixupAddr = offsetVMAddr(auxBar1FooFixupAddr, 24)
258 if enableLogging:
259 print "auxBar1FooNextFixupAddr: " + auxBar1FooNextFixupAddr
260 assert kernel_cache.dictionary()["dylibs"][0]["fixups"][auxBar1FooNextFixupAddr] == "kc(1) + " + pageableFoo1FooUsed1VMAddr
261
262 # --- bar2.kext ---
263 # The vtable we have is [ ..., foo(), kernelClass_RESERVED0(), foo1Used0(), foo1_RESERVED1() ]
264 # and we want [ ..., foo(), kernelClassUsed0(), foo1Used0(), foo1Used1() ]
265
266 # In vtable for Foo2, we match the entry for Foo2::foo() by looking for its value on the RHS of the fixup
267 auxBar2FooFixupAddr = findAuxFixupVMAddr(kernel_cache, 1, "kc(3) + " + auxBar2FooVMAddr)
268 if enableLogging:
269 print "auxBar2FooFixupAddr: " + auxBar2FooFixupAddr
270
271 # Then the following fixup should be to KernelClass::kernelClassUsed0()
272 auxBar2FooNextFixupAddr = offsetVMAddr(auxBar2FooFixupAddr, 8)
273 if enableLogging:
274 print "auxBar2FooNextFixupAddr: " + auxBar2FooNextFixupAddr
275 assert kernel_cache.dictionary()["dylibs"][1]["fixups"][auxBar2FooNextFixupAddr] == "kc(0) + " + kernelClassUsed0VMOffset
276
277 # Then we should have foo1Used0() from Foo2 as it overrides it from Foo1
278 auxBar2FooNextFixupAddr = offsetVMAddr(auxBar2FooFixupAddr, 16)
279 if enableLogging:
280 print "auxBar2FooNextFixupAddr: " + auxBar2FooNextFixupAddr
281 assert kernel_cache.dictionary()["dylibs"][1]["fixups"][auxBar2FooNextFixupAddr] == "kc(1) + " + pageableFoo2FooUsed0VMAddr
282
283 # And then foo1Used1()
284 auxBar2FooNextFixupAddr = offsetVMAddr(auxBar2FooFixupAddr, 24)
285 if enableLogging:
286 print "auxBar2FooNextFixupAddr: " + auxBar2FooNextFixupAddr
287 assert kernel_cache.dictionary()["dylibs"][1]["fixups"][auxBar2FooNextFixupAddr] == "kc(1) + " + pageableFoo1FooUsed1VMAddr
288
289 # [~]> xcrun -sdk macosx.internal cc -arch x86_64 -Wl,-static -mkernel -nostdlib -Wl,-e,__start -Wl,-pie main.cpp kernel.cpp -Wl,-pagezero_size,0x0 -o main.kernel -Wl,-image_base,0x10000 -Wl,-segaddr,__HIB,0x4000 -Wl,-add_split_seg_info -Wl,-install_name,/usr/lib/swift/split.seg.v2.hack -iwithsysroot /System/Library/Frameworks/Kernel.framework/Headers -Wl,-sectcreate,__LINKINFO,__symbolsets,SymbolSets.plist -Wl,-segprot,__LINKINFO,r--,r-- -std=c++11 -DKERNEL_USED=1 -Wl,-exported_symbol,__ZN1X11KernelClass10gMetaClassE -Wl,-exported_symbol,__ZN8OSObject10gMetaClassE -Wl,-exported_symbol,__ZNK11OSMetaClass19instanceConstructedEv
290 # [~]> xcrun -sdk macosx.internal cc -arch x86_64 -Wl,-kext -mkernel -nostdlib -Wl,-add_split_seg_info -Wl,-no_data_const foo1.cpp -o extensions/foo1.kext/foo1 -iwithsysroot /System/Library/Frameworks/Kernel.framework/Headers -std=c++11 -DFOO1_USED0=1 -DFOO1_USED1=1 -Wl,-exported_symbol,__ZN1X4Foo110gMetaClassE -Wl,-exported_symbol,__ZN1X4Foo1C2EPK11OSMetaClass -Wl,-exported_symbol,__ZTVN1X4Foo1E -Wl,-exported_symbol,__ZN1X4Foo1D2Ev
291 # [~]> xcrun -sdk macosx.internal cc -arch x86_64 -Wl,-kext -mkernel -nostdlib -Wl,-add_split_seg_info -Wl,-no_data_const foo2.cpp -o extensions/foo2.kext/foo2 -iwithsysroot /System/Library/Frameworks/Kernel.framework/Headers -std=c++11 -DFOO1_USED0=1 -Wl,-exported_symbol,__ZN1X4Foo210gMetaClassE -Wl,-exported_symbol,__ZN1X4Foo2C2EPK11OSMetaClass -Wl,-exported_symbol,__ZTVN1X4Foo2E -Wl,-exported_symbol,__ZN1X4Foo2D2Ev
292 # [~]> xcrun -sdk macosx.internal cc -arch x86_64 -Wl,-kext -mkernel -nostdlib -Wl,-add_split_seg_info -Wl,-data_const bar1.cpp -o extensions/bar1.kext/bar1 -iwithsysroot /System/Library/Frameworks/Kernel.framework/Headers -std=c++11 -DFOO1_USED0=1 -Wl,-exported_symbol,__ZN1X4Bar110gMetaClassE -Wl,-exported_symbol,__ZN1X4Bar1C2EPK11OSMetaClass -Wl,-exported_symbol,__ZTVN1X4Bar1E -Wl,-exported_symbol,__ZN1X4Bar1D2Ev
293 # [~]> xcrun -sdk macosx.internal cc -arch x86_64 -Wl,-kext -mkernel -nostdlib -Wl,-add_split_seg_info -Wl,-data_const bar2.cpp -o extensions/bar2.kext/bar2 -iwithsysroot /System/Library/Frameworks/Kernel.framework/Headers -std=c++11 -DFOO1_USED0=1
294