| Index: src/trusted/validator_ragel/dfa_validate_common.c
|
| diff --git a/src/trusted/validator_ragel/dfa_validate_common.c b/src/trusted/validator_ragel/dfa_validate_common.c
|
| index 4972cbd654b3fcd0d884dec0099db63750991802..3a4c96c623e989559e56b24ed292935e889eb6fd 100644
|
| --- a/src/trusted/validator_ragel/dfa_validate_common.c
|
| +++ b/src/trusted/validator_ragel/dfa_validate_common.c
|
| @@ -12,6 +12,7 @@
|
| #include "native_client/src/shared/platform/nacl_check.h"
|
| #include "native_client/src/trusted/service_runtime/nacl_config.h"
|
| #include "native_client/src/trusted/validator_ragel/validator.h"
|
| +#include "native_client/src/include/build_config.h"
|
|
|
| /* Used as an argument to copy_func when unsupported instruction must be
|
| replaced with HLTs. */
|
| @@ -33,29 +34,161 @@ Bool NaClDfaProcessValidationError(const uint8_t *begin, const uint8_t *end,
|
| return FALSE;
|
| }
|
|
|
| -Bool NaClDfaStubOutUnsupportedInstruction(const uint8_t *begin,
|
| +Bool NaClDfaProcessPostRewriteValidationError(const uint8_t *begin,
|
| + const uint8_t *end,
|
| + uint32_t info,
|
| + void *callback_data) {
|
| + UNREFERENCED_PARAMETER(begin);
|
| + UNREFERENCED_PARAMETER(end);
|
| + UNREFERENCED_PARAMETER(callback_data);
|
| +
|
| + if ((info & VALIDATION_ERRORS_MASK) == DIRECT_JUMP_OUT_OF_RANGE)
|
| + return TRUE;
|
| + else
|
| + return FALSE;
|
| +}
|
| +
|
| +#if NACL_BUILD_SUBARCH == 64
|
| +static Bool IsREX(uint8_t byte) {
|
| + return byte >= 0x40 && byte <= 0x4f;
|
| +}
|
| +#endif
|
| +
|
| +static Bool NaClDfaRewriteUnsupportedInstruction(const uint8_t *begin,
|
| const uint8_t *end,
|
| uint32_t info,
|
| void *callback_data) {
|
| + uint8_t *ptr = (uint8_t *) begin;
|
| struct StubOutCallbackData *data = callback_data;
|
| - /* Stub-out instructions unsupported on this CPU, but valid on other CPUs. */
|
| - if ((info & VALIDATION_ERRORS_MASK) == CPUID_UNSUPPORTED_INSTRUCTION) {
|
| + /* Clear DIRECT_JUMP_OUT_OF_RANGE error, because it may be introduced by
|
| + * validating a bundle which is smaller than the original chunk size. Even if
|
| + * the orignal chunk has this error, it can be detected when validating the
|
| + * whole chunk.
|
| + */
|
| + info &= ~DIRECT_JUMP_OUT_OF_RANGE;
|
| + if ((info & VALIDATION_ERRORS_MASK) == 0) {
|
| + return TRUE;
|
| + } else if ((info & VALIDATION_ERRORS_MASK) == CPUID_UNSUPPORTED_INSTRUCTION) {
|
| + /* Stub-out instructions unsupported on this CPU, but valid on other CPUs.*/
|
| data->did_rewrite = 1;
|
| memset((uint8_t *)begin, NACL_HALT_OPCODE, end - begin);
|
| return TRUE;
|
| - } else if ((info & VALIDATION_ERRORS_MASK) == UNSUPPORTED_INSTRUCTION) {
|
| - if (data->flags & NACL_DISABLE_NONTEMPORALS_X86) {
|
| - return FALSE;
|
| - } else {
|
| - /* TODO(ruiq): rewrite instruction. For now, we keep the original
|
| - * instruction and indicate validation success, which is consistent
|
| - * with current validation results. */
|
| - data->did_rewrite = 0;
|
| - return TRUE;
|
| - }
|
| - } else {
|
| + } else if ((info & VALIDATION_ERRORS_MASK) != UNSUPPORTED_INSTRUCTION) {
|
| return FALSE;
|
| }
|
| + /* We usually only check and rewrite the first few bytes without examining
|
| + * further because this function is only called when the validator tells us
|
| + * that it is an 'unsupported instruction' and there are no other validation
|
| + * failures.
|
| + */
|
| +#if NACL_BUILD_SUBARCH == 32
|
| + UNREFERENCED_PARAMETER(end);
|
| + if (memcmp(begin, "\x0f\xe7", 2) == 0) {
|
| + /* movntq => movq */
|
| + ptr[1] = 0x7f;
|
| + data->did_rewrite = 1;
|
| + return TRUE;
|
| + } else if (memcmp(begin, "\x66\x0f\xe7", 3) == 0) {
|
| + /* movntdq => movdqa */
|
| + ptr[2] = 0x7f;
|
| + data->did_rewrite = 1;
|
| + return TRUE;
|
| + }
|
| +#elif NACL_BUILD_SUBARCH == 64
|
| + if (IsREX(begin[0]) && (begin[1] == 0x0f)) {
|
| + uint8_t opcode_byte2 = begin[2];
|
| + switch (opcode_byte2) {
|
| + case 0x2b:
|
| + /* movntps => movaps */
|
| + ptr[2] = 0x29;
|
| + data->did_rewrite = 1;
|
| + return TRUE;
|
| + case 0xc3:
|
| + /* movnti => mov */
|
| + if (info & RESTRICTED_REGISTER_USED) {
|
| + ptr[1] = 0x89;
|
| + memmove(ptr + 2, ptr + 3, end - begin - 3);
|
| + ptr[end - begin - 1] = 0x90;
|
| + } else {
|
| + ptr[2] = 0x89;
|
| + ptr[1] = ptr[0];
|
| + ptr[0] = 0x90;
|
| + }
|
| + data->did_rewrite = 1;
|
| + return TRUE;
|
| + case 0x18:
|
| + /* prefetchnta => nop */
|
| + memset(ptr, 0x90, end - begin);
|
| + data->did_rewrite = 1;
|
| + return TRUE;
|
| + default:
|
| + return FALSE;
|
| + }
|
| + } else if (begin[0] == 0x66 && IsREX(begin[1]) &&
|
| + memcmp(begin + 2, "\x0f\xe7", 2) == 0) {
|
| + /* movntdq => movdqa */
|
| + ptr[3] = 0x7f;
|
| + data->did_rewrite = 1;
|
| + return TRUE;
|
| + }
|
| +#endif
|
| + return FALSE;
|
| +}
|
| +
|
| +Bool NaClDfaStubOutUnsupportedInstruction(const uint8_t *begin,
|
| + const uint8_t *end,
|
| + uint32_t info,
|
| + void *callback_data) {
|
| + struct StubOutCallbackData *data = callback_data;
|
| + intptr_t addr;
|
| + uint8_t *bundle_begin;
|
| + Bool rc, rc2;
|
| + UNREFERENCED_PARAMETER(end);
|
| +
|
| + if ((info & VALIDATION_ERRORS_MASK) != CPUID_UNSUPPORTED_INSTRUCTION &&
|
| + (info & VALIDATION_ERRORS_MASK) != UNSUPPORTED_INSTRUCTION)
|
| + return FALSE;
|
| + if ((info & VALIDATION_ERRORS_MASK) == UNSUPPORTED_INSTRUCTION &&
|
| + (data->flags & NACL_DISABLE_NONTEMPORALS_X86))
|
| + return FALSE;
|
| +
|
| + CHECK(!data->chunk_processed_as_a_contiguous_stream);
|
| + addr = ((intptr_t) begin & ~(kBundleMask)) + data->bundle_begin_offset;
|
| + if (addr > (intptr_t) begin)
|
| + bundle_begin = (uint8_t *) (addr - kBundleSize);
|
| + else
|
| + bundle_begin = (uint8_t *) addr;
|
| + /* Rewrite a bundle at a time. */
|
| +#if NACL_BUILD_SUBARCH == 32
|
| + rc = ValidateChunkIA32(bundle_begin, kBundleSize, 0 /*options*/,
|
| + (NaClCPUFeaturesX86 *) data->cpu_features,
|
| + NaClDfaRewriteUnsupportedInstruction,
|
| + callback_data);
|
| +#elif NACL_BUILD_SUBARCH == 64
|
| + rc = ValidateChunkAMD64(bundle_begin, kBundleSize, 0 /*options*/,
|
| + (NaClCPUFeaturesX86 *) data->cpu_features,
|
| + NaClDfaRewriteUnsupportedInstruction,
|
| + callback_data);
|
| +#endif
|
| +
|
| + if (!rc)
|
| + return FALSE;
|
| +
|
| + /* Revalidate the bundle after rewriting. */
|
| +#if NACL_BUILD_SUBARCH == 32
|
| + rc2 = ValidateChunkIA32(bundle_begin, kBundleSize, 0 /*options*/,
|
| + (NaClCPUFeaturesX86 *) data->cpu_features,
|
| + NaClDfaProcessPostRewriteValidationError,
|
| + NULL);
|
| +#elif NACL_BUILD_SUBARCH == 64
|
| + rc2 = ValidateChunkAMD64(bundle_begin, kBundleSize, 0 /*options*/,
|
| + (NaClCPUFeaturesX86 *) data->cpu_features,
|
| + NaClDfaProcessPostRewriteValidationError,
|
| + NULL);
|
| +#endif
|
| + if (!rc2)
|
| + return FALSE;
|
| + return TRUE;
|
| }
|
|
|
| Bool NaClDfaProcessCodeCopyInstruction(const uint8_t *begin_new,
|
|
|