Chromium Code Reviews| 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 /* | 7 /* |
| 8 * nccopycode.c | 8 * nccopycode.c |
| 9 * Copies two code streams in a thread-safe way | 9 * Copies two code streams in a thread-safe way |
| 10 * | 10 * |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 22 #include <stdlib.h> | 22 #include <stdlib.h> |
| 23 #include <errno.h> | 23 #include <errno.h> |
| 24 #include <string.h> | 24 #include <string.h> |
| 25 #include <assert.h> | 25 #include <assert.h> |
| 26 #include "native_client/src/include/nacl_platform.h" | 26 #include "native_client/src/include/nacl_platform.h" |
| 27 #include "native_client/src/shared/platform/nacl_check.h" | 27 #include "native_client/src/shared/platform/nacl_check.h" |
| 28 #include "native_client/src/trusted/service_runtime/sel_ldr.h" | 28 #include "native_client/src/trusted/service_runtime/sel_ldr.h" |
| 29 #include "native_client/src/trusted/service_runtime/sel_memory.h" | 29 #include "native_client/src/trusted/service_runtime/sel_memory.h" |
| 30 #include "native_client/src/trusted/validator/ncvalidate.h" | 30 #include "native_client/src/trusted/validator/ncvalidate.h" |
| 31 | 31 |
| 32 #if NACL_ARCH(NACL_TARGET_ARCH) == NACL_x86 | 32 #if NACL_ARCH(NACL_TARGET_ARCH) == NACL_x86 |
|
Nick Bray
2012/05/25 06:41:21
Remove dead includes?
| |
| 33 # if NACL_TARGET_SUBARCH == 32 | 33 # if NACL_TARGET_SUBARCH == 32 |
| 34 # include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode.h" | 34 # include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode.h" |
| 35 # include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate.h" | 35 # include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate.h" |
| 36 # elif NACL_TARGET_SUBARCH == 64 | 36 # elif NACL_TARGET_SUBARCH == 64 |
| 37 # include "native_client/src/trusted/validator/x86/decoder/nc_inst_iter.h" | 37 # include "native_client/src/trusted/validator/x86/decoder/nc_inst_iter.h" |
| 38 # include "native_client/src/trusted/validator/x86/decoder/nc_inst_state_intern al.h" | 38 # include "native_client/src/trusted/validator/x86/decoder/nc_inst_state_intern al.h" |
| 39 # include "native_client/src/trusted/validator/x86/nacl_cpuid.h" | 39 # include "native_client/src/trusted/validator/x86/nacl_cpuid.h" |
| 40 # include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncval_decode_t ables.h" | 40 # include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncval_decode_t ables.h" |
| 41 # include "native_client/src/trusted/validator/x86/nc_segment.h" | 41 # include "native_client/src/trusted/validator/x86/nc_segment.h" |
| 42 # else | 42 # else |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 175 */ | 175 */ |
| 176 if (0 != NaCl_mprotect(g_squashybuffer, size, PROT_READ)) { | 176 if (0 != NaCl_mprotect(g_squashybuffer, size, PROT_READ)) { |
| 177 NaClLog(0, | 177 NaClLog(0, |
| 178 ("SerializeAllProcessors: interprocessor interrupt" | 178 ("SerializeAllProcessors: interprocessor interrupt" |
| 179 " generation failed: could not reverse shield polarity (3)\n")); | 179 " generation failed: could not reverse shield polarity (3)\n")); |
| 180 return FALSE; | 180 return FALSE; |
| 181 } | 181 } |
| 182 return TRUE; | 182 return TRUE; |
| 183 } | 183 } |
| 184 | 184 |
| 185 /* | 185 int NaClCopyInstruction_x86(uint8_t *dst, uint8_t *src, uint8_t sz) { |
| 186 * Copy a single instruction, avoiding the possibility of other threads | |
| 187 * executing a partially changed instruction. | |
| 188 */ | |
| 189 static Bool CopyInstructionInternal(uint8_t *dst, | |
| 190 uint8_t *src, | |
| 191 uint8_t sz) { | |
| 192 intptr_t offset = 0; | 186 intptr_t offset = 0; |
| 193 uint8_t *firstbyte_p = dst; | 187 uint8_t *firstbyte_p = dst; |
| 194 | 188 |
| 195 while (sz > 0 && dst[0] == src[0]) { | 189 while (sz > 0 && dst[0] == src[0]) { |
| 196 /* scroll to first changed byte */ | 190 /* scroll to first changed byte */ |
| 197 dst++, src++, sz--; | 191 dst++, src++, sz--; |
| 198 } | 192 } |
| 199 | 193 |
| 200 if (sz == 0) { | 194 if (sz == 0) { |
| 201 /* instructions are identical, we are done */ | 195 /* instructions are identical, we are done */ |
| 202 return TRUE; | 196 return 1; |
| 203 } | 197 } |
| 204 | 198 |
| 205 while (sz > 0 && dst[sz-1] == src[sz-1]) { | 199 while (sz > 0 && dst[sz-1] == src[sz-1]) { |
| 206 /* trim identical bytes at end */ | 200 /* trim identical bytes at end */ |
| 207 sz--; | 201 sz--; |
| 208 } | 202 } |
| 209 | 203 |
| 210 if (sz == 1) { | 204 if (sz == 1) { |
| 211 /* we assume a 1-byte change is atomic */ | 205 /* we assume a 1-byte change is atomic */ |
| 212 *dst = *src; | 206 *dst = *src; |
| 213 } else if (IsTrustedWrite(dst, sz, 4, &offset)) { | 207 } else if (IsTrustedWrite(dst, sz, 4, &offset)) { |
| 214 uint8_t tmp[4]; | 208 uint8_t tmp[4]; |
| 215 memcpy(tmp, dst-offset, sizeof tmp); | 209 memcpy(tmp, dst-offset, sizeof tmp); |
| 216 memcpy(tmp+offset, src, sz); | 210 memcpy(tmp+offset, src, sz); |
| 217 onestore_memmove4(dst-offset, tmp); | 211 onestore_memmove4(dst-offset, tmp); |
| 218 } else if (IsTrustedWrite(dst, sz, 8, &offset)) { | 212 } else if (IsTrustedWrite(dst, sz, 8, &offset)) { |
| 219 uint8_t tmp[8]; | 213 uint8_t tmp[8]; |
| 220 memcpy(tmp, dst-offset, sizeof tmp); | 214 memcpy(tmp, dst-offset, sizeof tmp); |
| 221 memcpy(tmp+offset, src, sz); | 215 memcpy(tmp+offset, src, sz); |
| 222 onestore_memmove8(dst-offset, tmp); | 216 onestore_memmove8(dst-offset, tmp); |
| 223 } else { | 217 } else { |
| 224 /* the slow path, first flip first byte to halt*/ | 218 /* the slow path, first flip first byte to halt*/ |
| 225 uint8_t firstbyte = firstbyte_p[0]; | 219 uint8_t firstbyte = firstbyte_p[0]; |
| 226 firstbyte_p[0] = kNaClFullStop; | 220 firstbyte_p[0] = kNaClFullStop; |
| 227 | 221 |
| 228 if (!SerializeAllProcessors()) return FALSE; | 222 if (!SerializeAllProcessors()) return 0; |
| 229 | 223 |
| 230 /* copy the rest of instruction */ | 224 /* copy the rest of instruction */ |
| 231 if (dst == firstbyte_p) { | 225 if (dst == firstbyte_p) { |
| 232 /* but not the first byte! */ | 226 /* but not the first byte! */ |
| 233 firstbyte = *src; | 227 firstbyte = *src; |
| 234 dst++, src++, sz--; | 228 dst++, src++, sz--; |
| 235 } | 229 } |
| 236 memcpy(dst, src, sz); | 230 memcpy(dst, src, sz); |
| 237 | 231 |
| 238 if (!SerializeAllProcessors()) return FALSE; | 232 if (!SerializeAllProcessors()) return 0; |
| 239 | 233 |
| 240 /* flip first byte back */ | 234 /* flip first byte back */ |
| 241 firstbyte_p[0] = firstbyte; | 235 firstbyte_p[0] = firstbyte; |
| 242 } | 236 } |
| 243 return TRUE; | 237 return 1; |
| 244 } | 238 } |
| 245 | |
| 246 #if NACL_TARGET_SUBARCH == 32 | |
| 247 | |
| 248 /* | |
| 249 * Copy a single instruction, avoiding the possibility of other threads | |
| 250 * executing a partially changed instruction. | |
| 251 */ | |
| 252 static Bool CopyInstruction(NCDecoderStatePair* tthis, | |
| 253 NCDecoderInst *dinst_old, | |
| 254 NCDecoderInst *dinst_new) { | |
| 255 NCRemainingMemory* mem_old = &dinst_old->dstate->memory; | |
| 256 NCRemainingMemory* mem_new = &dinst_new->dstate->memory; | |
| 257 | |
| 258 return CopyInstructionInternal(mem_old->mpc, | |
| 259 mem_new->mpc, | |
| 260 mem_old->read_length); | |
| 261 } | |
| 262 | |
| 263 int NCCopyCode(uint8_t *dst, uint8_t *src, NaClPcAddress vbase, | |
| 264 size_t sz) { | |
| 265 NCDecoderState dst_dstate; | |
| 266 NCDecoderInst dst_inst; | |
| 267 NCDecoderState src_dstate; | |
| 268 NCDecoderInst src_inst; | |
| 269 NCDecoderStatePair pair; | |
| 270 int result = 0; | |
| 271 | |
| 272 NCDecoderStateConstruct(&dst_dstate, dst, vbase, sz, &dst_inst, 1); | |
| 273 NCDecoderStateConstruct(&src_dstate, src, vbase, sz, &src_inst, 1); | |
| 274 NCDecoderStatePairConstruct(&pair, &dst_dstate, &src_dstate); | |
| 275 pair.action_fn = CopyInstruction; | |
| 276 if (NCDecoderStatePairDecode(&pair)) result = 1; | |
| 277 NCDecoderStatePairDestruct(&pair); | |
| 278 NCDecoderStateDestruct(&src_dstate); | |
| 279 NCDecoderStateDestruct(&dst_dstate); | |
| 280 | |
| 281 return result; | |
| 282 } | |
| 283 | |
| 284 NaClValidationStatus NACL_SUBARCH_NAME(ApplyValidatorCopy, | |
| 285 NACL_TARGET_ARCH, | |
| 286 NACL_TARGET_SUBARCH) | |
| 287 (uintptr_t guest_addr, | |
| 288 uint8_t *data_old, | |
| 289 uint8_t *data_new, | |
| 290 size_t size, | |
| 291 const NaClCPUFeaturesX86 *cpu_features) { | |
| 292 if (!NaClArchSupported(cpu_features)) | |
| 293 return NaClValidationFailedCpuNotSupported; | |
| 294 | |
| 295 return ((0 == NCCopyCode(data_old, data_new, guest_addr, | |
| 296 size)) | |
| 297 ? NaClValidationFailed : NaClValidationSucceeded); | |
| 298 } | |
| 299 | |
| 300 #elif NACL_TARGET_SUBARCH == 64 | |
| 301 | |
| 302 int NaClCopyCodeIter(uint8_t *dst, uint8_t *src, | |
| 303 NaClPcAddress vbase, size_t size) { | |
| 304 NaClSegment segment_old, segment_new; | |
| 305 NaClInstIter *iter_old, *iter_new; | |
| 306 NaClInstState *istate_old, *istate_new; | |
| 307 int still_good = 1; | |
| 308 | |
| 309 NaClSegmentInitialize(dst, vbase, size, &segment_old); | |
| 310 NaClSegmentInitialize(src, vbase, size, &segment_new); | |
| 311 | |
| 312 iter_old = NaClInstIterCreate(kNaClValDecoderTables, &segment_old); | |
| 313 if (NULL == iter_old) return 0; | |
| 314 iter_new = NaClInstIterCreate(kNaClValDecoderTables, &segment_new); | |
| 315 if (NULL == iter_new) { | |
| 316 NaClInstIterDestroy(iter_old); | |
| 317 return 0; | |
| 318 } | |
| 319 while (1) { | |
| 320 /* March over every instruction, which means NaCl pseudo-instructions are | |
| 321 * treated as multiple instructions. Checks in NaClValidateCodeReplacement | |
| 322 * guarantee that only valid replacements will happen, and no pseudo- | |
| 323 * instructions should be touched. | |
| 324 */ | |
| 325 if (!(NaClInstIterHasNext(iter_old) && NaClInstIterHasNext(iter_new))) { | |
| 326 if (NaClInstIterHasNext(iter_old) || NaClInstIterHasNext(iter_new)) { | |
| 327 NaClLog(LOG_ERROR, | |
| 328 "Segment replacement: copy failed: iterators " | |
| 329 "length mismatch\n"); | |
| 330 still_good = 0; | |
| 331 } | |
| 332 break; | |
| 333 } | |
| 334 istate_old = NaClInstIterGetState(iter_old); | |
| 335 istate_new = NaClInstIterGetState(iter_new); | |
| 336 if (istate_old->bytes.length != istate_new->bytes.length || | |
| 337 iter_old->memory.read_length != iter_new->memory.read_length || | |
| 338 istate_new->inst_addr != istate_old->inst_addr) { | |
| 339 /* Sanity check: this should never happen based on checks in | |
| 340 * NaClValidateInstReplacement. | |
| 341 */ | |
| 342 NaClLog(LOG_ERROR, | |
| 343 "Segment replacement: copied instructions misaligned\n"); | |
| 344 still_good = 0; | |
| 345 break; | |
| 346 } | |
| 347 /* Replacing all modified instructions at once could yield a speedup here | |
| 348 * as every time we modify instructions we must serialize all processors | |
| 349 * twice. Re-evaluate if code modification performance is an issue. | |
| 350 */ | |
| 351 if (!CopyInstructionInternal(iter_old->memory.mpc, | |
| 352 iter_new->memory.mpc, | |
| 353 iter_old->memory.read_length)) { | |
| 354 NaClLog(LOG_ERROR, | |
| 355 "Segment replacement: copy failed: unable to copy instruction\n"); | |
| 356 still_good = 0; | |
| 357 break; | |
| 358 } | |
| 359 NaClInstIterAdvance(iter_old); | |
| 360 NaClInstIterAdvance(iter_new); | |
| 361 } | |
| 362 | |
| 363 NaClInstIterDestroy(iter_old); | |
| 364 NaClInstIterDestroy(iter_new); | |
| 365 return still_good; | |
| 366 } | |
| 367 | |
| 368 NaClValidationStatus NACL_SUBARCH_NAME(ApplyValidatorCopy, | |
| 369 NACL_TARGET_ARCH, | |
| 370 NACL_TARGET_SUBARCH) | |
| 371 (uintptr_t guest_addr, | |
| 372 uint8_t *data_old, | |
| 373 uint8_t *data_new, | |
| 374 size_t size, | |
| 375 const NaClCPUFeaturesX86 *cpu_features) { | |
| 376 if (!NaClArchSupported(cpu_features)) | |
| 377 return NaClValidationFailedCpuNotSupported; | |
| 378 | |
| 379 return (0 == NaClCopyCodeIter(data_old, data_new, guest_addr, size)) | |
| 380 ? NaClValidationFailed : NaClValidationSucceeded; | |
| 381 } | |
| 382 | |
| 383 #endif | |
| OLD | NEW |