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