| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. | 2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. |
| 3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
| 4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
| 5 */ | 5 */ |
| 6 | 6 |
| 7 /* | 7 /* |
| 8 * nc_jumps.c - Validate where valid jumps can occur. | 8 * nc_jumps.c - Validate where valid jumps can occur. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include <assert.h> | 11 #include <assert.h> |
| 12 #include <stdlib.h> | 12 #include <stdlib.h> |
| 13 | 13 |
| 14 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_jumps.h" | 14 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_jumps.h" |
| 15 | 15 |
| 16 #include "native_client/src/shared/platform/nacl_log.h" | 16 #include "native_client/src/shared/platform/nacl_log.h" |
| 17 #include "native_client/src/trusted/validator/x86/decoder/ncop_exps.h" | |
| 18 #include "native_client/src/trusted/validator/x86/decoder/nc_inst_iter.h" | |
| 19 #include "native_client/src/trusted/validator/x86/decoder/nc_inst_state_internal
.h" | 17 #include "native_client/src/trusted/validator/x86/decoder/nc_inst_state_internal
.h" |
| 20 #include "native_client/src/trusted/validator/x86/decoder/nc_inst_trans.h" | 18 #include "native_client/src/trusted/validator/x86/decoder/nc_inst_trans.h" |
| 21 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/address_sets.h" | 19 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/address_sets.h" |
| 22 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter.
h" | 20 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter.
h" |
| 23 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter_
internal.h" | 21 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter_
internal.h" |
| 24 | 22 |
| 25 /* To turn on debugging of instruction decoding, change value of | 23 /* To turn on debugging of instruction decoding, change value of |
| 26 * DEBUGGING to 1. | 24 * DEBUGGING to 1. |
| 27 */ | 25 */ |
| 28 #define DEBUGGING 0 | 26 #define DEBUGGING 0 |
| 29 | 27 |
| 30 #include "native_client/src/shared/utils/debugging.h" | 28 #include "native_client/src/shared/utils/debugging.h" |
| 31 | 29 |
| 30 #include "native_client/src/trusted/validator/x86/decoder/ncop_exps_inl.c" |
| 31 #include "native_client/src/trusted/validator/x86/decoder/nc_inst_iter_inl.c" |
| 32 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/address_sets_inl
.c" |
| 33 |
| 32 Bool NACL_FLAGS_identity_mask = FALSE; | 34 Bool NACL_FLAGS_identity_mask = FALSE; |
| 33 | 35 |
| 34 static INLINE uint8_t NaClGetJumpMask(NaClValidatorState* state) { | 36 static INLINE uint8_t NaClGetJumpMask(NaClValidatorState* state) { |
| 35 return NACL_FLAGS_identity_mask | 37 return NACL_FLAGS_identity_mask |
| 36 ? (uint8_t) 0xFF | 38 ? (uint8_t) 0xFF |
| 37 : (uint8_t) (~state->alignment_mask); | 39 : (uint8_t) (~state->alignment_mask); |
| 38 } | 40 } |
| 39 | 41 |
| 40 /* Generates a jump validator. */ | 42 /* Generates a jump validator. */ |
| 41 NaClJumpSets* NaClJumpValidatorCreate(NaClValidatorState* state) { | 43 NaClJumpSets* NaClJumpValidatorCreate(NaClValidatorState* state) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 81 * Otherwise, only allow if 0 mod 32. | 83 * Otherwise, only allow if 0 mod 32. |
| 82 */ | 84 */ |
| 83 DEBUG(NaClLog(LOG_INFO, "Add jump to jump sets: %" | 85 DEBUG(NaClLog(LOG_INFO, "Add jump to jump sets: %" |
| 84 NACL_PRIxNaClPcAddress" -> %"NACL_PRIxNaClPcAddress"\n", | 86 NACL_PRIxNaClPcAddress" -> %"NACL_PRIxNaClPcAddress"\n", |
| 85 from_address, to_address)); | 87 from_address, to_address)); |
| 86 if (state->vbase <= to_address && to_address < state->vlimit) { | 88 if (state->vbase <= to_address && to_address < state->vlimit) { |
| 87 /* Remember address for checking later. */ | 89 /* Remember address for checking later. */ |
| 88 DEBUG(NaClLog(LOG_INFO, "Add jump to target: %"NACL_PRIxNaClPcAddress | 90 DEBUG(NaClLog(LOG_INFO, "Add jump to target: %"NACL_PRIxNaClPcAddress |
| 89 " -> %"NACL_PRIxNaClPcAddress"\n", | 91 " -> %"NACL_PRIxNaClPcAddress"\n", |
| 90 from_address, to_address)); | 92 from_address, to_address)); |
| 91 NaClAddressSetAdd(jump_sets->actual_targets, to_address, state); | 93 NaClAddressSetAddInline(jump_sets->actual_targets, to_address, state); |
| 92 } | 94 } |
| 93 /* The range check may not be strictly necessary given that we have | 95 /* The range check may not be strictly necessary given that we have |
| 94 * guard regions around the sandbox address space, but it shouldn't | 96 * guard regions around the sandbox address space, but it shouldn't |
| 95 * hurt to disallow branches that overflow or underflow the address | 97 * hurt to disallow branches that overflow or underflow the address |
| 96 * space. | 98 * space. |
| 97 */ | 99 */ |
| 98 else if ((to_address & state->alignment_mask) == 0 && | 100 else if ((to_address & state->alignment_mask) == 0 && |
| 99 (to_address & ~(NaClPcAddress) 0xffffffff) == 0) { | 101 (to_address & ~(NaClPcAddress) 0xffffffff) == 0) { |
| 100 /* Allow bundle-aligned jump. */ | 102 /* Allow bundle-aligned jump. */ |
| 101 } | 103 } |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 NaClJumpSets* jump_sets) { | 197 NaClJumpSets* jump_sets) { |
| 196 uint8_t mask; | 198 uint8_t mask; |
| 197 NaClInstState* and_state; | 199 NaClInstState* and_state; |
| 198 NaClInstState* middle_state; | 200 NaClInstState* middle_state; |
| 199 const NaClInst* and_inst; | 201 const NaClInst* and_inst; |
| 200 const NaClInst* middle_inst; | 202 const NaClInst* middle_inst; |
| 201 int op_1, op_2; | 203 int op_1, op_2; |
| 202 NaClOpKind and_reg, and_64_reg, jump_reg, middle_reg; | 204 NaClOpKind and_reg, and_64_reg, jump_reg, middle_reg; |
| 203 NaClExpVector* nodes; | 205 NaClExpVector* nodes; |
| 204 NaClExp* node; | 206 NaClExp* node; |
| 205 jump_reg = NaClGetExpRegister(reg); | 207 jump_reg = NaClGetExpRegisterInline(reg); |
| 206 DEBUG(NaClLog(LOG_INFO, "checking indirect jump: "); | 208 DEBUG(NaClLog(LOG_INFO, "checking indirect jump: "); |
| 207 NaClInstStateInstPrint(NaClLogGetGio(), inst); | 209 NaClInstStateInstPrint(NaClLogGetGio(), inst); |
| 208 gprintf(NaClLogGetGio(), "jump_reg = %s\n", NaClOpKindName(jump_reg))); | 210 gprintf(NaClLogGetGio(), "jump_reg = %s\n", NaClOpKindName(jump_reg))); |
| 209 | 211 |
| 210 /* Do the following block exactly once. Use loop so that "break" can | 212 /* Do the following block exactly once. Use loop so that "break" can |
| 211 * be used for premature exit of block. | 213 * be used for premature exit of block. |
| 212 */ | 214 */ |
| 213 do { | 215 do { |
| 214 /* Check and in 3 instruction sequence. */ | 216 /* Check and in 3 instruction sequence. */ |
| 215 if (!NaClInstIterHasLookbackState(iter, 2)) break; | 217 if (!NaClInstIterHasLookbackStateInline(iter, 2)) break; |
| 216 and_state = NaClInstIterGetLookbackState(iter, 2); | 218 and_state = NaClInstIterGetLookbackStateInline(iter, 2); |
| 217 DEBUG(NaClLog(LOG_INFO, "and?: "); | 219 DEBUG(NaClLog(LOG_INFO, "and?: "); |
| 218 NaClInstStateInstPrint(NaClLogGetGio(), and_state)); | 220 NaClInstStateInstPrint(NaClLogGetGio(), and_state)); |
| 219 and_inst = NaClInstStateInst(and_state); | 221 and_inst = NaClInstStateInst(and_state); |
| 220 if (((and_state->num_opcode_bytes == 0) || | 222 if (((and_state->num_opcode_bytes == 0) || |
| 221 (0x83 != and_state->bytes.byte[and_state->num_prefix_bytes])) || | 223 (0x83 != and_state->bytes.byte[and_state->num_prefix_bytes])) || |
| 222 InstAnd != and_inst->name) break; | 224 InstAnd != and_inst->name) break; |
| 223 DEBUG(NaClLog(LOG_INFO, "and instruction\n")); | 225 DEBUG(NaClLog(LOG_INFO, "and instruction\n")); |
| 224 | 226 |
| 225 /* Extract the values of the two operands for the and. */ | 227 /* Extract the values of the two operands for the and. */ |
| 226 if (!NaClExtractBinaryOperandIndices(and_state, &op_1, &op_2)) break; | 228 if (!NaClExtractBinaryOperandIndices(and_state, &op_1, &op_2)) break; |
| 227 DEBUG(NaClLog(LOG_INFO, "binary and\n")); | 229 DEBUG(NaClLog(LOG_INFO, "binary and\n")); |
| 228 | 230 |
| 229 /* Extract the destination register of the and. */ | 231 /* Extract the destination register of the and. */ |
| 230 nodes = NaClInstStateExpVector(and_state); | 232 nodes = NaClInstStateExpVector(and_state); |
| 231 node = &nodes->node[op_1]; | 233 node = &nodes->node[op_1]; |
| 232 if (ExprRegister != node->kind) break; | 234 if (ExprRegister != node->kind) break; |
| 233 and_reg = NaClGetExpRegister(node); | 235 and_reg = NaClGetExpRegisterInline(node); |
| 234 DEBUG(NaClLog(LOG_INFO, "and_reg = %s\n", NaClOpKindName(and_reg))); | 236 DEBUG(NaClLog(LOG_INFO, "and_reg = %s\n", NaClOpKindName(and_reg))); |
| 235 and_64_reg = NaClGet64For32BitReg(and_reg); | 237 and_64_reg = NaClGet64For32BitReg(and_reg); |
| 236 DEBUG(NaClLog(LOG_INFO, "and_64_reg = %s\n", NaClOpKindName(and_64_reg))); | 238 DEBUG(NaClLog(LOG_INFO, "and_64_reg = %s\n", NaClOpKindName(and_64_reg))); |
| 237 if (RegUnknown == and_64_reg) break; | 239 if (RegUnknown == and_64_reg) break; |
| 238 DEBUG(NaClLog(LOG_INFO, "registers match!\n")); | 240 DEBUG(NaClLog(LOG_INFO, "registers match!\n")); |
| 239 | 241 |
| 240 /* Check that the mask is ok. */ | 242 /* Check that the mask is ok. */ |
| 241 mask = NaClGetJumpMask(state); | 243 mask = NaClGetJumpMask(state); |
| 242 DEBUG(NaClLog(LOG_INFO, "mask = %"NACL_PRIx8"\n", mask)); | 244 DEBUG(NaClLog(LOG_INFO, "mask = %"NACL_PRIx8"\n", mask)); |
| 243 assert(0 != mask); /* alignment must be either 16 or 32. */ | 245 assert(0 != mask); /* alignment must be either 16 or 32. */ |
| 244 node = &nodes->node[op_2]; | 246 node = &nodes->node[op_2]; |
| 245 if (ExprConstant != node->kind || mask != node->value) break; | 247 if (ExprConstant != node->kind || mask != node->value) break; |
| 246 DEBUG(NaClLog(LOG_INFO, "is mask constant\n")); | 248 DEBUG(NaClLog(LOG_INFO, "is mask constant\n")); |
| 247 | 249 |
| 248 /* Check middle (i.e. lea/add) instruction in 3 instruction sequence. */ | 250 /* Check middle (i.e. lea/add) instruction in 3 instruction sequence. */ |
| 249 middle_state = NaClInstIterGetLookbackState(iter, 1); | 251 middle_state = NaClInstIterGetLookbackStateInline(iter, 1); |
| 250 DEBUG(NaClLog(LOG_INFO, "middle inst: "); | 252 DEBUG(NaClLog(LOG_INFO, "middle inst: "); |
| 251 NaClInstStateInstPrint(NaClLogGetGio(), middle_state)); | 253 NaClInstStateInstPrint(NaClLogGetGio(), middle_state)); |
| 252 middle_inst = NaClInstStateInst(middle_state); | 254 middle_inst = NaClInstStateInst(middle_state); |
| 253 | 255 |
| 254 /* Extract the values of the two operands for the lea/add instruction. */ | 256 /* Extract the values of the two operands for the lea/add instruction. */ |
| 255 if (!NaClExtractBinaryOperandIndices(middle_state, &op_1, &op_2)) break; | 257 if (!NaClExtractBinaryOperandIndices(middle_state, &op_1, &op_2)) break; |
| 256 DEBUG(NaClLog(LOG_INFO, "middle is binary, op_1 index = %d\n", op_1)); | 258 DEBUG(NaClLog(LOG_INFO, "middle is binary, op_1 index = %d\n", op_1)); |
| 257 | 259 |
| 258 /* Extract the destination register of the lea/and, and verify that | 260 /* Extract the destination register of the lea/and, and verify that |
| 259 * it is a register. | 261 * it is a register. |
| 260 */ | 262 */ |
| 261 nodes = NaClInstStateExpVector(middle_state); | 263 nodes = NaClInstStateExpVector(middle_state); |
| 262 node = &nodes->node[op_1]; | 264 node = &nodes->node[op_1]; |
| 263 if (ExprRegister != node->kind) break; | 265 if (ExprRegister != node->kind) break; |
| 264 | 266 |
| 265 /* Compare the middle destination register to the jump register. */ | 267 /* Compare the middle destination register to the jump register. */ |
| 266 middle_reg = NaClGetExpRegister(node); | 268 middle_reg = NaClGetExpRegisterInline(node); |
| 267 DEBUG(NaClLog(LOG_INFO, "middle reg = %s\n", NaClOpKindName(middle_reg))); | 269 DEBUG(NaClLog(LOG_INFO, "middle reg = %s\n", NaClOpKindName(middle_reg))); |
| 268 if (middle_reg != jump_reg) break; | 270 if (middle_reg != jump_reg) break; |
| 269 | 271 |
| 270 if (InstLea == middle_inst->name) { | 272 if (InstLea == middle_inst->name) { |
| 271 /* Check that we have [%RBASE + %REG64-A] as second argument to lea */ | 273 /* Check that we have [%RBASE + %REG64-A] as second argument to lea */ |
| 272 node = &nodes->node[op_2]; | 274 node = &nodes->node[op_2]; |
| 273 if (ExprMemOffset != node->kind || | 275 if (ExprMemOffset != node->kind || |
| 274 !NaClMemOffsetMatchesBaseIndex(nodes, op_2, state->base_register, | 276 !NaClMemOffsetMatchesBaseIndex(nodes, op_2, state->base_register, |
| 275 and_64_reg)) { | 277 and_64_reg)) { |
| 276 break; | 278 break; |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 329 NaClJumpSets* jump_sets | 331 NaClJumpSets* jump_sets |
| 330 ) { | 332 ) { |
| 331 uint8_t mask; | 333 uint8_t mask; |
| 332 NaClInstState* and_state; | 334 NaClInstState* and_state; |
| 333 const NaClInst* and_inst; | 335 const NaClInst* and_inst; |
| 334 int op_1, op_2; | 336 int op_1, op_2; |
| 335 NaClOpKind and_reg, jump_reg; | 337 NaClOpKind and_reg, jump_reg; |
| 336 NaClExpVector* nodes; | 338 NaClExpVector* nodes; |
| 337 NaClExp* node; | 339 NaClExp* node; |
| 338 assert(ExprRegister == reg->kind); | 340 assert(ExprRegister == reg->kind); |
| 339 jump_reg = NaClGetExpRegister(reg); | 341 jump_reg = NaClGetExpRegisterInline(reg); |
| 340 | 342 |
| 341 /* Do the following block exactly once. */ | 343 /* Do the following block exactly once. */ |
| 342 do { | 344 do { |
| 343 /* Check that the jump is preceded with an AND. */ | 345 /* Check that the jump is preceded with an AND. */ |
| 344 if (!NaClInstIterHasLookbackState(iter, 1)) break; | 346 if (!NaClInstIterHasLookbackStateInline(iter, 1)) break; |
| 345 and_state = NaClInstIterGetLookbackState(iter, 1); | 347 and_state = NaClInstIterGetLookbackStateInline(iter, 1); |
| 346 and_inst = NaClInstStateInst(and_state); | 348 and_inst = NaClInstStateInst(and_state); |
| 347 if (((and_state->num_opcode_bytes == 0) || | 349 if (((and_state->num_opcode_bytes == 0) || |
| 348 (0x83 != and_state->bytes.byte[and_state->num_prefix_bytes])) || | 350 (0x83 != and_state->bytes.byte[and_state->num_prefix_bytes])) || |
| 349 InstAnd != and_inst->name) break; | 351 InstAnd != and_inst->name) break; |
| 350 | 352 |
| 351 /* Extract the values of the two operands for the and. */ | 353 /* Extract the values of the two operands for the and. */ |
| 352 if (!NaClExtractBinaryOperandIndices(and_state, &op_1, &op_2)) break; | 354 if (!NaClExtractBinaryOperandIndices(and_state, &op_1, &op_2)) break; |
| 353 | 355 |
| 354 | 356 |
| 355 /* Check that the register of the AND matches the jump. */ | 357 /* Check that the register of the AND matches the jump. */ |
| 356 nodes = NaClInstStateExpVector(and_state); | 358 nodes = NaClInstStateExpVector(and_state); |
| 357 node = &nodes->node[op_1]; | 359 node = &nodes->node[op_1]; |
| 358 if (ExprRegister != node->kind) break; | 360 if (ExprRegister != node->kind) break; |
| 359 and_reg = NaClGetExpRegister(node); | 361 and_reg = NaClGetExpRegisterInline(node); |
| 360 if (jump_reg != and_reg) break; | 362 if (jump_reg != and_reg) break; |
| 361 | 363 |
| 362 /* Check that the mask is ok. */ | 364 /* Check that the mask is ok. */ |
| 363 mask = NaClGetJumpMask(state); | 365 mask = NaClGetJumpMask(state); |
| 364 assert(0 != mask); /* alignment must be either 16 or 32. */ | 366 assert(0 != mask); /* alignment must be either 16 or 32. */ |
| 365 node = &nodes->node[op_2]; | 367 node = &nodes->node[op_2]; |
| 366 if (ExprConstant != node->kind || mask != node->value) break; | 368 if (ExprConstant != node->kind || mask != node->value) break; |
| 367 | 369 |
| 368 /* If reached, indirect jump is properly masked. */ | 370 /* If reached, indirect jump is properly masked. */ |
| 369 DEBUG(NaClLog(LOG_INFO, "Protect register jump indirect\n")); | 371 DEBUG(NaClLog(LOG_INFO, "Protect register jump indirect\n")); |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 477 NaClPcAddress pc, | 479 NaClPcAddress pc, |
| 478 NaClInstState* inst_state, | 480 NaClInstState* inst_state, |
| 479 NaClJumpSets* jump_sets) { | 481 NaClJumpSets* jump_sets) { |
| 480 if (pc < state->vbase || pc >= state->vlimit) { | 482 if (pc < state->vbase || pc >= state->vlimit) { |
| 481 NaClValidatorInstMessage(LOG_ERROR, state, inst_state, | 483 NaClValidatorInstMessage(LOG_ERROR, state, inst_state, |
| 482 "Instruction pc out of range\n"); | 484 "Instruction pc out of range\n"); |
| 483 } else { | 485 } else { |
| 484 DEBUG(NaClLog(LOG_INFO, | 486 DEBUG(NaClLog(LOG_INFO, |
| 485 "Add possible jump address: %"NACL_PRIxNaClPcAddress"\n", | 487 "Add possible jump address: %"NACL_PRIxNaClPcAddress"\n", |
| 486 pc)); | 488 pc)); |
| 487 NaClAddressSetAdd(jump_sets->possible_targets, pc, state); | 489 NaClAddressSetAddInline(jump_sets->possible_targets, pc, state); |
| 488 } | 490 } |
| 489 } | 491 } |
| 490 | 492 |
| 491 void NaClJumpValidatorRememberIpOnly(NaClValidatorState* state, | 493 void NaClJumpValidatorRememberIpOnly(NaClValidatorState* state, |
| 492 NaClInstIter* iter, | 494 NaClInstIter* iter, |
| 493 NaClJumpSets* jump_sets) { | 495 NaClJumpSets* jump_sets) { |
| 494 NaClInstState* inst_state = state->cur_inst_state; | 496 NaClInstState* inst_state = state->cur_inst_state; |
| 495 NaClPcAddress pc = NaClInstStateVpc(inst_state); | 497 NaClPcAddress pc = NaClInstStateVpc(inst_state); |
| 496 NaClRememberIp(state, pc, inst_state, jump_sets); | 498 NaClRememberIp(state, pc, inst_state, jump_sets); |
| 497 } | 499 } |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 628 */ | 630 */ |
| 629 } else { | 631 } else { |
| 630 NaClJumpSets* jump_sets = | 632 NaClJumpSets* jump_sets = |
| 631 (NaClJumpSets*) | 633 (NaClJumpSets*) |
| 632 NaClGetValidatorLocalMemory((NaClValidator) NaClJumpValidator, | 634 NaClGetValidatorLocalMemory((NaClValidator) NaClJumpValidator, |
| 633 state); | 635 state); |
| 634 DEBUG(NaClLog(LOG_INFO, | 636 DEBUG(NaClLog(LOG_INFO, |
| 635 "Mark instruction as jump illegal: %"NACL_PRIxNaClPcAddress | 637 "Mark instruction as jump illegal: %"NACL_PRIxNaClPcAddress |
| 636 "\n", | 638 "\n", |
| 637 pc)); | 639 pc)); |
| 638 NaClAddressSetAdd(jump_sets->removed_targets, pc, state); | 640 NaClAddressSetAddInline(jump_sets->removed_targets, pc, state); |
| 639 } | 641 } |
| 640 } | 642 } |
| OLD | NEW |