| OLD | NEW |
| (Empty) |
| 1 /* | |
| 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 | |
| 4 * found in the LICENSE file. | |
| 5 */ | |
| 6 | |
| 7 /* Implement the ApplyValidator API for the x86-64 architecture. */ | |
| 8 #include <assert.h> | |
| 9 #include "native_client/src/shared/platform/nacl_log.h" | |
| 10 #include "native_client/src/trusted/validator/ncvalidate.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/cpu_features/arch/x86/cpu_x86.h" | |
| 15 #include "native_client/src/trusted/validator/x86/nc_segment.h" | |
| 16 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncval_decode_tab
les.h" | |
| 17 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter.
h" | |
| 18 | |
| 19 /* Be sure the correct compile flags are defined for this. */ | |
| 20 #if NACL_ARCH(NACL_TARGET_ARCH) != NACL_x86 | |
| 21 # error("Can't compile, target is for x86-64") | |
| 22 #else | |
| 23 # if NACL_TARGET_SUBARCH != 64 | |
| 24 # error("Can't compile, target is for x86-64") | |
| 25 # endif | |
| 26 #endif | |
| 27 | |
| 28 NaClValidationStatus NaClValidatorSetup_x86_64( | |
| 29 intptr_t guest_addr, | |
| 30 size_t size, | |
| 31 int readonly_text, | |
| 32 const NaClCPUFeaturesX86 *cpu_features, | |
| 33 struct NaClValidatorState** vstate_ptr) { | |
| 34 *vstate_ptr = NaClValidatorStateCreate(guest_addr, size, RegR15, | |
| 35 readonly_text, cpu_features); | |
| 36 return (*vstate_ptr == NULL) | |
| 37 ? NaClValidationFailedOutOfMemory | |
| 38 : NaClValidationSucceeded; /* or at least to this point! */ | |
| 39 } | |
| 40 | |
| 41 static NaClValidationStatus ApplyValidator_x86_64( | |
| 42 uintptr_t guest_addr, | |
| 43 uint8_t *data, | |
| 44 size_t size, | |
| 45 int stubout_mode, | |
| 46 int readonly_text, | |
| 47 const NaClCPUFeatures *f, | |
| 48 const struct NaClValidationMetadata *metadata, | |
| 49 struct NaClValidationCache *cache) { | |
| 50 /* TODO(jfb) Use a safe cast here. */ | |
| 51 const NaClCPUFeaturesX86 *cpu_features = (NaClCPUFeaturesX86 *) f; | |
| 52 struct NaClValidatorState *vstate; | |
| 53 NaClValidationStatus status; | |
| 54 void *query = NULL; | |
| 55 | |
| 56 /* Check that the given parameter values are supported. */ | |
| 57 if (stubout_mode && readonly_text) | |
| 58 return NaClValidationFailedNotImplemented; | |
| 59 | |
| 60 if (!NaClArchSupportedX86(cpu_features)) | |
| 61 return NaClValidationFailedCpuNotSupported; | |
| 62 | |
| 63 /* Don't cache in stubout mode. */ | |
| 64 if (stubout_mode) | |
| 65 cache = NULL; | |
| 66 | |
| 67 /* If the validation caching interface is available, perform a query. */ | |
| 68 if (cache != NULL) | |
| 69 query = cache->CreateQuery(cache->handle); | |
| 70 if (query != NULL) { | |
| 71 const char validator_id[] = "x86-64"; | |
| 72 cache->AddData(query, (uint8_t *) validator_id, sizeof(validator_id)); | |
| 73 cache->AddData(query, (uint8_t *) cpu_features, sizeof(*cpu_features)); | |
| 74 NaClAddCodeIdentity(data, size, metadata, cache, query); | |
| 75 if (cache->QueryKnownToValidate(query)) { | |
| 76 cache->DestroyQuery(query); | |
| 77 return NaClValidationSucceeded; | |
| 78 } | |
| 79 } | |
| 80 | |
| 81 /* Init then validator state. */ | |
| 82 status = NaClValidatorSetup_x86_64( | |
| 83 guest_addr, size, readonly_text, cpu_features, &vstate); | |
| 84 if (status != NaClValidationSucceeded) { | |
| 85 if (query != NULL) | |
| 86 cache->DestroyQuery(query); | |
| 87 return status; | |
| 88 } | |
| 89 NaClValidatorStateSetLogVerbosity(vstate, LOG_ERROR); | |
| 90 NaClValidatorStateSetDoStubOut(vstate, stubout_mode); | |
| 91 | |
| 92 /* Validate. */ | |
| 93 NaClValidateSegment(data, guest_addr, size, vstate); | |
| 94 status = (NaClValidatesOk(vstate) || stubout_mode) ? | |
| 95 NaClValidationSucceeded : NaClValidationFailed; | |
| 96 | |
| 97 /* Cache the result if validation succeded and the code was not modified. */ | |
| 98 if (query != NULL) { | |
| 99 /* Don't cache the result if the code is modified. */ | |
| 100 if (status == NaClValidationSucceeded && !NaClValidatorDidStubOut(vstate)) | |
| 101 cache->SetKnownToValidate(query); | |
| 102 cache->DestroyQuery(query); | |
| 103 } | |
| 104 | |
| 105 NaClValidatorStateDestroy(vstate); | |
| 106 return status; | |
| 107 } | |
| 108 | |
| 109 static NaClValidationStatus ApplyValidatorCodeReplacement_x86_64( | |
| 110 uintptr_t guest_addr, | |
| 111 uint8_t *data_old, | |
| 112 uint8_t *data_new, | |
| 113 size_t size, | |
| 114 const NaClCPUFeatures *f) { | |
| 115 /* TODO(jfb) Use a safe cast here. */ | |
| 116 const NaClCPUFeaturesX86 *cpu_features = (NaClCPUFeaturesX86 *) f; | |
| 117 NaClValidationStatus status; | |
| 118 struct NaClValidatorState *vstate; | |
| 119 | |
| 120 /* Check that the given parameter values are supported. */ | |
| 121 if (!NaClArchSupportedX86(cpu_features)) | |
| 122 return NaClValidationFailedCpuNotSupported; | |
| 123 | |
| 124 /* Init then validator state. */ | |
| 125 status = NaClValidatorSetup_x86_64(guest_addr, size, FALSE, | |
| 126 cpu_features, &vstate); | |
| 127 if (status != NaClValidationSucceeded) | |
| 128 return status; | |
| 129 NaClValidatorStateSetLogVerbosity(vstate, LOG_ERROR); | |
| 130 | |
| 131 /* Validate. */ | |
| 132 NaClValidateSegmentPair(data_old, data_new, guest_addr, size, vstate); | |
| 133 status = NaClValidatesOk(vstate) ? | |
| 134 NaClValidationSucceeded : NaClValidationFailed; | |
| 135 | |
| 136 NaClValidatorStateDestroy(vstate); | |
| 137 return status; | |
| 138 } | |
| 139 | |
| 140 /* Copies code from src to dest in a thread safe way, returns 1 on success, | |
| 141 * returns 0 on error. This will likely assert on error to avoid partially | |
| 142 * copied code or undefined state. | |
| 143 */ | |
| 144 static int CopyCodeIter(uint8_t *dst, uint8_t *src, | |
| 145 NaClPcAddress vbase, size_t size, | |
| 146 NaClCopyInstructionFunc copy_func) { | |
| 147 NaClSegment segment_old; | |
| 148 NaClSegment segment_new; | |
| 149 NaClInstIter *iter_old; | |
| 150 NaClInstIter *iter_new; | |
| 151 NaClInstState *istate_old; | |
| 152 NaClInstState *istate_new; | |
| 153 int still_good = 1; | |
| 154 | |
| 155 NaClSegmentInitialize(dst, vbase, size, &segment_old); | |
| 156 NaClSegmentInitialize(src, vbase, size, &segment_new); | |
| 157 | |
| 158 iter_old = NaClInstIterCreate(kNaClValDecoderTables, &segment_old); | |
| 159 if (NULL == iter_old) return 0; | |
| 160 iter_new = NaClInstIterCreate(kNaClValDecoderTables, &segment_new); | |
| 161 if (NULL == iter_new) { | |
| 162 NaClInstIterDestroy(iter_old); | |
| 163 return 0; | |
| 164 } | |
| 165 while (1) { | |
| 166 /* March over every instruction, which means NaCl pseudo-instructions are | |
| 167 * treated as multiple instructions. Checks in NaClValidateCodeReplacement | |
| 168 * guarantee that only valid replacements will happen, and no pseudo- | |
| 169 * instructions should be touched. | |
| 170 */ | |
| 171 if (!(NaClInstIterHasNext(iter_old) && NaClInstIterHasNext(iter_new))) { | |
| 172 if (NaClInstIterHasNext(iter_old) || NaClInstIterHasNext(iter_new)) { | |
| 173 NaClLog(LOG_ERROR, | |
| 174 "Segment replacement: copy failed: iterators " | |
| 175 "length mismatch\n"); | |
| 176 still_good = 0; | |
| 177 } | |
| 178 break; | |
| 179 } | |
| 180 istate_old = NaClInstIterGetState(iter_old); | |
| 181 istate_new = NaClInstIterGetState(iter_new); | |
| 182 if (istate_old->bytes.length != istate_new->bytes.length || | |
| 183 iter_old->memory.read_length != iter_new->memory.read_length || | |
| 184 istate_new->inst_addr != istate_old->inst_addr) { | |
| 185 /* Sanity check: this should never happen based on checks in | |
| 186 * NaClValidateInstReplacement. | |
| 187 */ | |
| 188 NaClLog(LOG_ERROR, | |
| 189 "Segment replacement: copied instructions misaligned\n"); | |
| 190 still_good = 0; | |
| 191 break; | |
| 192 } | |
| 193 /* Replacing all modified instructions at once could yield a speedup here | |
| 194 * as every time we modify instructions we must serialize all processors | |
| 195 * twice. Re-evaluate if code modification performance is an issue. | |
| 196 */ | |
| 197 if (!copy_func(iter_old->memory.mpc, iter_new->memory.mpc, | |
| 198 iter_old->memory.read_length)) { | |
| 199 NaClLog(LOG_ERROR, | |
| 200 "Segment replacement: copy failed: unable to copy instruction\n"); | |
| 201 still_good = 0; | |
| 202 break; | |
| 203 } | |
| 204 NaClInstIterAdvance(iter_old); | |
| 205 NaClInstIterAdvance(iter_new); | |
| 206 } | |
| 207 | |
| 208 NaClInstIterDestroy(iter_old); | |
| 209 NaClInstIterDestroy(iter_new); | |
| 210 return still_good; | |
| 211 } | |
| 212 | |
| 213 static NaClValidationStatus ApplyValidatorCopy_x86_64( | |
| 214 uintptr_t guest_addr, | |
| 215 uint8_t *data_old, | |
| 216 uint8_t *data_new, | |
| 217 size_t size, | |
| 218 const NaClCPUFeatures *f, | |
| 219 NaClCopyInstructionFunc copy_func) { | |
| 220 /* TODO(jfb) Use a safe cast here. */ | |
| 221 const NaClCPUFeaturesX86 *cpu_features = (NaClCPUFeaturesX86 *) f; | |
| 222 if (!NaClArchSupportedX86(cpu_features)) | |
| 223 return NaClValidationFailedCpuNotSupported; | |
| 224 | |
| 225 return (0 == CopyCodeIter(data_old, data_new, guest_addr, size, copy_func)) | |
| 226 ? NaClValidationFailed : NaClValidationSucceeded; | |
| 227 } | |
| 228 | |
| 229 static const struct NaClValidatorInterface validator = { | |
| 230 TRUE, /* Optional stubout_mode is implemented. */ | |
| 231 TRUE, /* Optional readonly_text is implemented. */ | |
| 232 TRUE, /* Optional code replacement functions are implemented. */ | |
| 233 ApplyValidator_x86_64, | |
| 234 ApplyValidatorCopy_x86_64, | |
| 235 ApplyValidatorCodeReplacement_x86_64, | |
| 236 sizeof(NaClCPUFeaturesX86), | |
| 237 NaClSetAllCPUFeaturesX86, | |
| 238 NaClGetCurrentCPUFeaturesX86, | |
| 239 NaClFixCPUFeaturesX86, | |
| 240 }; | |
| 241 | |
| 242 const struct NaClValidatorInterface *NaClValidatorCreate_x86_64(void) { | |
| 243 return &validator; | |
| 244 } | |
| OLD | NEW |