| Index: src/trusted/validator_ragel/validator_x86_32.rl
|
| ===================================================================
|
| --- src/trusted/validator_ragel/validator_x86_32.rl (revision 11020)
|
| +++ src/trusted/validator_ragel/validator_x86_32.rl (working copy)
|
| @@ -20,13 +20,14 @@
|
| #include <string.h>
|
|
|
| #include "native_client/src/trusted/validator_ragel/bitmap.h"
|
| -#include "native_client/src/trusted/validator_ragel/unreviewed/validator_internal.h"
|
| +#include "native_client/src/trusted/validator_ragel/validator_internal.h"
|
|
|
| /* Ignore this information: it's not used by security model in IA32 mode. */
|
| +/* TODO(khim): change gen_dfa to remove needs for these lines. */
|
| #undef GET_VEX_PREFIX3
|
| #define GET_VEX_PREFIX3 0
|
| #undef SET_VEX_PREFIX3
|
| -#define SET_VEX_PREFIX3(P)
|
| +#define SET_VEX_PREFIX3(PREFIX_BYTE)
|
|
|
| %%{
|
| machine x86_32_validator;
|
| @@ -57,14 +58,6 @@
|
| include cpuid_actions
|
| "native_client/src/trusted/validator_ragel/parse_instruction.rl";
|
|
|
| - # Action which marks last byte as not immediate. Most 3DNow! instructions,
|
| - # some AVX and XOP instructions have this property. It's referenced by
|
| - # decode_x86_32 machine in [autogenerated] "validator_x86_32_instruction.rl"
|
| - # file.
|
| - action last_byte_is_not_immediate {
|
| - instruction_info_collected |= LAST_BYTE_IS_NOT_IMMEDIATE;
|
| - }
|
| -
|
| include decode_x86_32 "validator_x86_32_instruction.rl";
|
|
|
| special_instruction =
|
| @@ -81,7 +74,7 @@
|
| # ^^^^ ^^^^
|
| # and $~0x1f, %eXX jmp %eXX
|
| @{
|
| - UnmarkValidJumpTarget((current_position - data) - 1, valid_targets);
|
| + UnmarkValidJumpTarget((current_position - codeblock) - 1, valid_targets);
|
| instruction_begin -= 3;
|
| instruction_info_collected |= SPECIAL_INSTRUCTION;
|
| } |
|
| @@ -89,39 +82,38 @@
|
| 0x65 0x8b (0x05|0x0d|0x015|0x1d|0x25|0x2d|0x35|0x3d)
|
| (0x00|0x04) 0x00 0x00 0x00); # mov %gs:0x0/0x4,%reg
|
|
|
| - # Check if call is properly aligned
|
| - #
|
| - # For direct call we explicitly encode all variations. For indirect call
|
| - # we accept all the special instructions which ends with register-addressed
|
| - # indirect call.
|
| + # For direct call we explicitly encode all variations.
|
| + direct_call = (data16 0xe8 rel16) | (0xe8 rel32);
|
| +
|
| + # For indirect call we accept only near register-addressed indirect call.
|
| + indirect_call_register = data16? 0xff (opcode_2 & modrm_registers);
|
| +
|
| + # Ragel machine that accepts one call instruction or call superinstruction and
|
| + # checks if call is properly aligned.
|
| call_alignment =
|
| - ((one_instruction &
|
| - # Direct call
|
| - ((data16 0xe8 rel16) |
|
| - (0xe8 rel32))) |
|
| - (special_instruction &
|
| - # Indirect call
|
| - (any* data16? 0xff ((opcode_2 | opcode_3) any* &
|
| - modrm_registers))))
|
| + ((one_instruction & direct_call) |
|
| + # For indirect calls we accept all the special instructions which ends with
|
| + # register-addressed indirect call.
|
| + (special_instruction & (any* indirect_call_register)))
|
| # Call instruction must aligned to the end of bundle. Previously this was
|
| # strict requirement, today it's just warning to aid with debugging.
|
| @{
|
| - if (((current_position - data) & kBundleMask) != kBundleMask)
|
| + if (((current_position - codeblock) & kBundleMask) != kBundleMask)
|
| instruction_info_collected |= BAD_CALL_ALIGNMENT;
|
| };
|
|
|
| - # This action calls user's callback (if needed) and cleans up validator's
|
| + # This action calls user callback (if needed) and cleans up validator
|
| # internal state.
|
| #
|
| - # We call the user callback if there are validation errors or if the
|
| - # CALL_USER_CALLBACK_ON_EACH_INSTRUCTION option is used.
|
| + # We call the user callback either on validation errors or on every
|
| + # instruction, depending on CALL_USER_CALLBACK_ON_EACH_INSTRUTION option.
|
| #
|
| # After that we move instruction_begin and clean all the variables which
|
| - # only used in the processing of a single instruction (prefixes, operand
|
| - # states and instruction_info_collected).
|
| + # are only used in the processing of a single instruction (here it's just
|
| + # instruction_info_collected, there are more state in x86-64 case).
|
| action end_of_instruction_cleanup {
|
| /* Mark start of this instruction as a valid target for jump. */
|
| - MarkValidJumpTarget(instruction_begin - data, valid_targets);
|
| + MarkValidJumpTarget(instruction_begin - codeblock, valid_targets);
|
|
|
| /* Call user-supplied callback. */
|
| instruction_end = current_position + 1;
|
| @@ -131,9 +123,11 @@
|
| instruction_info_collected, callback_data);
|
| }
|
|
|
| - /* On successful match the instruction_begin must point to the next byte
|
| - * to be able to report the new offset as the start of instruction
|
| - * causing error. */
|
| + /*
|
| + * We may set instruction_begin at the first byte of the instruction instead
|
| + * of here but in the case of incorrect one byte instructions user callback
|
| + * may be called before instruction_begin is set.
|
| + */
|
| instruction_begin = instruction_end;
|
|
|
| /* Clear variables (well, one variable currently). */
|
| @@ -156,8 +150,8 @@
|
| }
|
|
|
| # This is main ragel machine: it does 99% of validation work. There are only
|
| - # one thing to do if this machine accepts the bundles - check that direct
|
| - # jumps are correct. This is done in the following way:
|
| + # one thing to do if this ragel machine accepts the bundles - check that
|
| + # direct jumps are correct. This is done in the following way:
|
| # * DFA fills two arrays: valid_targets and jump_dests.
|
| # * ProcessInvalidJumpTargets checks that "jump_dests & !valid_targets == 0".
|
| # All other checks are done here.
|
| @@ -167,10 +161,14 @@
|
|
|
| }%%
|
|
|
| +/*
|
| + * The "write data" statement causes Ragel to emit the constant static data
|
| + * needed by the ragel machine.
|
| + */
|
| %% write data;
|
|
|
| -
|
| -Bool ValidateChunkIA32(const uint8_t *data, size_t size,
|
| +Bool ValidateChunkIA32(const uint8_t codeblock[],
|
| + size_t size,
|
| uint32_t options,
|
| const NaClCPUFeaturesX86 *cpu_features,
|
| ValidationCallbackFunc user_callback,
|
| @@ -206,12 +204,12 @@
|
| /*
|
| * This option is usually used in tests: we will process the whole chunk
|
| * in one pass. Usually each bundle is processed separately which means
|
| - * instructions (and super-instructions) can not cross borders of the bundle.
|
| + * instructions (and "superinstructions") can not cross borders of the bundle.
|
| */
|
| if (options & PROCESS_CHUNK_AS_A_CONTIGUOUS_STREAM)
|
| - end_of_bundle = data + size;
|
| + end_of_bundle = codeblock + size;
|
| else
|
| - end_of_bundle = data + kBundleSize;
|
| + end_of_bundle = codeblock + kBundleSize;
|
|
|
| /*
|
| * Main loop. Here we process the data array bundle-after-bundle.
|
| @@ -219,8 +217,8 @@
|
| * It collects the two arrays: valid_targets and jump_dests which are used
|
| * to test direct jumps later.
|
| */
|
| - for (current_position = data;
|
| - current_position < data + size;
|
| + for (current_position = codeblock;
|
| + current_position < codeblock + size;
|
| current_position = end_of_bundle,
|
| end_of_bundle = current_position + kBundleSize) {
|
| /* Start of the instruction being processed. */
|
| @@ -230,7 +228,15 @@
|
| uint32_t instruction_info_collected = 0;
|
| int current_state;
|
|
|
| + /*
|
| + * The "write init" statement causes Ragel to emit initialization code.
|
| + * This should be executed once before the ragel machine is started.
|
| + */
|
| %% write init;
|
| + /*
|
| + * The "write exec" statement causes Ragel to emit the ragel machine's
|
| + * execution code.
|
| + */
|
| %% write exec;
|
| }
|
|
|
| @@ -238,8 +244,12 @@
|
| * Check the direct jumps. All the targets from jump_dests must be in
|
| * valid_targets.
|
| */
|
| - result &= ProcessInvalidJumpTargets(data, size, valid_targets, jump_dests,
|
| - user_callback, callback_data);
|
| + result &= ProcessInvalidJumpTargets(codeblock,
|
| + size,
|
| + valid_targets,
|
| + jump_dests,
|
| + user_callback,
|
| + callback_data);
|
|
|
| /* We only use malloc for a large code sequences */
|
| if (jump_dests != &jump_dests_small) free(jump_dests);
|
|
|