Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/trusted/validator_ragel/dfa_validate_common.c

Issue 1309953002: x86 validator: Rewrite non-temporal stores into cached memory accesses (Closed) Base URL: https://chromium.googlesource.com/native_client/src/native_client.git@master
Patch Set: Review nit Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/trusted/validator/validation_rewrite_test_data.S ('k') | tests/validator/nacl.scons » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 functions common for ia32 and x86-64 architectures. */ 7 /* Implement the functions common for ia32 and x86-64 architectures. */
8 #include "native_client/src/trusted/validator_ragel/dfa_validate_common.h" 8 #include "native_client/src/trusted/validator_ragel/dfa_validate_common.h"
9 9
10 #include <string.h> 10 #include <string.h>
11 11
12 #include "native_client/src/include/build_config.h"
12 #include "native_client/src/shared/platform/nacl_check.h" 13 #include "native_client/src/shared/platform/nacl_check.h"
13 #include "native_client/src/trusted/service_runtime/nacl_config.h" 14 #include "native_client/src/trusted/service_runtime/nacl_config.h"
14 #include "native_client/src/trusted/validator_ragel/validator.h" 15 #include "native_client/src/trusted/validator_ragel/validator.h"
15 16
16 /* Used as an argument to copy_func when unsupported instruction must be 17 /* Used as an argument to copy_func when unsupported instruction must be
17 replaced with HLTs. */ 18 replaced with HLTs. */
18 static const uint8_t kStubOutMem[MAX_INSTRUCTION_LENGTH] = { 19 static const uint8_t kStubOutMem[MAX_INSTRUCTION_LENGTH] = {
19 NACL_HALT_OPCODE, NACL_HALT_OPCODE, NACL_HALT_OPCODE, NACL_HALT_OPCODE, 20 NACL_HALT_OPCODE, NACL_HALT_OPCODE, NACL_HALT_OPCODE, NACL_HALT_OPCODE,
20 NACL_HALT_OPCODE, NACL_HALT_OPCODE, NACL_HALT_OPCODE, NACL_HALT_OPCODE, 21 NACL_HALT_OPCODE, NACL_HALT_OPCODE, NACL_HALT_OPCODE, NACL_HALT_OPCODE,
21 NACL_HALT_OPCODE, NACL_HALT_OPCODE, NACL_HALT_OPCODE, NACL_HALT_OPCODE, 22 NACL_HALT_OPCODE, NACL_HALT_OPCODE, NACL_HALT_OPCODE, NACL_HALT_OPCODE,
22 NACL_HALT_OPCODE, NACL_HALT_OPCODE, NACL_HALT_OPCODE, NACL_HALT_OPCODE, 23 NACL_HALT_OPCODE, NACL_HALT_OPCODE, NACL_HALT_OPCODE, NACL_HALT_OPCODE,
23 NACL_HALT_OPCODE 24 NACL_HALT_OPCODE
24 }; 25 };
25 26
26 Bool NaClDfaProcessValidationError(const uint8_t *begin, const uint8_t *end, 27 Bool NaClDfaProcessValidationError(const uint8_t *begin, const uint8_t *end,
27 uint32_t info, void *callback_data) { 28 uint32_t info, void *callback_data) {
28 UNREFERENCED_PARAMETER(begin); 29 UNREFERENCED_PARAMETER(begin);
29 UNREFERENCED_PARAMETER(end); 30 UNREFERENCED_PARAMETER(end);
30 UNREFERENCED_PARAMETER(info); 31 UNREFERENCED_PARAMETER(info);
31 UNREFERENCED_PARAMETER(callback_data); 32 UNREFERENCED_PARAMETER(callback_data);
32 33
33 return FALSE; 34 return FALSE;
34 } 35 }
35 36
36 /* 37 /*
37 * Returns whether a validation error should be ignored by 38 * Returns whether a validation error should be ignored by
38 * RewriteAndRevalidateBundle()'s two validation passes, which 39 * RewriteAndRevalidateBundle()'s two validation passes, which
39 * validate individual instruction bundles. 40 * validate individual instruction bundles.
40 */ 41 */
41 static Bool AllowErrorDuringBundleValidation( 42 static Bool AllowErrorDuringBundleValidation(uint32_t info) {
42 uint32_t info, struct StubOutCallbackData *data) {
43 if ((info & VALIDATION_ERRORS_MASK) == DIRECT_JUMP_OUT_OF_RANGE) { 43 if ((info & VALIDATION_ERRORS_MASK) == DIRECT_JUMP_OUT_OF_RANGE) {
44 /* 44 /*
45 * This error can occur on valid jumps because we are validating 45 * This error can occur on valid jumps because we are validating
46 * an instruction bundle that is a subset of a code chunk. 46 * an instruction bundle that is a subset of a code chunk.
47 */ 47 */
48 return TRUE; 48 return TRUE;
49 } 49 }
50 if ((info & VALIDATION_ERRORS_MASK) == UNSUPPORTED_INSTRUCTION) {
51 return (data->flags & NACL_DISABLE_NONTEMPORALS_X86) == 0;
52 }
53 return FALSE; 50 return FALSE;
54 } 51 }
55 52
53 #if NACL_BUILD_SUBARCH == 64
54 static Bool IsREXPrefix(uint8_t byte) {
55 return byte >= 0x40 && byte <= 0x4f;
56 }
57 #endif
58
59 static Bool RewriteNonTemporal(uint8_t *ptr, uint8_t *end, uint32_t info) {
60 /*
61 * Instruction rewriting. Note that we only rewrite non-temporal
62 * instructions found in nexes and DSOs that are currently found in the
63 * Chrome Web Store. If future nexes use other non-temporal
64 * instructions, they will fail validation.
65 *
66 * We usually only check and rewrite the first few bytes without
67 * examining further because this function is only called when the
68 * validator tells us that it is an 'unsupported instruction' and there
69 * are no other validation failures.
70 */
71 ptrdiff_t size = end - ptr;
72 #if NACL_BUILD_SUBARCH == 32
73 UNREFERENCED_PARAMETER(end);
74 UNREFERENCED_PARAMETER(info);
75
76 if (size >= 2 && memcmp(ptr, "\x0f\xe7", 2) == 0) {
77 /* movntq => movq */
78 ptr[1] = 0x7f;
79 return TRUE;
80 } else if (size >= 3 && memcmp(ptr, "\x66\x0f\xe7", 3) == 0) {
81 /* movntdq => movdqa */
82 ptr[2] = 0x7f;
83 return TRUE;
84 }
85 #elif NACL_BUILD_SUBARCH == 64
86 if (size >= 3 && IsREXPrefix(ptr[0]) && ptr[1] == 0x0f) {
87 uint8_t opcode_byte2 = ptr[2];
88 switch (opcode_byte2) {
89 case 0x2b:
90 /* movntps => movaps */
91 ptr[2] = 0x29;
92 return TRUE;
93 case 0xc3:
94 /* movnti => mov, nop */
95 if ((info & RESTRICTED_REGISTER_USED) != 0) {
96 /*
97 * The rewriting for movnti is special because it changes
98 * instruction boundary: movnti is replaced by a mov and a nop so
99 * that the total size does not change. Therefore, special care
100 * needs to be taken: if restricted register is used in this
101 * instruction, we have to put nop at the end so that the
102 * rewritten restricted register consuming instruction follows
103 * closely with the restricted register producing instruction (if
104 * there is one).
105 */
106 ptr[1] = 0x89;
107 memmove(ptr + 2, ptr + 3, size - 3);
108 ptr[size - 1] = 0x90; /* NOP */
109 } else {
110 /*
111 * There are cases where we need to preserve instruction end
112 * position, for example, when RIP-relative address is used.
113 * Fortunately, RIP-relative addressing cannot use an index
114 * register, and therefore RESTRICTED_REGISTER_USED cannot be
115 * set. Therefore, no matter whether RIP-relative addressing is
116 * used, as long as restricted register is not used, we are safe
117 * to put nop in the beginning and preserve instruction end
118 * position.
119 */
120 ptr[2] = 0x89;
121 ptr[1] = ptr[0];
122 ptr[0] = 0x90; /* NOP */
123 }
124 return TRUE;
125 case 0x18:
126 /* prefetchnta => nop...nop */
127 memset(ptr, 0x90, size);
128 return TRUE;
129 default:
130 return FALSE;
131 }
132 } else if (size >= 4 &&
133 ptr[0] == 0x66 &&
134 IsREXPrefix(ptr[1]) &&
135 memcmp(ptr + 2, "\x0f\xe7", 2) == 0) {
136 /* movntdq => movdqa */
137 ptr[3] = 0x7f;
138 return TRUE;
139 }
140 #else
141 # error "Unknown architecture"
142 #endif
143 return FALSE;
144 }
145
56 /* 146 /*
57 * First pass of RewriteAndRevalidateBundle(): Rewrite any 147 * First pass of RewriteAndRevalidateBundle(): Rewrite any
58 * instructions that need rewriting. 148 * instructions that need rewriting.
59 */ 149 */
60 static Bool BundleValidationApplyRewrite(const uint8_t *begin, 150 static Bool BundleValidationApplyRewrite(const uint8_t *begin,
61 const uint8_t *end, 151 const uint8_t *end,
62 uint32_t info, 152 uint32_t info,
63 void *callback_data) { 153 void *callback_data) {
64 struct StubOutCallbackData *data = callback_data; 154 struct StubOutCallbackData *data = callback_data;
65 155
66 if ((info & VALIDATION_ERRORS_MASK) == CPUID_UNSUPPORTED_INSTRUCTION) { 156 if ((info & VALIDATION_ERRORS_MASK) == CPUID_UNSUPPORTED_INSTRUCTION) {
67 /* Stub-out instructions unsupported on this CPU, but valid on other CPUs.*/ 157 /* Stub-out instructions unsupported on this CPU, but valid on other CPUs.*/
68 data->did_rewrite = 1; 158 data->did_rewrite = 1;
69 memset((uint8_t *) begin, NACL_HALT_OPCODE, end - begin); 159 memset((uint8_t *) begin, NACL_HALT_OPCODE, end - begin);
70 return TRUE; 160 return TRUE;
71 } 161 }
72 return AllowErrorDuringBundleValidation(info, data); 162 if ((info & VALIDATION_ERRORS_MASK) == UNSUPPORTED_INSTRUCTION &&
163 (data->flags & NACL_DISABLE_NONTEMPORALS_X86) == 0) {
164 if (RewriteNonTemporal((uint8_t *) begin, (uint8_t *) end, info)) {
165 data->did_rewrite = 1;
166 return TRUE;
167 }
168 return FALSE;
169 }
170 return AllowErrorDuringBundleValidation(info);
73 } 171 }
74 172
75 /* 173 /*
76 * Second pass of RewriteAndRevalidateBundle(): Revalidate, checking 174 * Second pass of RewriteAndRevalidateBundle(): Revalidate, checking
77 * that no further instruction rewrites are needed. 175 * that no further instruction rewrites are needed.
78 */ 176 */
79 static Bool BundleValidationCheckAfterRewrite(const uint8_t *begin, 177 static Bool BundleValidationCheckAfterRewrite(const uint8_t *begin,
80 const uint8_t *end, 178 const uint8_t *end,
81 uint32_t info, 179 uint32_t info,
82 void *callback_data) { 180 void *callback_data) {
83 struct StubOutCallbackData *data = callback_data;
84 UNREFERENCED_PARAMETER(begin); 181 UNREFERENCED_PARAMETER(begin);
85 UNREFERENCED_PARAMETER(end); 182 UNREFERENCED_PARAMETER(end);
183 UNREFERENCED_PARAMETER(callback_data);
86 184
87 return AllowErrorDuringBundleValidation(info, data); 185 return AllowErrorDuringBundleValidation(info);
88 } 186 }
89 187
90 /* 188 /*
91 * As an extra safety check, when the validator modifies an 189 * As an extra safety check, when the validator modifies an
92 * instruction, we want to revalidate the rewritten code. 190 * instruction, we want to revalidate the rewritten code.
93 * 191 *
94 * For performance, we don't want to revalidate the whole code chunk, 192 * For performance, we don't want to revalidate the whole code chunk,
95 * because that would double the overall validation time. However, 193 * because that would double the overall validation time. However,
96 * it's not practical to revalidate the individual rewritten 194 * it's not practical to revalidate the individual rewritten
97 * instruction, because for x86-64 we need to account for previous 195 * instruction, because for x86-64 we need to account for previous
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 } 234 }
137 235
138 Bool NaClDfaStubOutUnsupportedInstruction(const uint8_t *begin, 236 Bool NaClDfaStubOutUnsupportedInstruction(const uint8_t *begin,
139 const uint8_t *end, 237 const uint8_t *end,
140 uint32_t info, 238 uint32_t info,
141 void *callback_data) { 239 void *callback_data) {
142 struct StubOutCallbackData *data = callback_data; 240 struct StubOutCallbackData *data = callback_data;
143 /* Stub-out instructions unsupported on this CPU, but valid on other CPUs. */ 241 /* Stub-out instructions unsupported on this CPU, but valid on other CPUs. */
144 if ((info & VALIDATION_ERRORS_MASK) == CPUID_UNSUPPORTED_INSTRUCTION) { 242 if ((info & VALIDATION_ERRORS_MASK) == CPUID_UNSUPPORTED_INSTRUCTION) {
145 return RewriteAndRevalidateBundle(begin, end, data); 243 return RewriteAndRevalidateBundle(begin, end, data);
146 } else if ((info & VALIDATION_ERRORS_MASK) == UNSUPPORTED_INSTRUCTION) {
147 if (data->flags & NACL_DISABLE_NONTEMPORALS_X86) {
148 return FALSE;
149 } else {
150 /* TODO(ruiq): rewrite instruction. For now, we keep the original
151 * instruction and indicate validation success, which is consistent
152 * with current validation results. */
153 return TRUE;
154 }
155 } else {
156 return FALSE;
157 } 244 }
245 if ((info & VALIDATION_ERRORS_MASK) == UNSUPPORTED_INSTRUCTION &&
246 (data->flags & NACL_DISABLE_NONTEMPORALS_X86) == 0) {
247 return RewriteAndRevalidateBundle(begin, end, data);
248 }
249 return FALSE;
158 } 250 }
159 251
160 Bool NaClDfaProcessCodeCopyInstruction(const uint8_t *begin_new, 252 Bool NaClDfaProcessCodeCopyInstruction(const uint8_t *begin_new,
161 const uint8_t *end_new, 253 const uint8_t *end_new,
162 uint32_t info_new, 254 uint32_t info_new,
163 void *callback_data) { 255 void *callback_data) {
164 struct CodeCopyCallbackData *data = callback_data; 256 struct CodeCopyCallbackData *data = callback_data;
165 size_t instruction_length = end_new - begin_new; 257 size_t instruction_length = end_new - begin_new;
166 258
167 /* Sanity check: instruction must be no longer than 17 bytes. */ 259 /* Sanity check: instruction must be no longer than 17 bytes. */
168 CHECK(instruction_length <= MAX_INSTRUCTION_LENGTH); 260 CHECK(instruction_length <= MAX_INSTRUCTION_LENGTH);
169 261
170 return data->copy_func( 262 return data->copy_func(
171 (uint8_t *)begin_new + data->existing_minus_new, /* begin_existing */ 263 (uint8_t *)begin_new + data->existing_minus_new, /* begin_existing */
172 (info_new & VALIDATION_ERRORS_MASK) == CPUID_UNSUPPORTED_INSTRUCTION ? 264 (info_new & VALIDATION_ERRORS_MASK) == CPUID_UNSUPPORTED_INSTRUCTION ?
173 (uint8_t *)kStubOutMem : 265 (uint8_t *)kStubOutMem :
174 (uint8_t *)begin_new, 266 (uint8_t *)begin_new,
175 (uint8_t)instruction_length); 267 (uint8_t)instruction_length);
176 } 268 }
177 269
178 Bool NaClDfaCodeReplacementIsStubouted(const uint8_t *begin_existing, 270 Bool NaClDfaCodeReplacementIsStubouted(const uint8_t *begin_existing,
179 size_t instruction_length) { 271 size_t instruction_length) {
180 272
181 /* Unsupported instruction must have been replaced with HLTs. */ 273 /* Unsupported instruction must have been replaced with HLTs. */
182 if (memcmp(kStubOutMem, begin_existing, instruction_length) == 0) 274 if (memcmp(kStubOutMem, begin_existing, instruction_length) == 0)
183 return TRUE; 275 return TRUE;
184 else 276 else
185 return FALSE; 277 return FALSE;
186 } 278 }
OLDNEW
« no previous file with comments | « src/trusted/validator/validation_rewrite_test_data.S ('k') | tests/validator/nacl.scons » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698