]>
git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/macho++.cpp
2 * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 // macho++ - Mach-O object file helpers
28 #include <security_utilities/alloc.h>
29 #include <security_utilities/memutils.h>
30 #include <security_utilities/endian.h>
31 #include <mach-o/dyld.h>
38 /* Maximum number of archs a fat binary can have */
39 static const int MAX_ARCH_COUNT
= 100;
40 /* Maximum power of 2 that a mach-o can be aligned by */
41 static const int MAX_ALIGN
= 30;
44 // Architecture values
46 Architecture::Architecture(const fat_arch
&arch
)
47 : pair
<cpu_type_t
, cpu_subtype_t
>(arch
.cputype
, arch
.cpusubtype
)
51 Architecture::Architecture(const char *name
)
53 if (const NXArchInfo
*nxa
= NXGetArchInfoFromName(name
)) {
54 this->first
= nxa
->cputype
;
55 this->second
= nxa
->cpusubtype
;
57 this->first
= this->second
= none
;
63 // The local architecture.
65 // We take this from ourselves - the architecture of our main program Mach-O binary.
66 // There's the NXGetLocalArchInfo API, but it insists on saying "i386" on modern
67 // x86_64-centric systems, and lies to ppc (Rosetta) programs claiming they're native ppc.
68 // So let's not use that.
70 Architecture
Architecture::local()
72 return MainMachOImage().architecture();
77 // Translate between names and numbers
79 const char *Architecture::name() const
81 if (const NXArchInfo
*info
= NXGetArchInfoFromCpuType(cpuType(), cpuSubtype()))
87 std::string
Architecture::displayName() const
89 if (const char *s
= this->name())
92 snprintf(buf
, sizeof(buf
), "(%d:%d)", cpuType(), cpuSubtype());
98 // Compare architectures.
99 // This is asymmetrical; the second argument provides for some templating.
101 bool Architecture::matches(const Architecture
&templ
) const
103 if (first
!= templ
.first
)
104 return false; // main architecture mismatch
105 if (templ
.second
== CPU_SUBTYPE_MULTIPLE
)
106 return true; // subtype wildcard
107 // match subtypes, ignoring feature bits
108 return ((second
^ templ
.second
) & ~CPU_SUBTYPE_MASK
) == 0;
113 // MachOBase contains knowledge of the Mach-O object file format,
114 // but abstracts from any particular sourcing. It must be subclassed,
115 // and the subclass must provide the file header and commands area
116 // during its construction. Memory is owned by the subclass.
118 MachOBase::~MachOBase()
121 // provide the Mach-O file header, somehow
122 void MachOBase::initHeader(const mach_header
*header
)
125 switch (mHeader
->magic
) {
143 secdebug("macho", "%p: unrecognized header magic (%x)", this, mHeader
->magic
);
144 UnixError::throwMe(ENOEXEC
);
148 // provide the Mach-O commands section, somehow
149 void MachOBase::initCommands(const load_command
*commands
)
151 mCommands
= commands
;
152 mEndCommands
= LowLevelMemoryUtilities::increment
<load_command
>(commands
, flip(mHeader
->sizeofcmds
));
153 if (mCommands
+ 1 > mEndCommands
) // ensure initial load command core available
154 UnixError::throwMe(ENOEXEC
);
158 size_t MachOBase::headerSize() const
160 return m64
? sizeof(mach_header_64
) : sizeof(mach_header
);
163 size_t MachOBase::commandSize() const
165 return flip(mHeader
->sizeofcmds
);
170 // Create a MachO object from an open file and a starting offset.
171 // We load (only) the header and load commands into memory at that time.
172 // Note that the offset must be relative to the start of the containing file
173 // (not relative to some intermediate container).
175 MachO::MachO(FileDesc fd
, size_t offset
, size_t length
)
176 : FileDesc(fd
), mOffset(offset
), mLength(length
), mSuspicious(false)
179 mLength
= fd
.fileSize();
180 size_t size
= fd
.read(&mHeaderBuffer
, sizeof(mHeaderBuffer
), mOffset
);
181 if (size
!= sizeof(mHeaderBuffer
))
182 UnixError::throwMe(ENOEXEC
);
183 this->initHeader(&mHeaderBuffer
);
184 size_t cmdSize
= this->commandSize();
185 mCommandBuffer
= (load_command
*)malloc(cmdSize
);
187 UnixError::throwMe();
188 if (fd
.read(mCommandBuffer
, cmdSize
, this->headerSize() + mOffset
) != cmdSize
)
189 UnixError::throwMe(ENOEXEC
);
190 this->initCommands(mCommandBuffer
);
191 /* If we do not know the length, we cannot do a verification of the mach-o structure */
193 this->validateStructure();
196 void MachO::validateStructure()
198 bool isValid
= false;
200 /* There should be either an LC_SEGMENT, an LC_SEGMENT_64, or an LC_SYMTAB
201 load_command and that + size must be equal to the end of the arch */
202 for (const struct load_command
*cmd
= loadCommands(); cmd
!= NULL
; cmd
= nextCommand(cmd
)) {
203 uint32_t cmd_type
= flip(cmd
->cmd
);
204 struct segment_command
*seg
= NULL
;
205 struct segment_command_64
*seg64
= NULL
;
206 struct symtab_command
*symtab
= NULL
;
208 if (cmd_type
== LC_SEGMENT
) {
209 seg
= (struct segment_command
*)cmd
;
210 if (strcmp(seg
->segname
, SEG_LINKEDIT
) == 0) {
211 isValid
= flip(seg
->fileoff
) + flip(seg
->filesize
) == this->length();
214 } else if (cmd_type
== LC_SEGMENT_64
) {
215 seg64
= (struct segment_command_64
*)cmd
;
216 if (strcmp(seg64
->segname
, SEG_LINKEDIT
) == 0) {
217 isValid
= flip(seg64
->fileoff
) + flip(seg64
->filesize
) == this->length();
220 /* PPC binaries have a SYMTAB section */
221 } else if (cmd_type
== LC_SYMTAB
) {
222 symtab
= (struct symtab_command
*)cmd
;
223 isValid
= flip(symtab
->stroff
) + flip(symtab
->strsize
) == this->length();
234 ::free(mCommandBuffer
);
239 // Create a MachO object that is (entirely) mapped into memory.
240 // The caller must ensire that the underlying mapping persists
241 // at least as long as our object.
243 MachOImage::MachOImage(const void *address
)
245 this->initHeader((const mach_header
*)address
);
246 this->initCommands(LowLevelMemoryUtilities::increment
<const load_command
>(address
, this->headerSize()));
251 // Locate the Mach-O image of the main program
253 MainMachOImage::MainMachOImage()
254 : MachOImage(mainImageAddress())
258 const void *MainMachOImage::mainImageAddress()
260 return _dyld_get_image_header(0);
265 // Return various header fields
267 Architecture
MachOBase::architecture() const
269 return Architecture(flip(mHeader
->cputype
), flip(mHeader
->cpusubtype
));
272 uint32_t MachOBase::type() const
274 return flip(mHeader
->filetype
);
277 uint32_t MachOBase::flags() const
279 return flip(mHeader
->flags
);
284 // Iterate through load commands
286 const load_command
*MachOBase::nextCommand(const load_command
*command
) const
288 using LowLevelMemoryUtilities::increment
;
289 /* Do not try and increment by 0, or it will loop forever */
290 if (flip(command
->cmdsize
) == 0)
291 UnixError::throwMe(ENOEXEC
);
292 command
= increment
<const load_command
>(command
, flip(command
->cmdsize
));
293 if (command
>= mEndCommands
) // end of load commands
295 if (increment(command
, sizeof(load_command
)) > mEndCommands
296 || increment(command
, flip(command
->cmdsize
)) > mEndCommands
)
297 UnixError::throwMe(ENOEXEC
);
303 // Find a specific load command, by command number.
304 // If there are multiples, returns the first one found.
306 const load_command
*MachOBase::findCommand(uint32_t cmd
) const
308 for (const load_command
*command
= loadCommands(); command
; command
= nextCommand(command
))
309 if (flip(command
->cmd
) == cmd
)
316 // Locate a segment command, by name
318 const segment_command
*MachOBase::findSegment(const char *segname
) const
320 for (const load_command
*command
= loadCommands(); command
; command
= nextCommand(command
)) {
321 switch (flip(command
->cmd
)) {
325 const segment_command
*seg
= reinterpret_cast<const segment_command
*>(command
);
326 if (!strcmp(seg
->segname
, segname
))
337 const section
*MachOBase::findSection(const char *segname
, const char *sectname
) const
339 using LowLevelMemoryUtilities::increment
;
340 if (const segment_command
*seg
= findSegment(segname
)) {
342 const segment_command_64
*seg64
= reinterpret_cast<const segment_command_64
*>(seg
);
343 // As a sanity check, if the reported number of sections is not consistent
344 // with the reported size, return NULL
345 if (sizeof(*seg64
) + (seg64
->nsects
* sizeof(section_64
)) > seg64
->cmdsize
)
347 const section_64
*sect
= increment
<const section_64
>(seg64
+ 1, 0);
348 for (unsigned n
= flip(seg64
->nsects
); n
> 0; n
--, sect
++) {
349 if (!strcmp(sect
->sectname
, sectname
))
350 return reinterpret_cast<const section
*>(sect
);
353 const section
*sect
= increment
<const section
>(seg
+ 1, 0);
354 for (unsigned n
= flip(seg
->nsects
); n
> 0; n
--, sect
++) {
355 if (!strcmp(sect
->sectname
, sectname
))
365 // Translate a union lc_str into the string it denotes.
366 // Returns NULL (no exceptions) if the entry is corrupt.
368 const char *MachOBase::string(const load_command
*cmd
, const lc_str
&str
) const
370 size_t offset
= flip(str
.offset
);
371 const char *sp
= LowLevelMemoryUtilities::increment
<const char>(cmd
, offset
);
372 if (offset
+ strlen(sp
) + 1 > flip(cmd
->cmdsize
)) // corrupt string reference
379 // Figure out where the Code Signing information starts in the Mach-O binary image.
380 // The code signature is at the end of the file, and identified
381 // by a specially-named section. So its starting offset is also the end
382 // of the signable part.
383 // Note that the offset returned is relative to the start of the Mach-O image.
384 // Returns zero if not found (usually indicating that the binary was not signed).
386 const linkedit_data_command
*MachOBase::findCodeSignature() const
388 if (const load_command
*cmd
= findCommand(LC_CODE_SIGNATURE
))
389 return reinterpret_cast<const linkedit_data_command
*>(cmd
);
390 return NULL
; // not found
393 size_t MachOBase::signingOffset() const
395 if (const linkedit_data_command
*lec
= findCodeSignature())
396 return flip(lec
->dataoff
);
401 size_t MachOBase::signingLength() const
403 if (const linkedit_data_command
*lec
= findCodeSignature())
404 return flip(lec
->datasize
);
409 const linkedit_data_command
*MachOBase::findLibraryDependencies() const
411 if (const load_command
*cmd
= findCommand(LC_DYLIB_CODE_SIGN_DRS
))
412 return reinterpret_cast<const linkedit_data_command
*>(cmd
);
413 return NULL
; // not found
418 // Return the signing-limit length for this Mach-O binary image.
419 // This is the signingOffset if present, or the full length if not.
421 size_t MachO::signingExtent() const
423 if (size_t offset
= signingOffset())
433 void MachO::seek(size_t offset
)
435 FileDesc::seek(mOffset
+ offset
);
438 CFDataRef
MachO::dataAt(size_t offset
, size_t size
)
440 CFMallocData
buffer(size
);
441 if (this->read(buffer
, size
, mOffset
+ offset
) != size
)
442 UnixError::throwMe();
447 // Fat (aka universal) file wrappers.
448 // The offset is relative to the start of the containing file.
450 Universal::Universal(FileDesc fd
, size_t offset
/* = 0 */, size_t length
/* = 0 */)
451 : FileDesc(fd
), mBase(offset
), mLength(length
), mMachType(0), mSuspicious(false)
454 fat_header header
; // if this is a fat file
455 mach_header mheader
; // if this is a thin file
457 const size_t size
= max(sizeof(header
), sizeof(mheader
));
458 if (fd
.read(&header
, size
, offset
) != size
)
459 UnixError::throwMe(ENOEXEC
);
460 switch (header
.magic
) {
466 // Under certain circumstances (15001604), mArchCount under-counts the architectures
467 // by one, and special testing is required to validate the extra-curricular entry.
468 // We always read an extra entry; in the situations where this might hit end-of-file,
469 // we are content to fail.
471 mArchCount
= ntohl(header
.nfat_arch
);
473 if (mArchCount
> MAX_ARCH_COUNT
)
474 UnixError::throwMe(ENOEXEC
);
476 size_t archSize
= sizeof(fat_arch
) * (mArchCount
+ 1);
477 mArchList
= (fat_arch
*)malloc(archSize
);
479 UnixError::throwMe();
480 if (fd
.read(mArchList
, archSize
, mBase
+ sizeof(header
)) != archSize
) {
482 UnixError::throwMe(ENOEXEC
);
484 for (fat_arch
*arch
= mArchList
; arch
<= mArchList
+ mArchCount
; arch
++) {
486 n2hi(arch
->cpusubtype
);
491 const fat_arch
*last_arch
= mArchList
+ mArchCount
;
492 if (last_arch
->cputype
== (CPU_ARCH_ABI64
| CPU_TYPE_ARM
)) {
495 secdebug("macho", "%p is a fat file with %d architectures",
498 /* A Mach-O universal file has padding of no more than "page size"
499 * between the header and slices. This padding must be zeroed out or the file
501 std::list
<struct fat_arch
*> sortedList
;
502 for (unsigned i
= 0; i
< mArchCount
; i
++)
503 sortedList
.push_back(mArchList
+ i
);
505 sortedList
.sort(^ bool (const struct fat_arch
*arch1
, const struct fat_arch
*arch2
) { return arch1
->offset
< arch2
->offset
; });
507 const size_t universalHeaderEnd
= mBase
+ sizeof(header
) + (sizeof(fat_arch
) * mArchCount
);
508 size_t prevHeaderEnd
= universalHeaderEnd
;
509 size_t prevArchSize
= 0, prevArchStart
= 0;
511 for (auto iterator
= sortedList
.begin(); iterator
!= sortedList
.end(); ++iterator
) {
512 auto ret
= mSizes
.insert(std::pair
<size_t, size_t>((*iterator
)->offset
, (*iterator
)->size
));
513 if (ret
.second
== false) {
515 MacOSError::throwMe(errSecInternalError
); // Something is wrong if the same size was encountered twice
518 size_t gapSize
= (*iterator
)->offset
- prevHeaderEnd
;
520 /* The size of the padding after the universal cannot be calculated to a fixed size */
521 if (prevHeaderEnd
!= universalHeaderEnd
) {
522 if (((*iterator
)->align
> MAX_ALIGN
) || gapSize
>= (1 << (*iterator
)->align
)) {
528 // validate gap bytes in tasty page-sized chunks
529 CssmAutoPtr
<uint8_t> gapBytes(Allocator::standard().malloc
<uint8_t>(PAGE_SIZE
));
531 while (off
< gapSize
) {
532 size_t want
= min(gapSize
- off
, (size_t)PAGE_SIZE
);
533 size_t got
= fd
.read(gapBytes
, want
, prevHeaderEnd
+ off
);
539 for (size_t x
= 0; x
< got
; x
++) {
540 if (gapBytes
[x
] != 0) {
553 prevHeaderEnd
= (*iterator
)->offset
+ (*iterator
)->size
;
554 prevArchSize
= (*iterator
)->size
;
555 prevArchStart
= (*iterator
)->offset
;
558 /* If there is anything extra at the end of the file, reject this */
559 if (!mSuspicious
&& (prevArchStart
+ prevArchSize
!= fd
.fileSize()))
568 mThinArch
= Architecture(mheader
.cputype
, mheader
.cpusubtype
);
569 secdebug("macho", "%p is a thin file (%s)", this, mThinArch
.name());
575 mThinArch
= Architecture(flip(mheader
.cputype
), flip(mheader
.cpusubtype
));
576 secdebug("macho", "%p is a thin file (%s)", this, mThinArch
.name());
579 UnixError::throwMe(ENOEXEC
);
583 Universal::~Universal()
588 const size_t Universal::lengthOfSlice(size_t offset
) const
590 auto ret
= mSizes
.find(offset
);
591 if (ret
== mSizes
.end())
592 MacOSError::throwMe(errSecInternalError
);
597 // Get the "local" architecture from the fat file
598 // Throws ENOEXEC if not found.
600 MachO
*Universal::architecture() const
603 return findImage(bestNativeArch());
605 return new MachO(*this, mBase
, mLength
);
608 size_t Universal::archOffset() const
611 return mBase
+ findArch(bestNativeArch())->offset
;
618 // Get the specified architecture from the fat file
619 // Throws ENOEXEC if not found.
621 MachO
*Universal::architecture(const Architecture
&arch
) const
624 return findImage(arch
);
625 else if (mThinArch
.matches(arch
))
626 return new MachO(*this, mBase
);
628 UnixError::throwMe(ENOEXEC
);
631 size_t Universal::archOffset(const Architecture
&arch
) const
634 return mBase
+ findArch(arch
)->offset
;
635 else if (mThinArch
.matches(arch
))
638 UnixError::throwMe(ENOEXEC
);
641 size_t Universal::archLength(const Architecture
&arch
) const
644 return mBase
+ findArch(arch
)->size
;
645 else if (mThinArch
.matches(arch
))
646 return this->fileSize();
648 UnixError::throwMe(ENOEXEC
);
652 // Get the architecture at a specified offset from the fat file.
653 // Throws an exception of the offset does not point at a Mach-O image.
655 MachO
*Universal::architecture(size_t offset
) const
658 return make(new MachO(*this, offset
));
659 else if (offset
== mBase
)
660 return new MachO(*this);
662 UnixError::throwMe(ENOEXEC
);
667 // Locate an architecture from the fat file's list.
668 // Throws ENOEXEC if not found.
670 const fat_arch
*Universal::findArch(const Architecture
&target
) const
672 assert(isUniversal());
673 const fat_arch
*end
= mArchList
+ mArchCount
;
675 for (const fat_arch
*arch
= mArchList
; arch
< end
; ++arch
)
676 if (arch
->cputype
== target
.cpuType()
677 && arch
->cpusubtype
== target
.cpuSubtype())
679 // match for generic model of main architecture
680 for (const fat_arch
*arch
= mArchList
; arch
< end
; ++arch
)
681 if (arch
->cputype
== target
.cpuType() && arch
->cpusubtype
== 0)
683 // match for any subarchitecture of the main architecture (questionable)
684 for (const fat_arch
*arch
= mArchList
; arch
< end
; ++arch
)
685 if (arch
->cputype
== target
.cpuType())
688 UnixError::throwMe(ENOEXEC
); // not found
691 MachO
*Universal::findImage(const Architecture
&target
) const
693 const fat_arch
*arch
= findArch(target
);
694 return make(new MachO(*this, mBase
+ arch
->offset
, arch
->size
));
697 MachO
* Universal::make(MachO
* macho
) const
699 auto_ptr
<MachO
> mo(macho
); // safe resource
700 uint32_t type
= mo
->type();
701 if (type
== 0) // not a recognized Mach-O type
702 UnixError::throwMe(ENOEXEC
);
703 if (mMachType
&& mMachType
!= type
) // inconsistent members
704 UnixError::throwMe(ENOEXEC
);
705 mMachType
= type
; // record
711 // Find the best-matching architecture for this fat file.
712 // We pick the native architecture if it's available.
713 // If it contains exactly one architecture, we take that.
714 // Otherwise, we throw.
716 Architecture
Universal::bestNativeArch() const
719 // ask the NXArch API for our native architecture
720 const Architecture native
= Architecture::local();
721 if (fat_arch
*match
= NXFindBestFatArch(native
.cpuType(), native
.cpuSubtype(), mArchList
, mArchCount
))
723 // if the system can't figure it out, pick (arbitrarily) the first one
730 // List all architectures from the fat file's list.
732 void Universal::architectures(Architectures
&archs
) const
735 for (unsigned n
= 0; n
< mArchCount
; n
++)
736 archs
.insert(mArchList
[n
]);
738 auto_ptr
<MachO
> macho(architecture());
739 archs
.insert(macho
->architecture());
744 // Quickly guess the Mach-O type of a file.
745 // Returns type zero if the file isn't Mach-O or Universal.
746 // Always looks at the start of the file, and does not change the file pointer.
748 uint32_t Universal::typeOf(FileDesc fd
)
752 if (fd
.read(&header
, sizeof(header
), 0) != sizeof(header
))
754 while (max_tries
> 0) {
755 switch (header
.magic
) {
758 return header
.filetype
;
762 return flip(header
.filetype
);
767 const fat_arch
*arch1
=
768 LowLevelMemoryUtilities::increment
<fat_arch
>(&header
, sizeof(fat_header
));
769 if (fd
.read(&header
, sizeof(header
), ntohl(arch1
->offset
)) != sizeof(header
))
784 bool Universal::isSuspicious() const
788 Universal::Architectures archList
;
789 architectures(archList
);
790 for (Universal::Architectures::const_iterator it
= archList
.begin(); it
!= archList
.end(); ++it
) {
791 auto_ptr
<MachO
> macho(architecture(*it
));
792 if (macho
->isSuspicious())