Index: src/trusted/validator_x86/ncvalidate_iter.c |
=================================================================== |
--- src/trusted/validator_x86/ncvalidate_iter.c (revision 3655) |
+++ src/trusted/validator_x86/ncvalidate_iter.c (working copy) |
@@ -14,7 +14,7 @@ |
#include <string.h> |
#include "native_client/src/trusted/validator_x86/ncvalidate_iter.h" |
- |
+#include "native_client/src/shared/platform/nacl_check.h" |
#include "native_client/src/shared/platform/nacl_log.h" |
#include "native_client/src/trusted/validator_x86/nc_inst_iter.h" |
#include "native_client/src/trusted/validator_x86/nc_inst_state_internal.h" |
@@ -246,10 +246,12 @@ |
/* TODO(karl) - Make printing of instruction state possible via format. */ |
NaClInstStateInstPrint(g, inst); |
- va_start(ap, format); |
- NaClLog_mu(level, "VALIDATOR: %s", NaClLogLevelLabel(level)); |
- NaClLogV_mu(level, format, ap); |
- va_end(ap); |
+ if (format != NULL) { |
bsy
2010/11/11 21:27:21
when do we get NULL format strings? this sounds l
petr
2010/11/12 18:11:06
I use this to print two instructions in a row, see
|
+ va_start(ap, format); |
+ NaClLog_mu(level, "VALIDATOR: %s", NaClLogLevelLabel(level)); |
+ NaClLogV_mu(level, format, ap); |
+ va_end(ap); |
+ } |
NaClLogUnlock(); |
NaClRecordErrorReported(state, level); |
} |
@@ -449,3 +451,162 @@ |
} |
return NULL; |
} |
+ |
+/* |
+ * Check that iter_new is a valid replacement for iter_old. |
+ * If a validation error occurs, state->validates_ok will be set to false by |
+ * NaClValidatorInstMessage when it is given LOG_ERROR, see the end of this |
+ * function. |
+ */ |
+static void NaClValidateInstReplacement(NaClInstIter* iter_old, |
+ NaClInstIter* iter_new, |
+ struct NaClValidatorState* state) { |
+ NaClInstState *istate_old, *istate_new; |
+ NaClExpVector *exp_old, *exp_new; |
+ uint32_t i; |
+ |
+ istate_old = NaClInstIterGetState(iter_old); |
+ istate_new = NaClInstIterGetState(iter_new); |
+ |
+ /* Location/length must match */ |
+ if (istate_new->vpc != istate_old->vpc || |
+ istate_new->length != istate_old->length) { |
+ NaClValidatorMessage(LOG_ERROR, state, |
+ "Code modification: instructions length/addresses do not match\n"); |
+ NaClValidatorInstMessage(LOG_ERROR, state, istate_old, NULL); |
+ NaClValidatorInstMessage(LOG_ERROR, state, istate_new, NULL); |
+ return; |
+ } |
+ |
+ |
+ do { |
+ /* fast check if the replacement is identical */ |
+ if (!memcmp(istate_old->mpc, istate_new->mpc, istate_old->length)) |
+ return; |
+ |
+ if (istate_old->num_prefix_bytes != istate_new->num_prefix_bytes) |
+ break; |
+ if (istate_old->num_rex_prefixes != istate_new->num_rex_prefixes) |
+ break; |
+ if (istate_old->rexprefix != istate_new->rexprefix) |
+ break; |
+ if (istate_old->modrm != istate_new->modrm) |
+ break; |
+ if (istate_old->has_sib != istate_new->has_sib) |
+ break; |
+ if (istate_old->has_sib && istate_old->sib != istate_new->sib) |
+ break; |
+ if (istate_old->operand_size != istate_new->operand_size) |
+ break; |
+ if (istate_old->address_size != istate_new->address_size) |
+ break; |
+ if (istate_old->prefix_mask != istate_new->prefix_mask) |
+ break; |
+ |
+ /* |
+ * these are pointers, but they reference entries in a static table, |
+ * so if the two instructions are the same, then these pointers must |
+ * reference the same entry |
+ */ |
+ if (istate_old->inst != istate_new->inst) |
+ break; |
+ |
+ exp_old = NaClInstStateExpVector(istate_old); |
+ exp_new = NaClInstStateExpVector(istate_new); |
+ |
+ /* check if the instruction operands are identical */ |
+ if (exp_old->number_expr_nodes != exp_new->number_expr_nodes) |
+ break; |
+ |
+ for (i = 0; i < exp_old->number_expr_nodes; i++) { |
+ if (exp_old->node[i].kind != exp_new->node[i].kind) |
+ break; |
+ if (exp_old->node[i].flags != exp_new->node[i].flags) |
+ break; |
+ |
+ /* |
+ * allow some constants to be different; however it is important not to |
+ * allow modification of sandboxing instructions. Note nether of the |
+ * instructions allowed for modification is used for sandboxing |
+ */ |
+ if (exp_old->node[i].value != exp_new->node[i].value) { |
+ if (exp_old->node[i].kind == ExprConstant) { |
+ |
+ /* allow different constants in direct calls */ |
+ if (istate_old->inst->name == InstCall) |
+ if (exp_old->node[i].flags & NACL_EFLAG(ExprJumpTarget)) |
+ if (exp_old->node[NaClGetExpParentIndex(exp_old, i)].kind |
+ == OperandReference) |
+ continue; |
+ |
+ /* |
+ * allow different constants in operand of mov |
+ * e.g. mov $rax, 0xdeadbeef |
+ */ |
+ if (istate_old->inst->name == InstMov) |
+ if (exp_old->node[i].flags & NACL_EFLAG(ExprUsed)) |
+ if (exp_old->node[NaClGetExpParentIndex(exp_old, i)].kind |
+ == OperandReference) |
+ continue; |
+ /* |
+ * allow different displacements in memory reference of mov |
+ * instructions e.g. mov $rax, [$r15+$rbx*2+0x7fff] |
+ */ |
+ if (istate_old->inst->name == InstMov) |
+ if (exp_old->node[NaClGetExpParentIndex(exp_old, i)].kind |
+ == ExprMemOffset) |
+ /* displacement is the fourth node after ExprMemOffset node */ |
+ if (i - NaClGetExpParentIndex(exp_old, i) == 4) |
+ continue; |
+ } |
+ break; |
+ } |
+ } |
+ |
+ return; |
+ } while (0); |
+ |
+ NaClValidatorMessage(LOG_ERROR, state, |
+ "Code modification: failed to modify instructions\n"); |
+ NaClValidatorInstMessage(LOG_ERROR, state, istate_old, NULL); |
bsy
2010/11/11 21:27:21
are these two lines the only places where the form
Karl
2010/11/11 22:45:41
I think that you may just want to add a new "messa
petr
2010/11/12 18:11:06
Yes, they are
On 2010/11/11 21:27:21, bsy wrote:
petr
2010/11/12 18:11:06
Yes, I will do this
On 2010/11/11 22:45:41, Karl
|
+ NaClValidatorInstMessage(LOG_ERROR, state, istate_new, NULL); |
+} |
+ |
+void NaClValidateSegmentPair(uint8_t* mbase_old, uint8_t* mbase_new, |
+ NaClPcAddress vbase, size_t size, |
+ struct NaClValidatorState* state) { |
+ NaClSegment segment_old, segment_new; |
+ NaClInstIter *iter_old, *iter_new; |
+ |
+ NaClValidatorStateInitializeValidators(state); |
+ NaClSegmentInitialize(mbase_old, vbase, size, &segment_old); |
+ NaClSegmentInitialize(mbase_new, vbase, size, &segment_new); |
+ iter_old = NaClInstIterCreateWithLookback(&segment_old, kLookbackSize); |
+ iter_new = NaClInstIterCreateWithLookback(&segment_new, kLookbackSize); |
+ while (NaClInstIterHasNext(iter_old) && |
+ NaClInstIterHasNext(iter_new)) { |
+ state->cur_inst_state = NaClInstIterGetState(iter_new); |
+ state->cur_inst = NaClInstStateInst(state->cur_inst_state); |
+ state->cur_inst_vector = NaClInstStateExpVector(state->cur_inst_state); |
+ NaClApplyValidators(state, iter_new); |
+ NaClValidateInstReplacement(iter_old, iter_new, state); |
+ if (state->quit) break; |
+ NaClInstIterAdvance(iter_old); |
+ NaClInstIterAdvance(iter_new); |
+ } |
+ |
+ if (NaClInstIterHasNext(iter_old) || |
+ NaClInstIterHasNext(iter_new)) { |
+ NaClValidatorMessage(LOG_ERROR, state, |
+ "Code modification: code segments have different number of instructions\n"); |
+ } |
+ |
+ state->cur_inst_state = NULL; |
+ state->cur_inst = NULL; |
+ state->cur_inst_vector = NULL; |
+ NaClApplyPostValidators(state, iter_new); |
+ NaClInstIterDestroy(iter_old); |
+ NaClInstIterDestroy(iter_new); |
+ NaClValidatorStatePrintStats(state); |
+} |
+ |