/ OSX / libsecurity_utilities / lib / dyldcache.cpp
dyldcache.cpp
  1  /*
  2   * Copyright (c) 2009,2011-2012 Apple 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  // dyldcache - access layer to the DYLD Shared Library Cache file
 26  //
 27  #include "dyldcache.h"
 28  
 29  
 30  //
 31  // Table of supported architectures.
 32  // The cache file header has no direct architecture information, so we need to deduce it like this.
 33  //
 34  static const uint16_t bigEndian = 0x1200;
 35  static const uint16_t littleEndian = 0x0012;
 36  
 37  const DYLDCache::ArchType DYLDCache::architectures[] = {
 38  	{ CPU_TYPE_X86_64, CPU_SUBTYPE_MULTIPLE,	"dyld_v1  x86_64", "x86_64", littleEndian },
 39  	{ CPU_TYPE_X86, CPU_SUBTYPE_MULTIPLE,		"dyld_v1    i386", "i386", littleEndian },
 40  	{ CPU_TYPE_POWERPC, CPU_SUBTYPE_MULTIPLE,	"dyld_v1     ppc", "rosetta", bigEndian },
 41  	{ CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6,			"dyld_v1   armv6", "armv6", littleEndian },
 42  	{ CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7,			"dyld_v1   armv7", "armv7", littleEndian },
 43  	{ 0 }
 44  };
 45  
 46  const DYLDCache::ArchType DYLDCache::defaultArchitecture =
 47  	{ 0, 0, "dyld_v1 default", "unknown", littleEndian };
 48  
 49  
 50  //
 51  // Architecture matching and lookup
 52  //
 53  std::string DYLDCache::pathFor(const Architecture &arch)
 54  {
 55  	for (const ArchType *it = architectures; it->cpu; it++)
 56  		if (arch.matches(it->architecture()))
 57  			return it->path();
 58  	UnixError::throwMe(ENOEXEC);
 59  }
 60  
 61  const DYLDCache::ArchType *DYLDCache::matchArchitecture(const dyld_cache_header &header)
 62  {
 63  	for (const ArchType *arch = architectures; arch->cpu; arch++)
 64  		if (!strcmp(header.magic, arch->magic))
 65  			return arch;
 66  	if (!strncmp(header.magic, "dyld_v1 ", 8))
 67  		return &defaultArchitecture;
 68  	return NULL;
 69  }
 70  
 71  
 72  //
 73  // Construction and teardown
 74  //
 75  DYLDCache::DYLDCache(const std::string &path)
 76  {
 77  	this->open(path);
 78  	mLength = this->fileSize();
 79  	mBase = this->mmap(PROT_READ, mLength);
 80  	mHeader = at<dyld_cache_header>(0);
 81  
 82  	if ((mArch = matchArchitecture(*mHeader)) == NULL)
 83  		UnixError::throwMe(ENOEXEC);
 84  	mFlip = *((const uint8_t *)&mArch->order) != 0x12;
 85  	
 86  	mSigStart = (size_t)flip(mHeader->codeSignatureOffset);
 87  	mSigLength = (size_t)flip(mHeader->codeSignatureSize);
 88  	size_t sigEnd = mSigStart + mSigLength;
 89  	if (mSigStart > sigEnd || sigEnd > mLength)
 90  		UnixError::throwMe(ENOEXEC);
 91  }
 92  
 93  
 94  DYLDCache::~DYLDCache()
 95  {
 96  	::munmap((void *)mBase, mLength);
 97  }
 98  
 99  
100  //
101  // Preflight a file for file type
102  //
103  bool DYLDCache::validate(UnixPlusPlus::FileDesc &fd)
104  {
105  	dyld_cache_header header;
106  	return fd.read(&header, sizeof(header), 0) == sizeof(header)
107  		&& matchArchitecture(header) != NULL;
108  }
109  
110  
111  //
112  // Locate a mapping in the cache
113  //
114  DYLDCache::Mapping DYLDCache::mapping(unsigned ix) const
115  {
116  	assert(ix < this->mappingCount());
117  	return Mapping(*this, flip(mHeader->mappingOffset) + ix * sizeof(shared_file_mapping_np));
118  }
119  
120  
121  //
122  // Locate an image in the cache
123  //
124  DYLDCache::Image DYLDCache::image(unsigned ix) const
125  {
126  	assert(ix < this->imageCount());
127  	return Image(*this, flip(mHeader->imagesOffset) + ix * sizeof(dyld_cache_image_info));
128  }
129  
130  
131  
132  DYLDCache::Mapping DYLDCache::findMap(uint64_t address) const
133  {
134  	for (unsigned ix = 0; ix < mappingCount(); ix++) {
135  		Mapping map = this->mapping(ix);
136  		if (map.contains(address))
137  			return map;
138  	}
139  	UnixError::throwMe(EINVAL);
140  }
141  
142  uint64_t DYLDCache::mapAddress(uint64_t address) const
143  {
144  	Mapping map = this->findMap(address);
145  	return (address - map.address()) + map.offset();
146  }