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-32 architecture. */ | |
8 | |
9 #include "native_client/src/trusted/validator/ncvalidate.h" | |
10 #include "native_client/src/trusted/validator/validation_cache.h" | |
11 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate.h" | |
12 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate_detai
led.h" | |
13 /* HACK to get access to didstubout */ | |
14 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate_inter
naltypes.h" | |
15 #include <assert.h> | |
16 | |
17 /* Be sure the correct compile flags are defined for this. */ | |
18 #if NACL_ARCH(NACL_TARGET_ARCH) != NACL_x86 | |
19 # error("Can't compile, target is for x86-32") | |
20 #else | |
21 # if NACL_TARGET_SUBARCH != 32 | |
22 # error("Can't compile, target is for x86-32") | |
23 # endif | |
24 #endif | |
25 | |
26 static NaClValidationStatus ApplyValidator_x86_32( | |
27 uintptr_t guest_addr, | |
28 uint8_t *data, | |
29 size_t size, | |
30 int stubout_mode, | |
31 int readonly_text, | |
32 const NaClCPUFeatures *f, | |
33 const struct NaClValidationMetadata *metadata, | |
34 struct NaClValidationCache *cache) { | |
35 /* TODO(jfb) Use a safe cast here. */ | |
36 const NaClCPUFeaturesX86 *cpu_features = (NaClCPUFeaturesX86 *) f; | |
37 struct NCValidatorState *vstate; | |
38 int validator_result = 0; | |
39 void *query = NULL; | |
40 | |
41 /* Check that the given parameter values are supported. */ | |
42 if (stubout_mode && readonly_text) | |
43 return NaClValidationFailedNotImplemented; | |
44 | |
45 if (!NaClArchSupportedX86(cpu_features)) | |
46 return NaClValidationFailedCpuNotSupported; | |
47 | |
48 /* Don't cache in stubout mode. */ | |
49 if (stubout_mode) | |
50 cache = NULL; | |
51 | |
52 /* If the validation caching interface is available, perform a query. */ | |
53 if (cache != NULL) | |
54 query = cache->CreateQuery(cache->handle); | |
55 if (query != NULL) { | |
56 const char validator_id[] = "x86-32"; | |
57 cache->AddData(query, (uint8_t *) validator_id, sizeof(validator_id)); | |
58 cache->AddData(query, (uint8_t *) cpu_features, sizeof(*cpu_features)); | |
59 NaClAddCodeIdentity(data, size, metadata, cache, query); | |
60 if (cache->QueryKnownToValidate(query)) { | |
61 cache->DestroyQuery(query); | |
62 return NaClValidationSucceeded; | |
63 } | |
64 } | |
65 | |
66 /* Init then validator state. */ | |
67 /* TODO(ncbray) make "detailed" a parameter. */ | |
68 if (stubout_mode) { | |
69 vstate = NCValidateInitDetailed(guest_addr, size, cpu_features); | |
70 } else { | |
71 vstate = NCValidateInit(guest_addr, size, readonly_text, cpu_features); | |
72 } | |
73 if (vstate == NULL) { | |
74 if (query != NULL) | |
75 cache->DestroyQuery(query); | |
76 return NaClValidationFailedOutOfMemory; | |
77 } | |
78 NCValidateSetStubOutMode(vstate, stubout_mode); | |
79 | |
80 /* Validate. */ | |
81 NCValidateSegment(data, guest_addr, size, vstate); | |
82 validator_result = NCValidateFinish(vstate); | |
83 | |
84 /* Cache the result if validation succeeded and the code was not modified. */ | |
85 if (query != NULL) { | |
86 if (validator_result == 0 && !NCValidatorDidStubOut(vstate)) | |
87 cache->SetKnownToValidate(query); | |
88 cache->DestroyQuery(query); | |
89 } | |
90 | |
91 NCValidateFreeState(&vstate); | |
92 return (validator_result == 0 || stubout_mode) | |
93 ? NaClValidationSucceeded : NaClValidationFailed; | |
94 } | |
95 | |
96 static NaClValidationStatus ApplyValidatorCodeReplacement_x86_32( | |
97 uintptr_t guest_addr, | |
98 uint8_t *data_old, | |
99 uint8_t *data_new, | |
100 size_t size, | |
101 const NaClCPUFeatures *f) { | |
102 /* TODO(jfb) Use a safe cast here. */ | |
103 const NaClCPUFeaturesX86 *cpu_features = (NaClCPUFeaturesX86 *) f; | |
104 | |
105 /* Check that the given parameter values are supported. */ | |
106 if (!NaClArchSupportedX86(cpu_features)) | |
107 return NaClValidationFailedCpuNotSupported; | |
108 | |
109 return NCValidateSegmentPair(data_old, data_new, guest_addr, | |
110 size, cpu_features) | |
111 ? NaClValidationSucceeded : NaClValidationFailed; | |
112 } | |
113 | |
114 /* Copy a single instruction, avoiding the possibility of other threads | |
115 * executing a partially changed instruction. | |
116 */ | |
117 static Bool CopyInstruction(NCDecoderStatePair *self, | |
118 NCDecoderInst *dinst_old, | |
119 NCDecoderInst *dinst_new) { | |
120 NCRemainingMemory* mem_old = &dinst_old->dstate->memory; | |
121 NCRemainingMemory* mem_new = &dinst_new->dstate->memory; | |
122 | |
123 return self->copy_func(mem_old->mpc, mem_new->mpc, mem_old->read_length); | |
124 } | |
125 | |
126 /* Copies code from src to dest in a thread safe way, returns 1 on success, | |
127 * returns 0 on error. This will likely assert on error to avoid partially | |
128 * copied code or undefined state. | |
129 */ | |
130 static int NCCopyCode(uint8_t *dst, uint8_t *src, NaClPcAddress vbase, | |
131 size_t sz, NaClCopyInstructionFunc copy_func) { | |
132 NCDecoderState dst_dstate; | |
133 NCDecoderInst dst_inst; | |
134 NCDecoderState src_dstate; | |
135 NCDecoderInst src_inst; | |
136 NCDecoderStatePair pair; | |
137 int result = 0; | |
138 | |
139 NCDecoderStateConstruct(&dst_dstate, dst, vbase, sz, &dst_inst, 1); | |
140 NCDecoderStateConstruct(&src_dstate, src, vbase, sz, &src_inst, 1); | |
141 NCDecoderStatePairConstruct(&pair, &dst_dstate, &src_dstate, copy_func); | |
142 pair.action_fn = CopyInstruction; | |
143 if (NCDecoderStatePairDecode(&pair)) result = 1; | |
144 NCDecoderStatePairDestruct(&pair); | |
145 NCDecoderStateDestruct(&src_dstate); | |
146 NCDecoderStateDestruct(&dst_dstate); | |
147 | |
148 return result; | |
149 } | |
150 | |
151 static NaClValidationStatus ApplyValidatorCopy_x86_32( | |
152 uintptr_t guest_addr, | |
153 uint8_t *data_old, | |
154 uint8_t *data_new, | |
155 size_t size, | |
156 const NaClCPUFeatures *f, | |
157 NaClCopyInstructionFunc copy_func) { | |
158 /* TODO(jfb) Use a safe cast here. */ | |
159 const NaClCPUFeaturesX86 *cpu_features = (NaClCPUFeaturesX86 *) f; | |
160 | |
161 if (!NaClArchSupportedX86(cpu_features)) | |
162 return NaClValidationFailedCpuNotSupported; | |
163 | |
164 return ((0 == NCCopyCode(data_old, data_new, guest_addr, size, copy_func)) | |
165 ? NaClValidationFailed : NaClValidationSucceeded); | |
166 } | |
167 | |
168 static const struct NaClValidatorInterface validator = { | |
169 TRUE, /* Optional stubout_mode is implemented. */ | |
170 TRUE, /* Optional readonly_text is implemented. */ | |
171 TRUE, /* Optional code replacement functions are implemented. */ | |
172 ApplyValidator_x86_32, | |
173 ApplyValidatorCopy_x86_32, | |
174 ApplyValidatorCodeReplacement_x86_32, | |
175 sizeof(NaClCPUFeaturesX86), | |
176 NaClSetAllCPUFeaturesX86, | |
177 NaClGetCurrentCPUFeaturesX86, | |
178 NaClFixCPUFeaturesX86, | |
179 }; | |
180 | |
181 const struct NaClValidatorInterface *NaClValidatorCreate_x86_32(void) { | |
182 return &validator; | |
183 } | |
OLD | NEW |