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.
7 /* Implement the ApplyValidator API for the x86-64 architecture. */
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_tables.h"
17 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter.h"
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")
23 # if NACL_TARGET_SUBARCH != 64
24 # error("Can't compile, target is for x86-64")
28 NaClValidationStatus NaClValidatorSetup_x86_64(
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! */
41 static NaClValidationStatus ApplyValidator_x86_64(
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;
56 /* Check that the given parameter values are supported. */
57 if (stubout_mode && readonly_text)
58 return NaClValidationFailedNotImplemented;
60 if (!NaClArchSupportedX86(cpu_features))
61 return NaClValidationFailedCpuNotSupported;
63 /* Don't cache in stubout mode. */
67 /* If the validation caching interface is available, perform a query. */
69 query = cache->CreateQuery(cache->handle);
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;
81 /* Init then validator state. */
82 status = NaClValidatorSetup_x86_64(
83 guest_addr, size, readonly_text, cpu_features, &vstate);
84 if (status != NaClValidationSucceeded) {
86 cache->DestroyQuery(query);
89 NaClValidatorStateSetLogVerbosity(vstate, LOG_ERROR);
90 NaClValidatorStateSetDoStubOut(vstate, stubout_mode);
93 NaClValidateSegment(data, guest_addr, size, vstate);
94 status = (NaClValidatesOk(vstate) || stubout_mode) ?
95 NaClValidationSucceeded : NaClValidationFailed;
97 /* Cache the result if validation succeded and the code was not modified. */
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);
105 NaClValidatorStateDestroy(vstate);
109 static NaClValidationStatus ApplyValidatorCodeReplacement_x86_64(
110 uintptr_t guest_addr,
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;
120 /* Check that the given parameter values are supported. */
121 if (!NaClArchSupportedX86(cpu_features))
122 return NaClValidationFailedCpuNotSupported;
124 /* Init then validator state. */
125 status = NaClValidatorSetup_x86_64(guest_addr, size, FALSE,
126 cpu_features, &vstate);
127 if (status != NaClValidationSucceeded)
129 NaClValidatorStateSetLogVerbosity(vstate, LOG_ERROR);
132 NaClValidateSegmentPair(data_old, data_new, guest_addr, size, vstate);
133 status = NaClValidatesOk(vstate) ?
134 NaClValidationSucceeded : NaClValidationFailed;
136 NaClValidatorStateDestroy(vstate);
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.
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;
155 NaClSegmentInitialize(dst, vbase, size, &segment_old);
156 NaClSegmentInitialize(src, vbase, size, &segment_new);
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);
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.
171 if (!(NaClInstIterHasNext(iter_old) && NaClInstIterHasNext(iter_new))) {
172 if (NaClInstIterHasNext(iter_old) || NaClInstIterHasNext(iter_new)) {
174 "Segment replacement: copy failed: iterators "
175 "length mismatch\n");
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.
189 "Segment replacement: copied instructions misaligned\n");
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.
197 if (!copy_func(iter_old->memory.mpc, iter_new->memory.mpc,
198 iter_old->memory.read_length)) {
200 "Segment replacement: copy failed: unable to copy instruction\n");
204 NaClInstIterAdvance(iter_old);
205 NaClInstIterAdvance(iter_new);
208 NaClInstIterDestroy(iter_old);
209 NaClInstIterDestroy(iter_new);
213 static NaClValidationStatus ApplyValidatorCopy_x86_64(
214 uintptr_t guest_addr,
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;
225 return (0 == CopyCodeIter(data_old, data_new, guest_addr, size, copy_func))
226 ? NaClValidationFailed : NaClValidationSucceeded;
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,
242 const struct NaClValidatorInterface *NaClValidatorCreate_x86_64(void) {