NaClErrorCode NaClValidateImage(struct NaClApp *nap) { uintptr_t memp; uintptr_t endp; size_t regionsize; NaClErrorCode rcode; memp = nap->mem_start + NACL_TRAMPOLINE_END; endp = nap->mem_start + nap->static_text_end; regionsize = endp - memp; if (endp < memp) { return LOAD_NO_MEMORY; } if (nap->skip_validator) { NaClLog(LOG_ERROR, "VALIDATION SKIPPED.\n"); return LOAD_OK; } else { rcode = NaClValidateCode(nap, NACL_TRAMPOLINE_END, (uint8_t *) memp, regionsize); if (LOAD_OK != rcode) { if (nap->ignore_validator_result) { NaClLog(LOG_ERROR, "VALIDATION FAILED: continuing anyway...\n"); rcode = LOAD_OK; } else { NaClLog(LOG_ERROR, "VALIDATION FAILED.\n"); NaClLog(LOG_ERROR, "Run sel_ldr in debug mode to ignore validation failure.\n"); NaClLog(LOG_ERROR, "Run ncval <module-name> for validation error details.\n"); rcode = LOAD_VALIDATION_FAILED; } } } return rcode; }
int32_t NaClTextDyncodeCreate(struct NaClApp *nap, uint32_t dest, void *code_copy, uint32_t size, const struct NaClValidationMetadata *metadata) { uintptr_t dest_addr; uint8_t *mapped_addr; int32_t retval = -NACL_ABI_EINVAL; int validator_result; struct NaClPerfCounter time_dyncode_create; NaClPerfCounterCtor(&time_dyncode_create, "NaClTextDyncodeCreate"); if (NULL == nap->text_shm) { NaClLog(1, "NaClTextDyncodeCreate: Dynamic loading not enabled\n"); return -NACL_ABI_EINVAL; } if (0 != (dest & (nap->bundle_size - 1)) || 0 != (size & (nap->bundle_size - 1))) { NaClLog(1, "NaClTextDyncodeCreate: Non-bundle-aligned address or size\n"); return -NACL_ABI_EINVAL; } dest_addr = NaClUserToSysAddrRange(nap, dest, size); if (kNaClBadAddress == dest_addr) { NaClLog(1, "NaClTextDyncodeCreate: Dest address out of range\n"); return -NACL_ABI_EFAULT; } if (dest < nap->dynamic_text_start) { NaClLog(1, "NaClTextDyncodeCreate: Below dynamic code area\n"); return -NACL_ABI_EFAULT; } /* * We ensure that the final HLTs of the dynamic code region cannot * be overwritten, just in case of CPU bugs. */ if (dest + size > nap->dynamic_text_end - NACL_HALT_SLED_SIZE) { NaClLog(1, "NaClTextDyncodeCreate: Above dynamic code area\n"); return -NACL_ABI_EFAULT; } if (0 == size) { /* Nothing to load. Succeed trivially. */ return 0; } NaClXMutexLock(&nap->dynamic_load_mutex); /* * Validate the code before trying to create the region. This avoids the need * to delete the region if validation fails. * See: http://code.google.com/p/nativeclient/issues/detail?id=2566 */ if (!nap->skip_validator) { validator_result = NaClValidateCode(nap, dest, code_copy, size, metadata); } else { NaClLog(LOG_ERROR, "VALIDATION SKIPPED.\n"); validator_result = LOAD_OK; } NaClPerfCounterMark(&time_dyncode_create, NACL_PERF_IMPORTANT_PREFIX "DynRegionValidate"); NaClPerfCounterIntervalLast(&time_dyncode_create); if (validator_result != LOAD_OK && nap->ignore_validator_result) { NaClLog(LOG_ERROR, "VALIDATION FAILED for dynamically-loaded code: " "continuing anyway...\n"); validator_result = LOAD_OK; } if (validator_result != LOAD_OK) { NaClLog(1, "NaClTextDyncodeCreate: " "Validation of dynamic code failed\n"); retval = -NACL_ABI_EINVAL; goto cleanup_unlock; } if (NaClDynamicRegionCreate(nap, dest_addr, size, 0) != 1) { /* target addr is in use */ NaClLog(1, "NaClTextDyncodeCreate: Code range already allocated\n"); retval = -NACL_ABI_EINVAL; goto cleanup_unlock; } if (!NaClTextMapWrapper(nap, dest, size, &mapped_addr)) { retval = -NACL_ABI_ENOMEM; goto cleanup_unlock; } CopyCodeSafelyInitial(mapped_addr, code_copy, size, nap->bundle_size); /* * Flush the processor's instruction cache. This is not necessary * for security, because any old cached instructions will just be * safe halt instructions. It is only necessary to ensure that * untrusted code runs correctly when it tries to execute the * dynamically-loaded code. */ NaClFlushCacheForDoublyMappedCode(mapped_addr, (uint8_t *) dest_addr, size); retval = 0; NaClTextMapClearCacheIfNeeded(nap, dest, size); cleanup_unlock: NaClXMutexUnlock(&nap->dynamic_load_mutex); return retval; }