| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. | 2 * Copyright (c) 2012 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 /* Implement the ApplyValidator API for the x86-64 architecture. */ | 7 /* Implement the ApplyValidator API for the x86-64 architecture. */ |
| 8 #include <assert.h> | 8 #include <assert.h> |
| 9 #include "native_client/src/shared/platform/nacl_log.h" | 9 #include "native_client/src/shared/platform/nacl_log.h" |
| 10 #include "native_client/src/trusted/validator/ncvalidate.h" | 10 #include "native_client/src/trusted/validator/ncvalidate.h" |
| 11 #include "native_client/src/trusted/validator/validation_cache.h" | 11 #include "native_client/src/trusted/validator/validation_cache.h" |
| 12 #include "native_client/src/trusted/validator/x86/decoder/nc_inst_iter.h" |
| 13 #include "native_client/src/trusted/validator/x86/decoder/nc_inst_state_internal
.h" |
| 14 #include "native_client/src/trusted/validator/x86/nc_segment.h" |
| 15 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncval_decode_tab
les.h" |
| 12 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter.
h" | 16 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter.
h" |
| 13 | 17 |
| 14 /* Be sure the correct compile flags are defined for this. */ | 18 /* Be sure the correct compile flags are defined for this. */ |
| 15 #if NACL_ARCH(NACL_TARGET_ARCH) != NACL_x86 | 19 #if NACL_ARCH(NACL_TARGET_ARCH) != NACL_x86 |
| 16 # error("Can't compile, target is for x86-64") | 20 # error("Can't compile, target is for x86-64") |
| 17 #else | 21 #else |
| 18 # if NACL_TARGET_SUBARCH != 64 | 22 # if NACL_TARGET_SUBARCH != 64 |
| 19 # error("Can't compile, target is for x86-64") | 23 # error("Can't compile, target is for x86-64") |
| 20 # endif | 24 # endif |
| 21 #endif | 25 #endif |
| 22 | 26 |
| 23 NaClValidationStatus NaClValidatorSetup_x86_64( | 27 NaClValidationStatus NaClValidatorSetup_x86_64( |
| 24 intptr_t guest_addr, | 28 intptr_t guest_addr, |
| 25 size_t size, | 29 size_t size, |
| 26 int readonly_text, | 30 int readonly_text, |
| 27 const NaClCPUFeaturesX86 *cpu_features, | 31 const NaClCPUFeaturesX86 *cpu_features, |
| 28 struct NaClValidatorState** vstate_ptr) { | 32 struct NaClValidatorState** vstate_ptr) { |
| 29 *vstate_ptr = NaClValidatorStateCreate(guest_addr, size, RegR15, | 33 *vstate_ptr = NaClValidatorStateCreate(guest_addr, size, RegR15, |
| 30 readonly_text, cpu_features); | 34 readonly_text, cpu_features); |
| 31 return (*vstate_ptr == NULL) | 35 return (*vstate_ptr == NULL) |
| 32 ? NaClValidationFailedOutOfMemory | 36 ? NaClValidationFailedOutOfMemory |
| 33 : NaClValidationSucceeded; /* or at least to this point! */ | 37 : NaClValidationSucceeded; /* or at least to this point! */ |
| 34 } | 38 } |
| 35 | 39 |
| 36 NaClValidationStatus NACL_SUBARCH_NAME(ApplyValidator, x86, 64) ( | 40 static NaClValidationStatus ApplyValidator_x86_64( |
| 37 uintptr_t guest_addr, | 41 uintptr_t guest_addr, |
| 38 uint8_t *data, | 42 uint8_t *data, |
| 39 size_t size, | 43 size_t size, |
| 40 int stubout_mode, | 44 int stubout_mode, |
| 41 int readonly_text, | 45 int readonly_text, |
| 42 const NaClCPUFeaturesX86 *cpu_features, | 46 const NaClCPUFeaturesX86 *cpu_features, |
| 43 struct NaClValidationCache *cache) { | 47 struct NaClValidationCache *cache) { |
| 44 struct NaClValidatorState *vstate; | 48 struct NaClValidatorState *vstate; |
| 45 NaClValidationStatus status; | 49 NaClValidationStatus status; |
| 46 void *query = NULL; | 50 void *query = NULL; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 91 /* Don't cache the result if the code is modified. */ | 95 /* Don't cache the result if the code is modified. */ |
| 92 if (status == NaClValidationSucceeded && !NaClValidatorDidStubOut(vstate)) | 96 if (status == NaClValidationSucceeded && !NaClValidatorDidStubOut(vstate)) |
| 93 cache->SetKnownToValidate(query); | 97 cache->SetKnownToValidate(query); |
| 94 cache->DestroyQuery(query); | 98 cache->DestroyQuery(query); |
| 95 } | 99 } |
| 96 | 100 |
| 97 NaClValidatorStateDestroy(vstate); | 101 NaClValidatorStateDestroy(vstate); |
| 98 return status; | 102 return status; |
| 99 } | 103 } |
| 100 | 104 |
| 101 NaClValidationStatus NACL_SUBARCH_NAME(ApplyValidatorCodeReplacement, x86, 64) | 105 static NaClValidationStatus ApplyValidatorCodeReplacement_x86_64( |
| 102 (uintptr_t guest_addr, | 106 uintptr_t guest_addr, |
| 103 uint8_t *data_old, | 107 uint8_t *data_old, |
| 104 uint8_t *data_new, | 108 uint8_t *data_new, |
| 105 size_t size, | 109 size_t size, |
| 106 const NaClCPUFeaturesX86 *cpu_features) { | 110 const NaClCPUFeaturesX86 *cpu_features) { |
| 107 NaClValidationStatus status; | 111 NaClValidationStatus status; |
| 108 struct NaClValidatorState *vstate; | 112 struct NaClValidatorState *vstate; |
| 109 | 113 |
| 110 /* Check that the given parameter values are supported. */ | 114 /* Check that the given parameter values are supported. */ |
| 111 if (!NaClArchSupported(cpu_features)) | 115 if (!NaClArchSupported(cpu_features)) |
| 112 return NaClValidationFailedCpuNotSupported; | 116 return NaClValidationFailedCpuNotSupported; |
| 113 | 117 |
| 114 /* Init then validator state. */ | 118 /* Init then validator state. */ |
| 115 status = NaClValidatorSetup_x86_64(guest_addr, size, FALSE, | 119 status = NaClValidatorSetup_x86_64(guest_addr, size, FALSE, |
| 116 cpu_features, &vstate); | 120 cpu_features, &vstate); |
| 117 if (status != NaClValidationSucceeded) | 121 if (status != NaClValidationSucceeded) |
| 118 return status; | 122 return status; |
| 119 NaClValidatorStateSetLogVerbosity(vstate, LOG_ERROR); | 123 NaClValidatorStateSetLogVerbosity(vstate, LOG_ERROR); |
| 120 | 124 |
| 121 /* Validate. */ | 125 /* Validate. */ |
| 122 NaClValidateSegmentPair(data_old, data_new, guest_addr, size, vstate); | 126 NaClValidateSegmentPair(data_old, data_new, guest_addr, size, vstate); |
| 123 status = NaClValidatesOk(vstate) ? | 127 status = NaClValidatesOk(vstate) ? |
| 124 NaClValidationSucceeded : NaClValidationFailed; | 128 NaClValidationSucceeded : NaClValidationFailed; |
| 125 | 129 |
| 126 NaClValidatorStateDestroy(vstate); | 130 NaClValidatorStateDestroy(vstate); |
| 127 return status; | 131 return status; |
| 128 } | 132 } |
| 133 |
| 134 /* Copies code from src to dest in a thread safe way, returns 1 on success, |
| 135 * returns 0 on error. This will likely assert on error to avoid partially |
| 136 * copied code or undefined state. |
| 137 */ |
| 138 static int CopyCodeIter(uint8_t *dst, uint8_t *src, |
| 139 NaClPcAddress vbase, size_t size, |
| 140 NaClCopyInstructionFunc copy_func) { |
| 141 NaClSegment segment_old, segment_new; |
| 142 NaClInstIter *iter_old, *iter_new; |
| 143 NaClInstState *istate_old, *istate_new; |
| 144 int still_good = 1; |
| 145 |
| 146 NaClSegmentInitialize(dst, vbase, size, &segment_old); |
| 147 NaClSegmentInitialize(src, vbase, size, &segment_new); |
| 148 |
| 149 iter_old = NaClInstIterCreate(kNaClValDecoderTables, &segment_old); |
| 150 if (NULL == iter_old) return 0; |
| 151 iter_new = NaClInstIterCreate(kNaClValDecoderTables, &segment_new); |
| 152 if (NULL == iter_new) { |
| 153 NaClInstIterDestroy(iter_old); |
| 154 return 0; |
| 155 } |
| 156 while (1) { |
| 157 /* March over every instruction, which means NaCl pseudo-instructions are |
| 158 * treated as multiple instructions. Checks in NaClValidateCodeReplacement |
| 159 * guarantee that only valid replacements will happen, and no pseudo- |
| 160 * instructions should be touched. |
| 161 */ |
| 162 if (!(NaClInstIterHasNext(iter_old) && NaClInstIterHasNext(iter_new))) { |
| 163 if (NaClInstIterHasNext(iter_old) || NaClInstIterHasNext(iter_new)) { |
| 164 NaClLog(LOG_ERROR, |
| 165 "Segment replacement: copy failed: iterators " |
| 166 "length mismatch\n"); |
| 167 still_good = 0; |
| 168 } |
| 169 break; |
| 170 } |
| 171 istate_old = NaClInstIterGetState(iter_old); |
| 172 istate_new = NaClInstIterGetState(iter_new); |
| 173 if (istate_old->bytes.length != istate_new->bytes.length || |
| 174 iter_old->memory.read_length != iter_new->memory.read_length || |
| 175 istate_new->inst_addr != istate_old->inst_addr) { |
| 176 /* Sanity check: this should never happen based on checks in |
| 177 * NaClValidateInstReplacement. |
| 178 */ |
| 179 NaClLog(LOG_ERROR, |
| 180 "Segment replacement: copied instructions misaligned\n"); |
| 181 still_good = 0; |
| 182 break; |
| 183 } |
| 184 /* Replacing all modified instructions at once could yield a speedup here |
| 185 * as every time we modify instructions we must serialize all processors |
| 186 * twice. Re-evaluate if code modification performance is an issue. |
| 187 */ |
| 188 if (!copy_func(iter_old->memory.mpc, iter_new->memory.mpc, |
| 189 iter_old->memory.read_length)) { |
| 190 NaClLog(LOG_ERROR, |
| 191 "Segment replacement: copy failed: unable to copy instruction\n"); |
| 192 still_good = 0; |
| 193 break; |
| 194 } |
| 195 NaClInstIterAdvance(iter_old); |
| 196 NaClInstIterAdvance(iter_new); |
| 197 } |
| 198 |
| 199 NaClInstIterDestroy(iter_old); |
| 200 NaClInstIterDestroy(iter_new); |
| 201 return still_good; |
| 202 } |
| 203 |
| 204 static NaClValidationStatus ApplyValidatorCopy_x86_64( |
| 205 uintptr_t guest_addr, |
| 206 uint8_t *data_old, |
| 207 uint8_t *data_new, |
| 208 size_t size, |
| 209 const NaClCPUFeaturesX86 *cpu_features, |
| 210 NaClCopyInstructionFunc copy_func) { |
| 211 if (!NaClArchSupported(cpu_features)) |
| 212 return NaClValidationFailedCpuNotSupported; |
| 213 |
| 214 return (0 == CopyCodeIter(data_old, data_new, guest_addr, size, copy_func)) |
| 215 ? NaClValidationFailed : NaClValidationSucceeded; |
| 216 } |
| 217 |
| 218 static const struct NaClValidatorInterface validator = { |
| 219 ApplyValidator_x86_64, |
| 220 ApplyValidatorCopy_x86_64, |
| 221 ApplyValidatorCodeReplacement_x86_64, |
| 222 }; |
| 223 |
| 224 const struct NaClValidatorInterface *NaClValidatorCreate_x86_64() { |
| 225 return &validator; |
| 226 } |
| OLD | NEW |