Upstream version 11.39.266.0
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / validator / x86 / 64 / ncvalidate.c
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_tables.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 }