/ OSX / libsecurity_codesigning / lib / piddiskrep.cpp
piddiskrep.cpp
  1  /*
  2   * Copyright (c) 2012-2014 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  #include "piddiskrep.h"
 24  #include "sigblob.h"
 25  #include <sys/param.h>
 26  #include <sys/utsname.h>
 27  #include <System/sys/codesign.h>
 28  #include <libproc.h>
 29  #include <xpc/xpc.h>
 30  
 31  namespace Security {
 32  namespace CodeSigning {
 33                  
 34  using namespace UnixPlusPlus;
 35  
 36  
 37  void
 38  PidDiskRep::setCredentials(const Security::CodeSigning::CodeDirectory *cd)
 39  {
 40  	// save the Info.plist slot
 41  	if (cd->slotIsPresent(cdInfoSlot)) {
 42  		mInfoPlistHash.take(makeCFData(cd->getSlot(cdInfoSlot, false), cd->hashSize));
 43  	}
 44  }
 45  
 46  void
 47  PidDiskRep::fetchData(void)
 48  {
 49  	if (mDataFetched)	// once
 50  		return;
 51  	
 52  	xpc_connection_t conn = xpc_connection_create("com.apple.CodeSigningHelper",
 53  						      dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
 54  	xpc_connection_set_event_handler(conn, ^(xpc_object_t object){ });
 55  	xpc_connection_resume(conn);
 56  	
 57  	xpc_object_t request = xpc_dictionary_create(NULL, NULL, 0);
 58  	assert(request != NULL);
 59  	xpc_dictionary_set_string(request, "command", "fetchData");
 60  	xpc_dictionary_set_int64(request, "pid", mPid);
 61  	
 62  	if (mAudit) {
 63  		xpc_dictionary_set_data(request, "audit", mAudit.get(), sizeof(audit_token_t));
 64  	}
 65  	xpc_dictionary_set_data(request, "infohash", CFDataGetBytePtr(mInfoPlistHash), CFDataGetLength(mInfoPlistHash));
 66  	
 67  	xpc_object_t reply = xpc_connection_send_message_with_reply_sync(conn, request);
 68  	if (reply && xpc_get_type(reply) == XPC_TYPE_DICTIONARY) {
 69  		const void *data;
 70  		size_t size;
 71  
 72  		if (!mInfoPlist) {
 73  			data = xpc_dictionary_get_data(reply, "infoPlist", &size);
 74  			if (data && size > 0 && size < 50 * 1024)
 75  				mInfoPlist.take(CFDataCreate(NULL, (const UInt8 *)data, (CFIndex)size));
 76  		}
 77  		if (!mBundleURL) {
 78  			data = xpc_dictionary_get_data(reply, "bundleURL", &size);
 79  			if (data && size > 0 && size < 50 * 1024)
 80  				mBundleURL.take(CFURLCreateWithBytes(NULL, (const UInt8 *)data, (CFIndex)size, kCFStringEncodingUTF8, NULL));
 81  		}
 82  	}
 83  	if (reply)
 84  		xpc_release(reply);
 85  
 86  	xpc_release(request);
 87  	xpc_release(conn);
 88      
 89      if (!mBundleURL) {
 90          MacOSError::throwMe(errSecCSNoSuchCode);
 91      }
 92  
 93      mDataFetched = true;
 94  }
 95  
 96  
 97  PidDiskRep::PidDiskRep(pid_t pid, audit_token_t *audit, CFDataRef infoPlist)
 98  	: mDataFetched(false)
 99  {
100          BlobCore header;
101  	
102          mPid = pid;
103          mInfoPlist = infoPlist;
104      
105          if (audit != NULL) {
106              mAudit.reset(new audit_token_t);
107              memcpy(mAudit.get(), audit, sizeof(audit_token_t));
108          }
109      
110          //        fetchData();
111      
112          int rcent = EINVAL;
113  	
114          if (audit != NULL) {
115              rcent = ::csops_audittoken(pid, CS_OPS_BLOB, &header, sizeof(header), mAudit.get());
116          } else {
117              rcent = ::csops(pid, CS_OPS_BLOB, &header, sizeof(header));
118          }
119          if (rcent == 0)
120              MacOSError::throwMe(errSecCSNoSuchCode);
121          
122          if (errno != ERANGE)
123                  UnixError::throwMe(errno);
124  
125          if (header.length() > 1024 * 1024)
126                  MacOSError::throwMe(errSecCSNoSuchCode);
127          
128          uint32_t bufferLen = (uint32_t)header.length();
129          mBuffer = new uint8_t [bufferLen];
130      
131          if (audit != NULL) {
132              UnixError::check(::csops_audittoken(pid, CS_OPS_BLOB, mBuffer, bufferLen, mAudit.get()));
133          } else {
134              UnixError::check(::csops(pid, CS_OPS_BLOB, mBuffer, bufferLen));
135          }
136  
137          const EmbeddedSignatureBlob *b = (const EmbeddedSignatureBlob *)mBuffer;
138          if (!b->validateBlob(bufferLen))
139                  MacOSError::throwMe(errSecCSSignatureInvalid);
140  }
141  
142  PidDiskRep::~PidDiskRep()
143  {
144          if (mBuffer)
145                  delete [] mBuffer;
146  }
147  
148  
149  bool PidDiskRep::supportInfoPlist()
150  {
151  		fetchData();
152          return mInfoPlist;
153  }
154  
155  
156  CFDataRef PidDiskRep::component(CodeDirectory::SpecialSlot slot)
157  {
158  	if (slot == cdInfoSlot) {
159  		fetchData();
160  		return mInfoPlist.retain();
161  	}
162  
163  	EmbeddedSignatureBlob *b = (EmbeddedSignatureBlob *)this->blob();
164  	return b->component(slot);
165  }
166  
167  CFDataRef PidDiskRep::identification()
168  {
169          return NULL;
170  }
171  
172  
173  CFURLRef PidDiskRep::copyCanonicalPath()
174  {
175  	fetchData();
176  	return mBundleURL.retain();
177  }
178  
179  string PidDiskRep::recommendedIdentifier(const SigningContext &)
180  {
181  	return string("pid") + to_string(mPid);
182  }
183  
184  size_t PidDiskRep::signingLimit()
185  {
186          return 0;
187  }
188  
189  size_t PidDiskRep::execSegLimit(const Architecture *)
190  {
191  		return 0;
192  }
193      
194  string PidDiskRep::format()
195  {
196          return "pid diskrep";
197  }
198  
199  UnixPlusPlus::FileDesc &PidDiskRep::fd()
200  {
201          UnixError::throwMe(EINVAL);
202  }
203  
204  string PidDiskRep::mainExecutablePath()
205  {
206          char path[MAXPATHLEN * 2];
207          // This is unsafe by pid only, but so is using that path in general.
208          if(::proc_pidpath(mPid, path, sizeof(path)) == 0)
209  		UnixError::throwMe(errno);
210  
211          return path;
212  }
213  
214  bool PidDiskRep::appleInternalForcePlatform() const
215  {
216  	uint32_t flags = 0;
217  	int rcent = EINVAL;
218  	
219  	if (mAudit != NULL) {
220  		rcent = ::csops_audittoken(mPid, CS_OPS_STATUS, &flags, sizeof(flags),
221  								   mAudit.get());
222  	} else {
223  		rcent = ::csops(mPid, CS_OPS_STATUS, &flags, sizeof(flags));
224  	}
225  	
226  	if (rcent != 0) {
227  		MacOSError::throwMe(errSecCSNoSuchCode);
228  	}
229  	
230  	return (flags & CS_PLATFORM_BINARY) == CS_PLATFORM_BINARY;
231  }
232                  
233  } // end namespace CodeSigning
234  } // end namespace Security