VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/darwin/mach_kernel-r0drv-darwin.cpp@ 37565

Last change on this file since 37565 was 37565, checked in by vboxsync, 14 years ago

mach_kernel-r0drv-darwin.cpp: Added a bunch of known symbols.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.8 KB
Line 
1/* $Id: mach_kernel-r0drv-darwin.cpp 37565 2011-06-20 23:19:48Z vboxsync $ */
2/** @file
3 * IPRT - mach_kernel symbol resolving hack, R0 Driver, Darwin.
4 */
5
6/*
7 * Copyright (C) 2011 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#ifdef IN_RING0
32# include "the-darwin-kernel.h"
33# include <sys/kauth.h>
34RT_C_DECLS_BEGIN /* Buggy 10.4 headers, fixed in 10.5. */
35# include <sys/kpi_mbuf.h>
36# include <net/kpi_interfacefilter.h>
37RT_C_DECLS_END
38#endif
39#include "../../include/internal/iprt.h"
40
41#include <iprt/asm.h>
42#include <iprt/assert.h>
43#include <iprt/err.h>
44#include <iprt/assert.h>
45#include <iprt/file.h>
46#include <iprt/log.h>
47#include <iprt/mem.h>
48#include <iprt/string.h>
49#include "../../include/internal/ldrMach-O.h"
50
51/** @def MY_CPU_TYPE
52 * The CPU type targeted by the compiler. */
53/** @def MY_CPU_TYPE
54 * The "ALL" CPU subtype targeted by the compiler. */
55/** @def MY_MACHO_HEADER
56 * The Mach-O header targeted by the compiler. */
57/** @def MY_MACHO_MAGIC
58 * The Mach-O header magic we're targeting. */
59/** @def MY_SEGMENT_COMMAND
60 * The segment command targeted by the compiler. */
61/** @def MY_SECTION
62 * The section struture targeted by the compiler. */
63/** @def MY_NLIST
64 * The symbol table entry targeted by the compiler. */
65#ifdef RT_ARCH_X86
66# define MY_CPU_TYPE CPU_TYPE_I386
67# define MY_CPU_SUBTYPE_ALL CPU_SUBTYPE_I386_ALL
68# define MY_MACHO_HEADER mach_header_32_t
69# define MY_MACHO_MAGIC IMAGE_MACHO32_SIGNATURE
70# define MY_SEGMENT_COMMAND segment_command_32_t
71# define MY_SECTION section_32_t
72# define MY_NLIST macho_nlist_32_t
73
74#elif defined(RT_ARCH_AMD64)
75# define MY_CPU_TYPE CPU_TYPE_X86_64
76# define MY_CPU_SUBTYPE_ALL CPU_SUBTYPE_X86_64_ALL
77# define MY_MACHO_HEADER mach_header_64_t
78# define MY_MACHO_MAGIC IMAGE_MACHO64_SIGNATURE
79# define MY_SEGMENT_COMMAND segment_command_64_t
80# define MY_SECTION section_64_t
81# define MY_NLIST macho_nlist_64_t
82
83#else
84# error "Port me!"
85#endif
86
87/** @name Return macros for make it simpler to track down too paranoid code.
88 * @{
89 */
90#ifdef DEBUG
91# define RETURN_VERR_BAD_EXE_FORMAT \
92 do { Assert(!g_fBreakpointOnError); return VERR_BAD_EXE_FORMAT; } while (0)
93# define RETURN_VERR_LDR_UNEXPECTED \
94 do { Assert(!g_fBreakpointOnError); return VERR_LDR_UNEXPECTED; } while (0)
95# define RETURN_VERR_LDR_ARCH_MISMATCH \
96 do { Assert(!g_fBreakpointOnError); return VERR_LDR_ARCH_MISMATCH; } while (0)
97#else
98# define RETURN_VERR_BAD_EXE_FORMAT do { return VERR_BAD_EXE_FORMAT; } while (0)
99# define RETURN_VERR_LDR_UNEXPECTED do { return VERR_LDR_UNEXPECTED; } while (0)
100# define RETURN_VERR_LDR_ARCH_MISMATCH do { return VERR_LDR_ARCH_MISMATCH; } while (0)
101#endif
102/** @} */
103
104#define VERR_LDR_UNEXPECTED (-641)
105
106
107/*******************************************************************************
108* Structures and Typedefs *
109*******************************************************************************/
110/**
111 * Our internal representation of the mach_kernel after loading it's symbols
112 * and successfully resolving their addresses.
113 */
114typedef struct RTR0DARWINKERNEL
115{
116 /** @name Result.
117 * @{ */
118 /** Pointer to the string table. */
119 char *pachStrTab;
120 /** The size of the string table. */
121 uint32_t cbStrTab;
122 /** The file offset of the string table. */
123 uint32_t offStrTab;
124 /** Pointer to the symbol table. */
125 MY_NLIST *paSyms;
126 /** The size of the symbol table. */
127 uint32_t cSyms;
128 /** The file offset of the symbol table. */
129 uint32_t offSyms;
130 /** @} */
131
132 /** @name Used during loading.
133 * @{ */
134 /** The file handle. */
135 RTFILE hFile;
136 /** The architecture image offset (fat_arch_t::offset). */
137 uint64_t offArch;
138 /** The architecture image size (fat_arch_t::size). */
139 uint32_t cbArch;
140 /** The number of load commands (mach_header_XX_t::ncmds). */
141 uint32_t cLoadCmds;
142 /** The size of the load commands. */
143 uint32_t cbLoadCmds;
144 /** The load commands. */
145 load_command_t *pLoadCmds;
146 /** Section pointer table (points into the load commands). */
147 MY_SECTION const *apSections[MACHO_MAX_SECT];
148 /** The number of sections. */
149 uint32_t cSections;
150 /** @} */
151
152 /** Buffer space. */
153 char abBuf[_4K];
154} RTR0DARWINKERNEL;
155typedef RTR0DARWINKERNEL *PRTR0DARWINKERNEL;
156
157
158/*******************************************************************************
159* Structures and Typedefs *
160*******************************************************************************/
161#ifdef DEBUG
162static bool g_fBreakpointOnError = true;
163#endif
164
165
166/**
167 * Frees up the internal scratch data when done looking up symbols.
168 *
169 * @param pKernel The internal scratch data.
170 */
171static void rtR0DarwinMachKernelClose(PRTR0DARWINKERNEL pKernel)
172{
173 RTMemFree(pKernel->pachStrTab);
174 pKernel->pachStrTab = NULL;
175 RTMemFree(pKernel->paSyms);
176 pKernel->paSyms = NULL;
177
178 RTMemFree(pKernel);
179}
180
181
182/**
183 * Close and free up resources we no longer needs.
184 *
185 * @param pKernel The internal scratch data.
186 */
187static void rtR0DarwinMachKernelLoadDone(PRTR0DARWINKERNEL pKernel)
188{
189 RTFileClose(pKernel->hFile);
190 pKernel->hFile = NIL_RTFILE;
191
192 RTMemFree(pKernel->pLoadCmds);
193 pKernel->pLoadCmds = NULL;
194 RT_ZERO(pKernel->apSections);
195}
196
197
198/**
199 * Looks up a kernel symbol.
200 *
201 *
202 * @returns The symbol address on success, 0 on failure.
203 * @param pKernel The internal scratch data.
204 * @param pszSymbol The symbol to resolve. Automatically prefixed
205 * with an underscore.
206 */
207static uintptr_t rtR0DarwinMachKernelLookup(PRTR0DARWINKERNEL pKernel, const char *pszSymbol)
208{
209 uint32_t const cSyms = pKernel->cSyms;
210 MY_NLIST const *pSym = pKernel->paSyms;
211
212#if 1
213 /* linear search. */
214 for (uint32_t iSym = 0; iSym < cSyms; iSym++, pSym++)
215 {
216 if (pSym->n_type & MACHO_N_STAB)
217 continue;
218
219 const char *pszTabName= &pKernel->pachStrTab[(uint32_t)pSym->n_un.n_strx];
220 if ( *pszTabName == '_'
221 && strcmp(pszTabName + 1, pszSymbol) == 0)
222 return pSym->n_value;
223 }
224#else
225 /** @todo binary search. */
226
227#endif
228 return 0;
229}
230
231
232extern "C" void ev_try_lock(void);
233extern "C" void OSMalloc(void);
234extern "C" void OSlibkernInit(void);
235extern "C" int osrelease;
236extern "C" int ostype;
237extern "C" void kdp_set_interface(void);
238
239static int rtR0DarwinMachKernelCheckStandardSymbols(PRTR0DARWINKERNEL pKernel)
240{
241 static struct
242 {
243 const char *pszName;
244 uintptr_t uAddr;
245 } const s_aStandardCandles[] =
246 {
247#ifdef IN_RING0
248# define KNOWN_ENTRY(a_Sym) { #a_Sym, (uintptr_t)&a_Sym }
249#else
250# define KNOWN_ENTRY(a_Sym) { #a_Sym, 0 }
251#endif
252 /* IOKit: */
253 KNOWN_ENTRY(IOMalloc),
254 KNOWN_ENTRY(IOFree),
255 KNOWN_ENTRY(IOSleep),
256 KNOWN_ENTRY(IORWLockAlloc),
257 KNOWN_ENTRY(IORecursiveLockLock),
258 KNOWN_ENTRY(IOSimpleLockAlloc),
259 KNOWN_ENTRY(PE_cpu_halt),
260 KNOWN_ENTRY(gIOKitDebug),
261 KNOWN_ENTRY(gIOServicePlane),
262 KNOWN_ENTRY(ev_try_lock),
263
264 /* Libkern: */
265 KNOWN_ENTRY(OSAddAtomic),
266 KNOWN_ENTRY(OSBitAndAtomic),
267 KNOWN_ENTRY(OSBitOrAtomic),
268 KNOWN_ENTRY(OSBitXorAtomic),
269 KNOWN_ENTRY(OSCompareAndSwap),
270 KNOWN_ENTRY(OSMalloc),
271 KNOWN_ENTRY(OSlibkernInit),
272 KNOWN_ENTRY(bcmp),
273 KNOWN_ENTRY(copyout),
274 KNOWN_ENTRY(copyin),
275 KNOWN_ENTRY(kprintf),
276 KNOWN_ENTRY(printf),
277 KNOWN_ENTRY(lck_grp_alloc_init),
278 KNOWN_ENTRY(lck_mtx_alloc_init),
279 KNOWN_ENTRY(lck_rw_alloc_init),
280 KNOWN_ENTRY(lck_spin_alloc_init),
281 KNOWN_ENTRY(osrelease),
282 KNOWN_ENTRY(ostype),
283 KNOWN_ENTRY(panic),
284 KNOWN_ENTRY(strprefix),
285 KNOWN_ENTRY(sysctlbyname),
286 KNOWN_ENTRY(vsscanf),
287 KNOWN_ENTRY(page_mask),
288
289 /* Mach: */
290 KNOWN_ENTRY(absolutetime_to_nanoseconds),
291 KNOWN_ENTRY(assert_wait),
292 KNOWN_ENTRY(clock_delay_until),
293 KNOWN_ENTRY(clock_get_uptime),
294 KNOWN_ENTRY(current_task),
295 KNOWN_ENTRY(current_thread),
296 KNOWN_ENTRY(kernel_task),
297 KNOWN_ENTRY(lck_mtx_sleep),
298 KNOWN_ENTRY(lck_rw_sleep),
299 KNOWN_ENTRY(lck_spin_sleep),
300 KNOWN_ENTRY(mach_absolute_time),
301 KNOWN_ENTRY(semaphore_create),
302 KNOWN_ENTRY(task_reference),
303 KNOWN_ENTRY(thread_block),
304 KNOWN_ENTRY(thread_reference),
305 KNOWN_ENTRY(thread_terminate),
306 KNOWN_ENTRY(thread_wakeup_prim),
307
308 /* BSDKernel: */
309 //KNOWN_ENTRY(buf_size),
310 KNOWN_ENTRY(copystr),
311 //KNOWN_ENTRY(current_proc),
312 KNOWN_ENTRY(ifnet_hdrlen),
313 KNOWN_ENTRY(ifnet_set_promiscuous),
314 KNOWN_ENTRY(kauth_getuid),
315#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
316 KNOWN_ENTRY(kauth_cred_unref),
317#else
318 KNOWN_ENTRY(kauth_cred_rele),
319#endif
320 //KNOWN_ENTRY(mbuf_data),
321 KNOWN_ENTRY(msleep),
322 KNOWN_ENTRY(nanotime),
323 //KNOWN_ENTRY(nop_close),
324 KNOWN_ENTRY(proc_pid),
325 //KNOWN_ENTRY(sock_accept),
326 //KNOWN_ENTRY(sockopt_name),
327 //KNOWN_ENTRY(spec_write),
328 //KNOWN_ENTRY(suword),
329 //KNOWN_ENTRY(sysctl_int),
330 KNOWN_ENTRY(uio_rw),
331 //KNOWN_ENTRY(vfs_flags),
332 //KNOWN_ENTRY(vfs_name),
333 //KNOWN_ENTRY(vfs_statfs),
334 //KNOWN_ENTRY(vn_rdwr),
335 //KNOWN_ENTRY(vnode_get),
336 //KNOWN_ENTRY(vnode_open),
337 //KNOWN_ENTRY(vnode_ref),
338 //KNOWN_ENTRY(vnode_rele),
339 //KNOWN_ENTRY(vnop_close_desc),
340 KNOWN_ENTRY(wakeup),
341 KNOWN_ENTRY(wakeup_one),
342
343 /* Unsupported: */
344 KNOWN_ENTRY(kdp_set_interface),
345 KNOWN_ENTRY(pmap_find_phys),
346 KNOWN_ENTRY(vm_map),
347 KNOWN_ENTRY(vm_protect),
348 KNOWN_ENTRY(vm_region),
349 KNOWN_ENTRY(vm_map_wire),
350 KNOWN_ENTRY(PE_kputc),
351 };
352
353 for (unsigned i = 0; i < RT_ELEMENTS(s_aStandardCandles); i++)
354 {
355 uintptr_t uAddr = rtR0DarwinMachKernelLookup(pKernel, s_aStandardCandles[i].pszName);
356#ifdef IN_RING0
357 if (uAddr != s_aStandardCandles[i].uAddr)
358#else
359 if (uAddr == 0)
360#endif
361 {
362 AssertLogRelMsgFailed(("%s (%p != %p)\n", s_aStandardCandles[i].pszName, uAddr, s_aStandardCandles[i].uAddr));
363 return VERR_INTERNAL_ERROR_2;
364 }
365 }
366 return VINF_SUCCESS;
367}
368
369
370/**
371 * Loads and validates the symbol and string tables.
372 *
373 * @returns IPRT status code.
374 * @param pKernel The internal scratch data.
375 */
376static int rtR0DarwinMachKernelLoadSymTab(PRTR0DARWINKERNEL pKernel)
377{
378 /*
379 * Load the tables.
380 */
381 pKernel->paSyms = (MY_NLIST *)RTMemAllocZ(pKernel->cSyms * sizeof(MY_NLIST));
382 if (!pKernel->paSyms)
383 return VERR_NO_MEMORY;
384
385 int rc = RTFileReadAt(pKernel->hFile, pKernel->offArch + pKernel->offSyms,
386 pKernel->paSyms, pKernel->cSyms * sizeof(MY_NLIST), NULL);
387 if (RT_FAILURE(rc))
388 return rc;
389
390 pKernel->pachStrTab = (char *)RTMemAllocZ(pKernel->cbStrTab + 1);
391 if (!pKernel->pachStrTab)
392 return VERR_NO_MEMORY;
393
394 rc = RTFileReadAt(pKernel->hFile, pKernel->offArch + pKernel->offStrTab,
395 pKernel->pachStrTab, pKernel->cbStrTab, NULL);
396 if (RT_FAILURE(rc))
397 return rc;
398
399 /*
400 * The first string table symbol must be a zero length name.
401 */
402 if (pKernel->pachStrTab[0] != '\0')
403 RETURN_VERR_BAD_EXE_FORMAT;
404
405 /*
406 * Validate the symbol table.
407 */
408 const char *pszPrev = "";
409 uint32_t const cSyms = pKernel->cSyms;
410 MY_NLIST const *pSym = pKernel->paSyms;
411 for (uint32_t iSym = 0; iSym < cSyms; iSym++, pSym++)
412 {
413 if ((uint32_t)pSym->n_un.n_strx >= pKernel->cbStrTab)
414 RETURN_VERR_BAD_EXE_FORMAT;
415 const char *pszSym = &pKernel->pachStrTab[(uint32_t)pSym->n_un.n_strx];
416#ifdef IN_RING3
417 RTAssertMsg2("%05i: %02x:%08x %02x %04x %s\n", iSym, pSym->n_sect, pSym->n_value, pSym->n_type, pSym->n_desc, pszSym);
418#endif
419
420 if (strcmp(pszSym, pszPrev) < 0)
421 RETURN_VERR_BAD_EXE_FORMAT; /* not sorted */
422
423 if (!(pSym->n_type & MACHO_N_STAB))
424 {
425 switch (pSym->n_type & MACHO_N_TYPE)
426 {
427 case MACHO_N_SECT:
428 if (pSym->n_sect == MACHO_NO_SECT)
429 RETURN_VERR_BAD_EXE_FORMAT;
430 if (pSym->n_sect > pKernel->cSections)
431 RETURN_VERR_BAD_EXE_FORMAT;
432 if (pSym->n_desc & ~(REFERENCED_DYNAMICALLY))
433 RETURN_VERR_BAD_EXE_FORMAT;
434 if (pSym->n_value < pKernel->apSections[pSym->n_sect - 1]->addr)
435 RETURN_VERR_BAD_EXE_FORMAT;
436 if ( pSym->n_value - pKernel->apSections[pSym->n_sect - 1]->addr
437 > pKernel->apSections[pSym->n_sect - 1]->size)
438 RETURN_VERR_BAD_EXE_FORMAT;
439 break;
440
441 case MACHO_N_ABS:
442#if 0 /* Spec say MACHO_NO_SECT, __mh_execute_header has 1 with 10.7/amd64 */
443 if (pSym->n_sect != MACHO_NO_SECT)
444#else
445 if (pSym->n_sect > pKernel->cSections)
446#endif
447 RETURN_VERR_BAD_EXE_FORMAT;
448 if (pSym->n_desc & ~(REFERENCED_DYNAMICALLY))
449 RETURN_VERR_BAD_EXE_FORMAT;
450 break;
451
452 case MACHO_N_UNDF:
453 /* No undefined or common symbols in the kernel. */
454 RETURN_VERR_BAD_EXE_FORMAT;
455
456 case MACHO_N_INDR:
457 /* No indirect symbols in the kernel. */
458 RETURN_VERR_BAD_EXE_FORMAT;
459
460 case MACHO_N_PBUD:
461 /* No prebound symbols in the kernel. */
462 RETURN_VERR_BAD_EXE_FORMAT;
463
464 default:
465 RETURN_VERR_BAD_EXE_FORMAT;
466 }
467 }
468 /* else: Ignore debug symbols. */
469 }
470
471 return VINF_SUCCESS;
472}
473
474
475/**
476 * Loads the load commands and validates them.
477 *
478 * @returns IPRT status code.
479 * @param pKernel The internal scratch data.
480 */
481static int rtR0DarwinMachKernelLoadCommands(PRTR0DARWINKERNEL pKernel)
482{
483 pKernel->offStrTab = 0;
484 pKernel->cbStrTab = 0;
485 pKernel->offSyms = 0;
486 pKernel->cSyms = 0;
487 pKernel->cSections = 0;
488
489 pKernel->pLoadCmds = (load_command_t *)RTMemAlloc(pKernel->cbLoadCmds);
490 if (!pKernel->pLoadCmds)
491 return VERR_NO_MEMORY;
492
493 int rc = RTFileReadAt(pKernel->hFile, pKernel->offArch + sizeof(MY_MACHO_HEADER),
494 pKernel->pLoadCmds, pKernel->cbLoadCmds, NULL);
495 if (RT_FAILURE(rc))
496 return rc;
497
498 /*
499 * Validate the relevant commands, picking up sections and the symbol
500 * table location.
501 */
502 load_command_t const *pCmd = pKernel->pLoadCmds;
503 for (uint32_t iCmd = 0; ; iCmd++)
504 {
505 /* cmd index & offset. */
506 uintptr_t offCmd = (uintptr_t)pCmd - (uintptr_t)pKernel->pLoadCmds;
507 if (offCmd == pKernel->cbLoadCmds && iCmd == pKernel->cLoadCmds)
508 break;
509 if (offCmd + sizeof(*pCmd) > pKernel->cbLoadCmds)
510 RETURN_VERR_BAD_EXE_FORMAT;
511 if (iCmd >= pKernel->cLoadCmds)
512 RETURN_VERR_BAD_EXE_FORMAT;
513
514 /* cmdsize */
515 if (pCmd->cmdsize < sizeof(*pCmd))
516 RETURN_VERR_BAD_EXE_FORMAT;
517 if (pCmd->cmdsize > pKernel->cbLoadCmds)
518 RETURN_VERR_BAD_EXE_FORMAT;
519 if (RT_ALIGN_32(pCmd->cmdsize, 4) != pCmd->cmdsize)
520 RETURN_VERR_BAD_EXE_FORMAT;
521
522 /* cmd */
523 switch (pCmd->cmd & ~LC_REQ_DYLD)
524 {
525 /* Validate and store the symbol table details. */
526 case LC_SYMTAB:
527 {
528 struct symtab_command const *pSymTab = (struct symtab_command const *)pCmd;
529 if (pSymTab->cmdsize != sizeof(*pSymTab))
530 RETURN_VERR_BAD_EXE_FORMAT;
531 if (pSymTab->nsyms > _1M)
532 RETURN_VERR_BAD_EXE_FORMAT;
533 if (pSymTab->strsize > _2M)
534 RETURN_VERR_BAD_EXE_FORMAT;
535
536 pKernel->offStrTab = pSymTab->stroff;
537 pKernel->cbStrTab = pSymTab->strsize;
538 pKernel->offSyms = pSymTab->symoff;
539 pKernel->cSyms = pSymTab->nsyms;
540 break;
541 }
542
543 /* Validate the segment. */
544#if ARCH_BITS == 32
545 case LC_SEGMENT_32:
546#elif ARCH_BITS == 64
547 case LC_SEGMENT_64:
548#else
549# error ARCH_BITS
550#endif
551 {
552 MY_SEGMENT_COMMAND const *pSeg = (MY_SEGMENT_COMMAND const *)pCmd;
553 if (pSeg->cmdsize < sizeof(*pSeg))
554 RETURN_VERR_BAD_EXE_FORMAT;
555
556 if (pSeg->segname[0] == '\0')
557 RETURN_VERR_BAD_EXE_FORMAT;
558
559 if (pSeg->nsects > MACHO_MAX_SECT)
560 RETURN_VERR_BAD_EXE_FORMAT;
561 if (pSeg->nsects * sizeof(MY_SECTION) + sizeof(*pSeg) != pSeg->cmdsize)
562 RETURN_VERR_BAD_EXE_FORMAT;
563
564 if (pSeg->flags & ~(SG_HIGHVM | SG_FVMLIB | SG_NORELOC | SG_PROTECTED_VERSION_1))
565 RETURN_VERR_BAD_EXE_FORMAT;
566
567 if (pSeg->vmaddr != 0)
568 {
569 if (pSeg->vmaddr + RT_ALIGN_Z(pSeg->vmsize, RT_BIT_32(12)) < pSeg->vmaddr)
570 RETURN_VERR_BAD_EXE_FORMAT;
571 }
572 else if (pSeg->vmsize)
573 RETURN_VERR_BAD_EXE_FORMAT;
574
575 if (pSeg->maxprot & ~VM_PROT_ALL)
576 RETURN_VERR_BAD_EXE_FORMAT;
577 if (pSeg->initprot & ~VM_PROT_ALL)
578 RETURN_VERR_BAD_EXE_FORMAT;
579
580 /* Validate the sections. */
581 uint32_t uAlignment = 0;
582 uintptr_t uAddr = pSeg->vmaddr;
583 MY_SECTION const *paSects = (MY_SECTION const *)(pSeg + 1);
584 for (uint32_t i = 0; i < pSeg->nsects; i++)
585 {
586 if (paSects[i].sectname[0] == '\0')
587 RETURN_VERR_BAD_EXE_FORMAT;
588 if (memcmp(paSects[i].segname, pSeg->segname, sizeof(pSeg->segname)))
589 RETURN_VERR_BAD_EXE_FORMAT;
590
591 switch (paSects[i].flags & SECTION_TYPE)
592 {
593 case S_REGULAR:
594 case S_CSTRING_LITERALS:
595 case S_NON_LAZY_SYMBOL_POINTERS:
596 case S_MOD_INIT_FUNC_POINTERS:
597 case S_MOD_TERM_FUNC_POINTERS:
598 case S_COALESCED:
599 if ( pSeg->filesize != 0
600 ? paSects[i].offset - pSeg->fileoff >= pSeg->filesize
601 : paSects[i].offset - pSeg->fileoff != pSeg->filesize)
602 RETURN_VERR_BAD_EXE_FORMAT;
603 if ( paSects[i].addr != 0
604 && paSects[i].offset - pSeg->fileoff != paSects[i].addr - pSeg->vmaddr)
605 RETURN_VERR_BAD_EXE_FORMAT;
606 break;
607
608 case S_ZEROFILL:
609 if (paSects[i].offset != 0)
610 RETURN_VERR_BAD_EXE_FORMAT;
611 break;
612
613 /* not observed */
614 case S_SYMBOL_STUBS:
615 case S_INTERPOSING:
616 case S_4BYTE_LITERALS:
617 case S_8BYTE_LITERALS:
618 case S_16BYTE_LITERALS:
619 case S_DTRACE_DOF:
620 case S_LAZY_SYMBOL_POINTERS:
621 case S_LAZY_DYLIB_SYMBOL_POINTERS:
622 RETURN_VERR_LDR_UNEXPECTED;
623 case S_GB_ZEROFILL:
624 RETURN_VERR_LDR_UNEXPECTED;
625 default:
626 RETURN_VERR_BAD_EXE_FORMAT;
627 }
628
629 if (paSects[i].align > 12)
630 RETURN_VERR_BAD_EXE_FORMAT;
631 if (paSects[i].align > uAlignment)
632 uAlignment = paSects[i].align;
633
634 /* Add to the section table. */
635 if (pKernel->cSections == MACHO_MAX_SECT)
636 RETURN_VERR_BAD_EXE_FORMAT;
637 pKernel->apSections[pKernel->cSections++] = &paSects[i];
638 }
639
640 if (RT_ALIGN_Z(pSeg->vmaddr, RT_BIT_32(uAlignment)) != pSeg->vmaddr)
641 RETURN_VERR_BAD_EXE_FORMAT;
642 if ( pSeg->filesize > RT_ALIGN_Z(pSeg->vmsize, RT_BIT_32(uAlignment))
643 && pSeg->vmsize != 0)
644 RETURN_VERR_BAD_EXE_FORMAT;
645 break;
646 }
647
648 case LC_UUID:
649 if (pCmd->cmdsize != sizeof(uuid_command))
650 RETURN_VERR_BAD_EXE_FORMAT;
651 break;
652
653 case LC_DYSYMTAB:
654 case LC_UNIXTHREAD:
655 break;
656
657 /* not observed */
658 case LC_SYMSEG:
659#if ARCH_BITS == 32
660 case LC_SEGMENT_64:
661#elif ARCH_BITS == 64
662 case LC_SEGMENT_32:
663#endif
664 case LC_ROUTINES_64:
665 case LC_ROUTINES:
666 case LC_THREAD:
667 case LC_LOADFVMLIB:
668 case LC_IDFVMLIB:
669 case LC_IDENT:
670 case LC_FVMFILE:
671 case LC_PREPAGE:
672 case LC_TWOLEVEL_HINTS:
673 case LC_PREBIND_CKSUM:
674 RETURN_VERR_LDR_UNEXPECTED;
675
676 /* dylib */
677 case LC_LOAD_DYLIB:
678 case LC_ID_DYLIB:
679 case LC_LOAD_DYLINKER:
680 case LC_ID_DYLINKER:
681 case LC_PREBOUND_DYLIB:
682 case LC_LOAD_WEAK_DYLIB & ~LC_REQ_DYLD:
683 case LC_SUB_FRAMEWORK:
684 case LC_SUB_UMBRELLA:
685 case LC_SUB_CLIENT:
686 case LC_SUB_LIBRARY:
687 RETURN_VERR_LDR_UNEXPECTED;
688
689 default:
690 RETURN_VERR_BAD_EXE_FORMAT;
691 }
692
693 /* next */
694 pCmd = (load_command_t *)((uintptr_t)pCmd + pCmd->cmdsize);
695 }
696
697 return VINF_SUCCESS;
698}
699
700
701/**
702 * Loads the FAT and MACHO headers, noting down the relevant info.
703 *
704 * @returns IPRT status code.
705 * @param pKernel The internal scratch data.
706 */
707static int rtR0DarwinMachKernelLoadFileHeaders(PRTR0DARWINKERNEL pKernel)
708{
709 uint32_t i;
710
711 pKernel->offArch = 0;
712 pKernel->cbArch = 0;
713
714 /*
715 * Read the first bit of the file, parse the FAT if found there.
716 */
717 int rc = RTFileReadAt(pKernel->hFile, 0, pKernel->abBuf, sizeof(fat_header_t) + sizeof(fat_arch_t) * 16, NULL);
718 if (RT_FAILURE(rc))
719 return rc;
720
721 fat_header_t *pFat = (fat_header *)pKernel->abBuf;
722 fat_arch_t *paFatArches = (fat_arch_t *)(pFat + 1);
723
724 /* Correct FAT endian first. */
725 if (pFat->magic == IMAGE_FAT_SIGNATURE_OE)
726 {
727 pFat->magic = RT_BSWAP_U32(pFat->magic);
728 pFat->nfat_arch = RT_BSWAP_U32(pFat->nfat_arch);
729 i = RT_MIN(pFat->nfat_arch, 16);
730 while (i-- > 0)
731 {
732 paFatArches[i].cputype = RT_BSWAP_U32(paFatArches[i].cputype);
733 paFatArches[i].cpusubtype = RT_BSWAP_U32(paFatArches[i].cpusubtype);
734 paFatArches[i].offset = RT_BSWAP_U32(paFatArches[i].offset);
735 paFatArches[i].size = RT_BSWAP_U32(paFatArches[i].size);
736 paFatArches[i].align = RT_BSWAP_U32(paFatArches[i].align);
737 }
738 }
739
740 /* Lookup our architecture in the FAT. */
741 if (pFat->magic == IMAGE_FAT_SIGNATURE)
742 {
743 if (pFat->nfat_arch > 16)
744 RETURN_VERR_BAD_EXE_FORMAT;
745
746 for (i = 0; i < pFat->nfat_arch; i++)
747 {
748 if ( paFatArches[i].cputype == MY_CPU_TYPE
749 && paFatArches[i].cpusubtype == MY_CPU_SUBTYPE_ALL)
750 {
751 pKernel->offArch = paFatArches[i].offset;
752 pKernel->cbArch = paFatArches[i].size;
753 if (!pKernel->cbArch)
754 RETURN_VERR_BAD_EXE_FORMAT;
755 if (pKernel->offArch < sizeof(fat_header_t) + sizeof(fat_arch_t) * pFat->nfat_arch)
756 RETURN_VERR_BAD_EXE_FORMAT;
757 if (pKernel->offArch + pKernel->cbArch <= pKernel->offArch)
758 RETURN_VERR_LDR_ARCH_MISMATCH;
759 break;
760 }
761 }
762 if (i >= pFat->nfat_arch)
763 RETURN_VERR_LDR_ARCH_MISMATCH;
764 }
765
766 /*
767 * Read the Mach-O header and validate it.
768 */
769 rc = RTFileReadAt(pKernel->hFile, pKernel->offArch, pKernel->abBuf, sizeof(MY_MACHO_HEADER), NULL);
770 if (RT_FAILURE(rc))
771 return rc;
772 MY_MACHO_HEADER const *pHdr = (MY_MACHO_HEADER const *)pKernel->abBuf;
773 if (pHdr->magic != MY_MACHO_MAGIC)
774 {
775 if ( pHdr->magic == IMAGE_MACHO32_SIGNATURE
776 || pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
777 || pHdr->magic == IMAGE_MACHO64_SIGNATURE
778 || pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE)
779 RETURN_VERR_LDR_ARCH_MISMATCH;
780 RETURN_VERR_BAD_EXE_FORMAT;
781 }
782
783 if (pHdr->cputype != MY_CPU_TYPE)
784 RETURN_VERR_LDR_ARCH_MISMATCH;
785 if (pHdr->cpusubtype != MY_CPU_SUBTYPE_ALL)
786 RETURN_VERR_LDR_ARCH_MISMATCH;
787 if (pHdr->filetype != MH_EXECUTE)
788 RETURN_VERR_LDR_UNEXPECTED;
789 if (pHdr->ncmds < 4)
790 RETURN_VERR_LDR_UNEXPECTED;
791 if (pHdr->ncmds > 256)
792 RETURN_VERR_LDR_UNEXPECTED;
793 if (pHdr->sizeofcmds <= pHdr->ncmds * sizeof(load_command_t))
794 RETURN_VERR_LDR_UNEXPECTED;
795 if (pHdr->sizeofcmds >= _1M)
796 RETURN_VERR_LDR_UNEXPECTED;
797 if (pHdr->flags & ~MH_VALID_FLAGS)
798 RETURN_VERR_LDR_UNEXPECTED;
799
800 pKernel->cLoadCmds = pHdr->ncmds;
801 pKernel->cbLoadCmds = pHdr->sizeofcmds;
802 return VINF_SUCCESS;
803}
804
805
806static int rtR0DarwinMachKernelOpen(const char *pszMachKernel, PRTR0DARWINKERNEL *ppHandle)
807{
808 PRTR0DARWINKERNEL pKernel = (PRTR0DARWINKERNEL)RTMemAllocZ(sizeof(*pKernel));
809 if (!pKernel)
810 return VERR_NO_MEMORY;
811 pKernel->hFile = NIL_RTFILE;
812
813 int rc = RTFileOpen(&pKernel->hFile, pszMachKernel, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
814 if (RT_SUCCESS(rc))
815 rc = rtR0DarwinMachKernelLoadFileHeaders(pKernel);
816 if (RT_SUCCESS(rc))
817 rc = rtR0DarwinMachKernelLoadCommands(pKernel);
818 if (RT_SUCCESS(rc))
819 rc = rtR0DarwinMachKernelLoadSymTab(pKernel);
820 if (RT_SUCCESS(rc))
821 rc = rtR0DarwinMachKernelCheckStandardSymbols(pKernel);
822
823 rtR0DarwinMachKernelLoadDone(pKernel);
824 if (RT_FAILURE(rc))
825 rtR0DarwinMachKernelClose(pKernel);
826 return rc;
827}
828
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette