Changeset 74726 in vbox for trunk/src/VBox/Runtime/common/ldr/ldrMachO.cpp
- Timestamp:
- Oct 9, 2018 9:06:46 PM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/ldr/ldrMachO.cpp
r74724 r74726 65 65 #include <iprt/mem.h> 66 66 #include <iprt/string.h> 67 #include <iprt/sha.h> 68 #include <iprt/crypto/digest.h> 67 69 68 70 #include <iprt/formats/mach-o.h> … … 234 236 PCRTCRAPLCSSUPERBLOB pSuper; 235 237 } PtrCodeSignature; 238 /** File offset of segment 0 (relative to Mach-O header). */ 239 uint64_t offSeg0ForCodeSign; 240 /** File size of segment 0. */ 241 uint64_t cbSeg0ForCodeSign; 242 /** Segment 0 flags. */ 243 uint64_t fSeg0ForCodeSign; 236 244 237 245 /** The RVA of the Global Offset Table. */ … … 261 269 /** The naturalized size. */ 262 270 uint32_t cb; 271 /** The digest type. */ 272 RTDIGESTTYPE enmDigest; 263 273 } RTLDRMACHCODEDIR; 264 274 /** Pointer to code directory data. */ … … 1166 1176 const uint32_t cSegments = pThis->cSegments; 1167 1177 PRTLDRMODMACHOSEG pSegItr; 1178 bool fFirstSeg = true; 1168 1179 RT_NOREF(cbStringPool); 1169 1180 … … 1315 1326 if (fAddSegOuter) \ 1316 1327 CLOSE_SEGMENT(); \ 1317 } while (0) /* ADD_SEGMENT_AND_ITS_SECTIONS */ 1328 \ 1329 /* Take down 'execSeg' info for signing */ \ 1330 if (fFirstSeg) \ 1331 { \ 1332 fFirstSeg = false; \ 1333 pThis->offSeg0ForCodeSign = pSrcSeg->fileoff; \ 1334 pThis->cbSeg0ForCodeSign = pSrcSeg->filesize; /** @todo file or vm size? */ \ 1335 pThis->fSeg0ForCodeSign = pSrcSeg->flags; \ 1336 } \ 1337 } while (0) /* ADD_SEGMENT_AND_ITS_SECTIONS */ 1318 1338 1319 1339 ADD_SEGMENT_AND_ITS_SECTIONS(32); … … 4049 4069 if ( offData < offFirst 4050 4070 || offData > cbBlob - sizeof(RTCRAPLCSHDR) 4051 || !(offData & 3))4071 || (offData & 3)) 4052 4072 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4053 4073 "Slot #%u has an invalid data offset: %#x (min %#x, max %#x-4)", … … 4056 4076 4057 4077 /* 4058 * Code directories.4059 */4060 if ( pSuper->aSlots[iSlot].uType == RTCRAPLCS_SLOT_CODEDIRECTORY4061 || ( pSuper->aSlots[iSlot].uType >= RTCRAPLCS_SLOT_ALTERNATE_CODEDIRECTORIES4062 && pSuper->aSlots[iSlot].uType < RTCRAPLCS_SLOT_ALTERNATE_CODEDIRECTORIES_END))4063 {4064 if (pSignature->cCodeDirs >= RT_ELEMENTS(pSignature->aCodeDirs))4065 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT,4066 "Slot #%u: Too many code directory slots (%u found thus far)",4067 iSlot, pSignature->cCodeDirs + 1);4068 if ( pSuper->aSlots[iSlot].uType == RTCRAPLCS_SLOT_CODEDIRECTORY4069 && pSignature->cCodeDirs > 0)4070 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT,4071 "Slot #%u: Already have primary code directory in slot #%u",4072 iSlot, pSignature->aCodeDirs[0].uSlot);4073 if ( pSuper->aSlots[iSlot].uType != RTCRAPLCS_SLOT_CODEDIRECTORY /* lazy bird */4074 && pSignature->cCodeDirs == 0)4075 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT,4076 "Slot #%u: Expected alternative code directory after the primary one", iSlot);4077 if (cbMaxData < RT_UOFFSETOF(RTCRAPLCSCODEDIRECTORY, uUnused))4078 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT,4079 "Slot #%u: Insufficient data vailable for code directory (max %#x)", iSlot, cbMaxData);4080 4081 PCRTCRAPLCSCODEDIRECTORY pCodeDir = (PCRTCRAPLCSCODEDIRECTORY)&pThis->PtrCodeSignature.pb[offData];4082 if (pCodeDir->Hdr.uMagic != RTCRAPLCS_MAGIC_CODEDIRECTORY)4083 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT,4084 "Slot #%u: Invalid code directory magic: %#x", iSlot, RT_BE2H_U32(pCodeDir->Hdr.uMagic));4085 uint32_t const cb = RT_BE2H_U32(pCodeDir->Hdr.cb);4086 if (cb > cbMaxData || cb < RT_UOFFSETOF(RTCRAPLCSCODEDIRECTORY, offScatter))4087 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT,4088 "Slot #%u: Code directory size is out of bound: %#x (min %#x, max %#x)",4089 iSlot, cb, RT_UOFFSETOF(RTCRAPLCSCODEDIRECTORY, offScatter), cbMaxData);4090 /** @todo validate all the fields we wish to use here. */4091 4092 pSignature->aCodeDirs[pSignature->cCodeDirs].pCodeDir = pCodeDir;4093 pSignature->aCodeDirs[pSignature->cCodeDirs].uSlot = iSlot;4094 pSignature->aCodeDirs[pSignature->cCodeDirs].cb = cb;4095 pSignature->cCodeDirs++;4096 }4097 /*4098 4078 * PKCS#7/CMS signature. 4099 4079 */ 4100 elseif (pSuper->aSlots[iSlot].uType == RTCRAPLCS_SLOT_SIGNATURE)4080 if (pSuper->aSlots[iSlot].uType == RTCRAPLCS_SLOT_SIGNATURE) 4101 4081 { 4102 4082 if (pSignature->idxPkcs7 != UINT32_MAX) … … 4115 4095 pSignature->pbPkcs7 = (uint8_t const *)(pHdr + 1); 4116 4096 pSignature->cbPkcs7 = cb - sizeof(*pHdr); 4097 } 4098 /* 4099 * Code directories. 4100 */ 4101 else if ( pSuper->aSlots[iSlot].uType == RTCRAPLCS_SLOT_CODEDIRECTORY 4102 || ( RT_BE2H_U32(pSuper->aSlots[iSlot].uType) - RT_BE2H_U32_C(RTCRAPLCS_SLOT_ALTERNATE_CODEDIRECTORIES) 4103 < RTCRAPLCS_SLOT_ALTERNATE_CODEDIRECTORIES_COUNT)) 4104 { 4105 /* Make sure we don't get too many code directories and that the first one is a regular one. */ 4106 if (pSignature->cCodeDirs >= RT_ELEMENTS(pSignature->aCodeDirs)) 4107 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4108 "Slot #%u: Too many code directory slots (%u found thus far)", 4109 iSlot, pSignature->cCodeDirs + 1); 4110 if ( pSuper->aSlots[iSlot].uType == RTCRAPLCS_SLOT_CODEDIRECTORY 4111 && pSignature->cCodeDirs > 0) 4112 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4113 "Slot #%u: Already have primary code directory in slot #%u", 4114 iSlot, pSignature->aCodeDirs[0].uSlot); 4115 if ( pSuper->aSlots[iSlot].uType != RTCRAPLCS_SLOT_CODEDIRECTORY /* lazy bird */ 4116 && pSignature->cCodeDirs == 0) 4117 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4118 "Slot #%u: Expected alternative code directory after the primary one", iSlot); 4119 4120 /* Check data header: */ 4121 if (cbMaxData < RT_UOFFSETOF(RTCRAPLCSCODEDIRECTORY, uUnused1)) 4122 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4123 "Slot #%u: Insufficient data vailable for code directory (max %#x)", iSlot, cbMaxData); 4124 4125 PCRTCRAPLCSCODEDIRECTORY pCodeDir = (PCRTCRAPLCSCODEDIRECTORY)&pThis->PtrCodeSignature.pb[offData]; 4126 if (pCodeDir->Hdr.uMagic != RTCRAPLCS_MAGIC_CODEDIRECTORY) 4127 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4128 "Slot #%u: Invalid code directory magic: %#x", iSlot, RT_BE2H_U32(pCodeDir->Hdr.uMagic)); 4129 uint32_t const cbCodeDir = RT_BE2H_U32(pCodeDir->Hdr.cb); 4130 if (cbCodeDir > cbMaxData || cbCodeDir < RT_UOFFSETOF(RTCRAPLCSCODEDIRECTORY, offScatter)) 4131 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4132 "Slot #%u: Code directory size is out of bound: %#x (min %#x, max %#x)", 4133 iSlot, cbCodeDir, RT_UOFFSETOF(RTCRAPLCSCODEDIRECTORY, offScatter), cbMaxData); 4134 pSignature->aCodeDirs[pSignature->cCodeDirs].pCodeDir = pCodeDir; 4135 pSignature->aCodeDirs[pSignature->cCodeDirs].cb = cbCodeDir; 4136 4137 /* Check Version: */ 4138 uint32_t const uVersion = RT_BE2H_U32(pCodeDir->uVersion); 4139 if ( uVersion < RTCRAPLCS_VER_2_0 4140 || uVersion >= RT_MAKE_U32(0, 3)) 4141 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4142 "Slot #%u: Code directory version is out of bounds: %#07x", iSlot, uVersion); 4143 uint32_t cbSelf = uVersion >= RTCRAPLCS_VER_SUPPORTS_EXEC_SEG ? RT_UOFFSET_AFTER(RTCRAPLCSCODEDIRECTORY, fExecSeg) 4144 : uVersion >= RTCRAPLCS_VER_SUPPORTS_CODE_LIMIT_64 ? RT_UOFFSET_AFTER(RTCRAPLCSCODEDIRECTORY, cbCodeLimit64) 4145 : uVersion >= RTCRAPLCS_VER_SUPPORTS_TEAMID ? RT_UOFFSET_AFTER(RTCRAPLCSCODEDIRECTORY, offTeamId) 4146 : uVersion >= RTCRAPLCS_VER_SUPPORTS_SCATTER ? RT_UOFFSET_AFTER(RTCRAPLCSCODEDIRECTORY, offScatter) 4147 : RT_UOFFSET_AFTER(RTCRAPLCSCODEDIRECTORY, uUnused1); 4148 if (cbSelf > cbCodeDir) 4149 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4150 "Slot #%u: Code directory size is out of bound: %#x (min %#x, max %#x)", 4151 iSlot, cbCodeDir, cbSelf, cbCodeDir); 4152 4153 /* hash type and size. */ 4154 uint8_t cbHash; 4155 RTDIGESTTYPE enmDigest; 4156 switch (pCodeDir->bHashType) 4157 { 4158 case RTCRAPLCS_HASHTYPE_SHA1: 4159 enmDigest = RTDIGESTTYPE_SHA1; 4160 cbHash = RTSHA1_HASH_SIZE; 4161 break; 4162 case RTCRAPLCS_HASHTYPE_SHA256: 4163 enmDigest = RTDIGESTTYPE_SHA256; 4164 cbHash = RTSHA256_HASH_SIZE; 4165 break; 4166 case RTCRAPLCS_HASHTYPE_SHA256_TRUNCATED: 4167 enmDigest = RTDIGESTTYPE_SHA256; 4168 cbHash = RTSHA1_HASH_SIZE; /* truncated to SHA-1 size. */ 4169 break; 4170 case RTCRAPLCS_HASHTYPE_SHA384: 4171 enmDigest = RTDIGESTTYPE_SHA384; 4172 cbHash = RTSHA384_HASH_SIZE; 4173 break; 4174 default: 4175 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, "Slot #%u: Unknown hash type %#x (LB %#x)", 4176 iSlot, pCodeDir->bHashType, pCodeDir->cbHash); 4177 } 4178 pSignature->aCodeDirs[pSignature->cCodeDirs].enmDigest = enmDigest; 4179 if (pCodeDir->cbHash != cbHash) 4180 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4181 "Slot #%u: Unexpected hash size for %s: %#x, expected %#x", 4182 iSlot, RTCrDigestTypeToName(enmDigest), pCodeDir->cbHash, cbHash); 4183 4184 /* Hash slot offset and counts. Special slots are counted backwards from offHashSlots. */ 4185 uint32_t const cSpecialSlots = RT_BE2H_U32(pCodeDir->cSpecialSlots); 4186 if (cSpecialSlots > 256) 4187 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4188 "Slot #%u: Too many special slots: %#x", iSlot, cSpecialSlots); 4189 uint32_t const cCodeSlots = RT_BE2H_U32(pCodeDir->cCodeSlots); 4190 if ( cCodeSlots >= UINT32_MAX / 2 4191 || cCodeSlots + cSpecialSlots > (cbCodeDir - cbHash) / cbHash) 4192 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, "Slot #%u: Too many code slots: %#x + %#x (max %#x)", 4193 iSlot, cCodeSlots, cSpecialSlots, (cbCodeDir - cbHash) / cbHash); 4194 uint32_t const offHashSlots = RT_BE2H_U32(pCodeDir->offHashSlots); 4195 if ( offHashSlots > cbCodeDir - cCodeSlots * cbHash 4196 || offHashSlots < cbSelf + cSpecialSlots * cbHash) 4197 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4198 "Slot #%u: Code directory hash offset is out of bounds: %#x (min: %#x, max: %#x)", 4199 iSlot, offHashSlots, cbSelf + cSpecialSlots * cbHash, cbCodeDir - cCodeSlots * cbHash); 4200 4201 /* page shift */ 4202 if (pCodeDir->cPageShift == 0) 4203 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4204 "Slot #%u: Unsupported page shift of zero in code directory", iSlot); 4205 uint32_t cMaxPageShift; 4206 if ( pThis->Core.enmArch == RTLDRARCH_AMD64 4207 || pThis->Core.enmArch == RTLDRARCH_X86_32 4208 || pThis->Core.enmArch == RTLDRARCH_ARM32) 4209 cMaxPageShift = 12; 4210 else if (pThis->Core.enmArch == RTLDRARCH_ARM64) 4211 cMaxPageShift = 16; /* 16KB */ 4212 else 4213 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, "Unsupported architecture: %d", pThis->Core.enmArch); 4214 if ( pCodeDir->cPageShift < 12 /* */ 4215 || pCodeDir->cPageShift > cMaxPageShift) 4216 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4217 "Slot #%u: Page shift in code directory is out of range: %d (min: 12, max: %d)", 4218 iSlot, pCodeDir->cPageShift, cMaxPageShift); 4219 4220 /* code limit vs page shift and code hash slots */ 4221 uint32_t const cbCodeLimit32 = RT_BE2H_U32(pCodeDir->cbCodeLimit32); 4222 uint32_t const cExpectedCodeHashes = pCodeDir->cPageShift == 0 ? 1 4223 : (cbCodeLimit32 + RT_BIT_32(pCodeDir->cPageShift) - 1) >> pCodeDir->cPageShift; 4224 if (cExpectedCodeHashes != cCodeSlots) 4225 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4226 "Slot #%u: Code limit and page shift value does not match code hash slots: cbCodeLimit32=%#x cPageShift=%u -> %#x; cCodeSlots=%#x", 4227 iSlot, cbCodeLimit32, pCodeDir->cPageShift, cExpectedCodeHashes, cCodeSlots); 4228 4229 /* Identifier offset: */ 4230 if (pCodeDir->offIdentifier) 4231 { 4232 uint32_t const offIdentifier = RT_BE2H_U32(pCodeDir->offIdentifier); 4233 if ( offIdentifier < cbSelf 4234 || offIdentifier >= cbCodeDir) 4235 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4236 "Slot #%u: Identifier offset is out of bounds: %#x (min: %#x, max: %#x)", 4237 iSlot, offIdentifier, cbSelf, cbCodeDir - 1); 4238 int rc = RTStrValidateEncodingEx((char const *)pCodeDir + offIdentifier, cbCodeDir - offIdentifier, 4239 RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); 4240 if (RT_FAILURE(rc)) 4241 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4242 "Slot #%u: Malformed identifier string: %Rrc", iSlot, rc); 4243 } 4244 4245 /* Team identifier: */ 4246 if (cbSelf >= RT_UOFFSET_AFTER(RTCRAPLCSCODEDIRECTORY, offTeamId) && pCodeDir->offTeamId) 4247 { 4248 uint32_t const offTeamId = RT_BE2H_U32(pCodeDir->offTeamId); 4249 if ( offTeamId < cbSelf 4250 || offTeamId >= cbCodeDir) 4251 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4252 "Slot #%u: Team identifier offset is out of bounds: %#x (min: %#x, max: %#x)", 4253 iSlot, offTeamId, cbSelf, cbCodeDir - 1); 4254 int rc = RTStrValidateEncodingEx((char const *)pCodeDir + offTeamId, cbCodeDir - offTeamId, 4255 RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); 4256 if (RT_FAILURE(rc)) 4257 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4258 "Slot #%u: Malformed team identifier string: %Rrc", iSlot, rc); 4259 } 4260 4261 /* We don't support scatter. */ 4262 if (cbSelf >= RT_UOFFSET_AFTER(RTCRAPLCSCODEDIRECTORY, offScatter) && pCodeDir->offScatter) 4263 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4264 "Slot #%u: Scatter not supported.", iSlot); 4265 4266 /* We don't really support the 64-bit code limit either: */ 4267 if ( cbSelf >= RT_UOFFSET_AFTER(RTCRAPLCSCODEDIRECTORY, cbCodeLimit64) 4268 && pCodeDir->cbCodeLimit64 4269 && RT_BE2H_U64(pCodeDir->cbCodeLimit64) != cbCodeLimit32) 4270 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4271 "Slot #%u: 64-bit code limit does not match 32-bit: %#RX64 vs %#RX32", 4272 iSlot, RT_BE2H_U64(pCodeDir->cbCodeLimit64), cbCodeLimit32); 4273 4274 /* Check executable segment info if present: */ 4275 if ( cbSelf >= RT_UOFFSET_AFTER(RTCRAPLCSCODEDIRECTORY, fExecSeg) 4276 && ( pThis->offSeg0ForCodeSign != RT_BE2H_U64(pCodeDir->offExecSeg) 4277 || pThis->cbSeg0ForCodeSign != RT_BE2H_U64(pCodeDir->cbExecSeg) 4278 || pThis->fSeg0ForCodeSign != RT_BE2H_U64(pCodeDir->fFlags)) ) 4279 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4280 "Slot #%u: Segment #0 info mismatch: @%#RX64 LB %#RX64 flags=%#RX64; expected @%#RX64 LB %#RX64 flags=%#RX64", 4281 iSlot, RT_BE2H_U64(pCodeDir->offExecSeg), RT_BE2H_U64(pCodeDir->cbExecSeg), 4282 RT_BE2H_U64(pCodeDir->fExecSeg), pThis->offSeg0ForCodeSign, pThis->cbSeg0ForCodeSign, 4283 pThis->fSeg0ForCodeSign); 4284 4285 /* Check fields that must be zero (don't want anyone to use them to counter changes): */ 4286 if (pCodeDir->uUnused1 != 0) 4287 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4288 "Slot #%u: Unused field #1 is non-zero: %#x", iSlot, RT_BE2H_U32(pCodeDir->uUnused1)); 4289 if ( cbSelf >= RT_UOFFSET_AFTER(RTCRAPLCSCODEDIRECTORY, uUnused2) 4290 && pCodeDir->uUnused2 != 0) 4291 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT, 4292 "Slot #%u: Unused field #2 is non-zero: %#x", iSlot, RT_BE2H_U32(pCodeDir->uUnused2)); 4293 4294 /** @todo idPlatform values. */ 4295 4296 4297 /* Commit the code dir entry: */ 4298 pSignature->aCodeDirs[pSignature->cCodeDirs++].uSlot = iSlot; 4117 4299 } 4118 4300 }
Note:
See TracChangeset
for help on using the changeset viewer.