OLD | NEW |
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 Validator API for the x86-64 architecture. */ | 7 /* Implement the Validator API for the x86-64 architecture. */ |
8 #include <assert.h> | 8 #include <assert.h> |
9 #include <errno.h> | 9 #include <errno.h> |
10 #include <stddef.h> | 10 #include <stddef.h> |
(...skipping 16 matching lines...) Expand all Loading... |
27 | 27 |
28 #define NACL_HALT_OPCODE 0xf4 | 28 #define NACL_HALT_OPCODE 0xf4 |
29 | 29 |
30 static Bool ProcessError(const uint8_t *begin, const uint8_t *end, | 30 static Bool ProcessError(const uint8_t *begin, const uint8_t *end, |
31 uint32_t info, void *callback_data) { | 31 uint32_t info, void *callback_data) { |
32 UNREFERENCED_PARAMETER(begin); | 32 UNREFERENCED_PARAMETER(begin); |
33 UNREFERENCED_PARAMETER(end); | 33 UNREFERENCED_PARAMETER(end); |
34 UNREFERENCED_PARAMETER(info); | 34 UNREFERENCED_PARAMETER(info); |
35 | 35 |
36 /* Instruction is unsupported by CPU, but otherwise valid. */ | 36 /* Instruction is unsupported by CPU, but otherwise valid. */ |
37 if ((info & VALIDATION_ERRORS) == CPUID_UNSUPPORTED_INSTRUCTION) { | 37 if ((info & VALIDATION_ERRORS_MASK) == CPUID_UNSUPPORTED_INSTRUCTION) { |
38 *((enum NaClValidationStatus*)callback_data) = | 38 *((enum NaClValidationStatus*)callback_data) = |
39 NaClValidationFailedCpuNotSupported; | 39 NaClValidationFailedCpuNotSupported; |
40 } | 40 } |
41 return FALSE; | 41 return FALSE; |
42 } | 42 } |
43 | 43 |
44 static Bool StubOutCPUUnsupportedInstruction(const uint8_t *begin, | 44 static Bool StubOutCPUUnsupportedInstruction(const uint8_t *begin, |
45 const uint8_t *end, uint32_t info, void *callback_data) { | 45 const uint8_t *end, uint32_t info, void *callback_data) { |
46 UNREFERENCED_PARAMETER(callback_data); | 46 UNREFERENCED_PARAMETER(callback_data); |
47 | 47 |
48 /* Stubout unsupported by CPU, but otherwise valid instructions. */ | 48 /* Stubout unsupported by CPU, but otherwise valid instructions. */ |
49 if ((info & VALIDATION_ERRORS) == CPUID_UNSUPPORTED_INSTRUCTION) { | 49 if ((info & VALIDATION_ERRORS_MASK) == CPUID_UNSUPPORTED_INSTRUCTION) { |
50 memset((uint8_t *)begin, NACL_HALT_OPCODE, end - begin + 1); | 50 memset((uint8_t *)begin, NACL_HALT_OPCODE, end - begin + 1); |
51 return TRUE; | 51 return TRUE; |
52 } else { | 52 } else { |
53 return FALSE; | 53 return FALSE; |
54 } | 54 } |
55 } | 55 } |
56 | 56 |
57 static NaClValidationStatus ApplyDfaValidator_x86_64( | 57 static NaClValidationStatus ApplyDfaValidator_x86_64( |
58 uintptr_t guest_addr, | 58 uintptr_t guest_addr, |
59 uint8_t *data, | 59 uint8_t *data, |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 | 104 |
105 static Bool ProcessCodeCopyInstruction(const uint8_t *begin_new, | 105 static Bool ProcessCodeCopyInstruction(const uint8_t *begin_new, |
106 const uint8_t *end_new, uint32_t info, void *callback_data) { | 106 const uint8_t *end_new, uint32_t info, void *callback_data) { |
107 struct CodeCopyCallbackData *data = callback_data; | 107 struct CodeCopyCallbackData *data = callback_data; |
108 | 108 |
109 /* Sanity check: instruction must be shorter then 15 bytes. */ | 109 /* Sanity check: instruction must be shorter then 15 bytes. */ |
110 CHECK(end_new - begin_new < MAX_INSTRUCTION_LENGTH); | 110 CHECK(end_new - begin_new < MAX_INSTRUCTION_LENGTH); |
111 | 111 |
112 return data->copy_func( | 112 return data->copy_func( |
113 (uint8_t *)begin_new + data->delta, | 113 (uint8_t *)begin_new + data->delta, |
114 (info & VALIDATION_ERRORS) == CPUID_UNSUPPORTED_INSTRUCTION ? | 114 (info & VALIDATION_ERRORS_MASK) == CPUID_UNSUPPORTED_INSTRUCTION ? |
115 (uint8_t *)kStubOutMem : | 115 (uint8_t *)kStubOutMem : |
116 (uint8_t *)begin_new, | 116 (uint8_t *)begin_new, |
117 (uint8_t)(end_new - begin_new + 1)); | 117 (uint8_t)(end_new - begin_new + 1)); |
118 } | 118 } |
119 | 119 |
120 static NaClValidationStatus ValidatorCodeCopy_x86_64( | 120 static NaClValidationStatus ValidatorCodeCopy_x86_64( |
121 uintptr_t guest_addr, | 121 uintptr_t guest_addr, |
122 uint8_t *data_old, | 122 uint8_t *data_old, |
123 uint8_t *data_new, | 123 uint8_t *data_new, |
124 size_t size, | 124 size_t size, |
(...skipping 25 matching lines...) Expand all Loading... |
150 const uint8_t *end_new, uint32_t info, void *callback_data) { | 150 const uint8_t *end_new, uint32_t info, void *callback_data) { |
151 ptrdiff_t delta = (ptrdiff_t)callback_data; | 151 ptrdiff_t delta = (ptrdiff_t)callback_data; |
152 size_t instruction_length = end_new - begin_new + 1; | 152 size_t instruction_length = end_new - begin_new + 1; |
153 const uint8_t *begin_old = begin_new + delta; | 153 const uint8_t *begin_old = begin_new + delta; |
154 const uint8_t *end_old = end_new + delta; | 154 const uint8_t *end_old = end_new + delta; |
155 | 155 |
156 /* Sanity check: instruction must be shorter then 15 bytes. */ | 156 /* Sanity check: instruction must be shorter then 15 bytes. */ |
157 CHECK(instruction_length <= MAX_INSTRUCTION_LENGTH); | 157 CHECK(instruction_length <= MAX_INSTRUCTION_LENGTH); |
158 | 158 |
159 /* Unsupported instruction must have been replaced with HLTs. */ | 159 /* Unsupported instruction must have been replaced with HLTs. */ |
160 if ((info & VALIDATION_ERRORS) == CPUID_UNSUPPORTED_INSTRUCTION) { | 160 if ((info & VALIDATION_ERRORS_MASK) == CPUID_UNSUPPORTED_INSTRUCTION) { |
161 if (memcmp(kStubOutMem, begin_old, instruction_length) == 0) { | 161 if (memcmp(kStubOutMem, begin_old, instruction_length) == 0) { |
162 return TRUE; | 162 return TRUE; |
163 } else { | 163 } else { |
164 return FALSE; | 164 return FALSE; |
165 } | 165 } |
166 /* If we have jump which jumps out of it's range... */ | 166 /* If we have jump which jumps out of it's range... */ |
167 } else if (info & DIRECT_JUMP_OUT_OF_RANGE) { | 167 } else if (info & DIRECT_JUMP_OUT_OF_RANGE) { |
168 /* then everything is fine if it's the only error and jump is unchanged! */ | 168 /* then everything is fine if it's the only error and jump is unchanged! */ |
169 if ((info & (VALIDATION_ERRORS & ~DIRECT_JUMP_OUT_OF_RANGE)) || | 169 if ((info & (VALIDATION_ERRORS_MASK & ~DIRECT_JUMP_OUT_OF_RANGE)) || |
170 memcmp(begin_new, begin_old, instruction_length) != 0) | 170 memcmp(begin_new, begin_old, instruction_length) != 0) |
171 return FALSE; | 171 return FALSE; |
172 /* If instruction is not accepted then we have nothing to do here. */ | 172 /* If instruction is not accepted then we have nothing to do here. */ |
173 } else if (info & (VALIDATION_ERRORS | BAD_JUMP_TARGET)) { | 173 } else if (info & (VALIDATION_ERRORS_MASK | BAD_JUMP_TARGET)) { |
174 return FALSE; | 174 return FALSE; |
175 /* Instruction is untouched: we are done. */ | 175 /* Instruction is untouched: we are done. */ |
176 } else if (memcmp(begin_new, begin_old, instruction_length) == 0) { | 176 } else if (memcmp(begin_new, begin_old, instruction_length) == 0) { |
177 return TRUE; | 177 return TRUE; |
178 /* Only some instructions can be modified. */ | 178 /* Only some instructions can be modified. */ |
179 } else if (!(info & MODIFIABLE_INSTRUCTION)) { | 179 } else if (!(info & MODIFIABLE_INSTRUCTION)) { |
180 return FALSE; | 180 return FALSE; |
181 /* Instruction with two-bit immediate can only change these two bits. */ | 181 /* Instruction with two-bit immediate can only change these two bits. */ |
182 } else if ((info & IMMEDIATE_2BIT) == IMMEDIATE_2BIT) { | 182 } else if ((info & IMMEDIATE_2BIT) == IMMEDIATE_2BIT) { |
183 if (memcmp(begin_new, begin_old, instruction_length - 1) != 0 || | 183 if (memcmp(begin_new, begin_old, |
| 184 instruction_length - (info & IMMEDIATES_SIZE_MASK) - 1) != 0 || |
184 (*end_new & 0xfc) != (*end_old & 0xfc)) { | 185 (*end_new & 0xfc) != (*end_old & 0xfc)) { |
185 return FALSE; | 186 return FALSE; |
186 } | 187 } |
| 188 /* Instruction's last byte is not immediate, thus it must be unchanged. */ |
187 } else if (info & LAST_BYTE_IS_NOT_IMMEDIATE) { | 189 } else if (info & LAST_BYTE_IS_NOT_IMMEDIATE) { |
188 if (memcmp(begin_new, begin_old, instruction_length - 1) != 0) { | 190 if (memcmp(begin_new, begin_old, |
| 191 instruction_length - (info & IMMEDIATES_SIZE_MASK) - 1) != 0 || |
| 192 (*end_new) != (*end_old)) { |
189 return FALSE; | 193 return FALSE; |
190 } | 194 } |
191 /* Normal instruction can only change an immediate. */ | 195 /* Normal instruction can only change an immediate. */ |
192 } else if (memcmp(begin_new, begin_old, | 196 } else if (memcmp(begin_new, begin_old, |
193 instruction_length - (info & IMMEDIATES_SIZE)) != 0) { | 197 instruction_length - (info & IMMEDIATES_SIZE_MASK)) != 0) { |
194 return FALSE; | 198 return FALSE; |
195 } | 199 } |
196 return TRUE; | 200 return TRUE; |
197 } | 201 } |
198 | 202 |
199 static NaClValidationStatus ValidatorCodeReplacement_x86_64( | 203 static NaClValidationStatus ValidatorCodeReplacement_x86_64( |
200 uintptr_t guest_addr, | 204 uintptr_t guest_addr, |
201 uint8_t *data_old, | 205 uint8_t *data_old, |
202 uint8_t *data_new, | 206 uint8_t *data_new, |
203 size_t size, | 207 size_t size, |
(...skipping 18 matching lines...) Expand all Loading... |
222 | 226 |
223 static const struct NaClValidatorInterface validator = { | 227 static const struct NaClValidatorInterface validator = { |
224 ApplyDfaValidator_x86_64, | 228 ApplyDfaValidator_x86_64, |
225 ValidatorCodeCopy_x86_64, | 229 ValidatorCodeCopy_x86_64, |
226 ValidatorCodeReplacement_x86_64, | 230 ValidatorCodeReplacement_x86_64, |
227 }; | 231 }; |
228 | 232 |
229 const struct NaClValidatorInterface *NaClDfaValidatorCreate_x86_64() { | 233 const struct NaClValidatorInterface *NaClDfaValidatorCreate_x86_64() { |
230 return &validator; | 234 return &validator; |
231 } | 235 } |
OLD | NEW |