1/*
2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24//
25// macho++ - Mach-O object file helpers
26//
27#ifndef _H_MACHOPLUSPLUS
28#define _H_MACHOPLUSPLUS
29
30#include <mach-o/loader.h>
31#include <mach-o/fat.h>
32#include <mach-o/arch.h>
33#include <security_utilities/globalizer.h>
34#include <security_utilities/endian.h>
35#include <security_utilities/unix++.h>
36#include <security_utilities/cfutilities.h>
37#include <map>
38
39namespace Security {
40
41
42//
43// An architecture specification.
44// Simply a pair or (cpu type, cpu subtype), really.
45//
46class Architecture : public std::pair<cpu_type_t, cpu_subtype_t> {
47	typedef std::pair<cpu_type_t, cpu_subtype_t> _Pair;
48public:
49	Architecture() { }
50	explicit Architecture(cpu_type_t type, cpu_subtype_t sub = CPU_SUBTYPE_MULTIPLE)
51		: std::pair<cpu_type_t, cpu_subtype_t>(type, sub) { }
52	Architecture(const fat_arch &archInFile);
53	Architecture(const char *name);
54
55	cpu_type_t cpuType() const { return this->first; }
56	cpu_subtype_t cpuSubtype() const { return this->second; }
57	const char *name() const;			// NULL if unknown
58	std::string displayName() const;	// always display-able
59
60	static const cpu_type_t none = 0;
61	operator bool () const { return cpuType() != none; }
62	bool operator ! () const { return cpuType() == none; }
63
64public:
65	friend bool operator == (const Architecture &a1, const Architecture &a2)
66	{ return _Pair(a1) == _Pair(a2); }
67
68	friend bool operator < (const Architecture &a1, const Architecture &a2)
69	{ return _Pair(a1) < _Pair(a2); }
70
71	bool matches(const Architecture &templ) const;
72
73public:
74	static Architecture local();
75};
76
77
78//
79// Common features of Mach-O object images.
80// MachOBase does not define where we get this from.
81//
82class MachOBase {
83protected:
84	virtual ~MachOBase();
85
86public:
87	template <class T>
88	T flip(T value) const
89	{ return mFlip ? Security::flip(value) : value; }
90
91	bool isFlipped() const { return mFlip; }
92	bool is64() const { return m64; }
93
94	const mach_header &header() const { return *mHeader; }
95	Architecture architecture() const;
96	uint32_t type() const;
97	uint32_t flags() const;
98
99	const load_command *loadCommands() const { return mCommands; }
100	const load_command *nextCommand(const load_command *command) const;
101	size_t commandLength() const { return flip(mHeader->sizeofcmds); }
102
103	const load_command *findCommand(uint32_t cmd) const;
104	const segment_command *findSegment(const char *segname) const;
105	const section *findSection(const char *segname, const char *sectname) const;
106
107	const char *string(const load_command *cmd, const lc_str &str) const;
108
109	const linkedit_data_command *findCodeSignature() const;
110	const linkedit_data_command *findLibraryDependencies() const;
111
112	size_t signingOffset() const;	// starting offset of CS section, or 0 if none
113	size_t signingLength() const;	// length of CS section, or 0 if none
114
115protected:
116	void initHeader(const mach_header *address);
117	void initCommands(const load_command *commands);
118
119	size_t headerSize() const;		// size of header
120	size_t commandSize() const;		// size of commands area
121
122private:
123	const mach_header *mHeader;	// Mach-O header
124	const load_command *mCommands; // load commands
125	const load_command *mEndCommands; // end of load commands
126
127	bool m64;					// is 64-bit
128	bool mFlip;					// wrong byte order (flip all integers)
129};
130
131
132//
133// A Mach-O object image that resides on disk.
134// We only read small parts of the contents into (discontinuous) memory.
135//
136class MachO : public MachOBase, public UnixPlusPlus::FileDesc {
137public:
138	MachO(FileDesc fd, size_t offset = 0, size_t length = 0);
139	~MachO();
140
141	size_t offset() const { return mOffset; }
142	size_t length() const { return mLength; }
143	size_t signingExtent() const;	// signingOffset, or file length if none
144
145	void seek(size_t offset);	// relative to start of image
146	CFDataRef dataAt(size_t offset, size_t size);
147	void validateStructure();	// is the structure of the mach-o sane
148
149	bool isSuspicious() const { return mSuspicious; }
150
151private:
152	size_t mOffset;			// starting file offset
153	size_t mLength;			// Mach-O file length
154
155	mach_header mHeaderBuffer; // read-in Mach-O header
156	load_command *mCommandBuffer; // read-in (malloc'ed) Mach-O load commands
157
158	bool mSuspicious;		// strict validation failed
159};
160
161
162//
163// A Mach-O object image that was mapped into memory.
164// We expect the entire image to be contiguously mapped starting at the
165// address given. No particular alignment is required (beyond native
166// alignment constraints on member variables).
167//
168class MachOImage : public MachOBase {
169public:
170	MachOImage(const void *address);
171
172	const void *address() { return &this->header(); }
173};
174
175class MainMachOImage : public MachOImage {
176public:
177	MainMachOImage();
178
179	static const void *mainImageAddress();
180};
181
182
183//
184// A Universal object represents a Mach-O binary image (whole) file.
185// It can represent a true Universal (aka "Fat") file with multiple
186// architectures; but it will also represent a single Mach-O ("thin")
187// binary and make you believe it's a Universal with just one architecture.
188//
189class Universal : public UnixPlusPlus::FileDesc {
190public:
191	Universal(FileDesc fd, size_t offset = 0, size_t length = 0);
192	~Universal();
193
194	// return a genuine MachO object for the given architecture
195	MachO *architecture() const;		// native
196	MachO *architecture(const Architecture &arch) const; // given
197	MachO *architecture(size_t offset) const; // given by file offset
198
199	// return (just) the starting offset of an architecture
200	size_t archOffset() const;			// native
201	size_t archOffset(const Architecture &arch) const; // given
202	size_t archLength(const Architecture &arch) const; // given
203	bool narrowed() const { return mBase != 0; }	// part of a fat file
204
205	// return a set of architectures contained
206	typedef std::set<Architecture> Architectures;
207	void architectures(Architectures &archs) const;
208
209	bool isUniversal() const { return mArchList != NULL; }
210	Architecture bestNativeArch() const;
211	const size_t lengthOfSlice(size_t offset) const;
212
213	size_t offset() const { return mBase; }
214	size_t length() const { return mLength; }
215
216	bool isSuspicious() const;
217
218public:
219	static uint32_t typeOf(FileDesc fd);
220
221private:
222	const fat_arch *findArch(const Architecture &arch) const;
223	MachO *findImage(const Architecture &arch) const;
224
225private:
226	fat_arch *mArchList;		// architectures (NULL if thin file)
227	unsigned mArchCount;		// number of architectures (if fat)
228	Architecture mThinArch;		// single architecture (if thin)
229	size_t mBase;				// overriding offset in file (all types)
230	size_t mLength;				// length of the architecture if thin file
231	typedef std::map<size_t, size_t> OffsetsToLength;
232	OffsetsToLength mSizes; // the length for the slice at a given offset
233	bool mSuspicious;			// strict validation failed
234};
235
236
237} // end namespace Security
238
239#endif // !_H_MACHOPLUSPLUS
240