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 #include "native_client/src/shared/platform/nacl_log.h" | 7 #include "native_client/src/shared/platform/nacl_log.h" |
| 8 #include "native_client/src/trusted/service_runtime/sel_ldr.h" | 8 #include "native_client/src/trusted/service_runtime/sel_ldr.h" |
| 9 #include "native_client/src/trusted/validator/ncvalidate.h" | 9 #include "native_client/src/trusted/validator/ncvalidate.h" |
| 10 | 10 |
| 11 const size_t kMinimumCachedCodeSize = 40000; | 11 const size_t kMinimumCachedCodeSize = 40000; |
| 12 | 12 |
| 13 /* Translate validation status to values wanted by sel_ldr. */ | 13 /* Translate validation status to values wanted by sel_ldr. */ |
| 14 static int NaClValidateStatus(NaClValidationStatus status) { | 14 static int NaClValidateStatus(NaClValidationStatus status) { |
| 15 switch (status) { | 15 switch (status) { |
| 16 case NaClValidationSucceeded: | 16 case NaClValidationSucceeded: |
| 17 return LOAD_OK; | 17 return LOAD_OK; |
| 18 case NaClValidationFailedOutOfMemory: | 18 case NaClValidationFailedOutOfMemory: |
| 19 /* Note: this is confusing, but is what sel_ldr is expecting. */ | 19 /* Note: this is confusing, but is what sel_ldr is expecting. */ |
| 20 return LOAD_BAD_FILE; | 20 return LOAD_BAD_FILE; |
| 21 case NaClValidationFailed: | 21 case NaClValidationFailed: |
| 22 case NaClValidationFailedNotImplemented: | 22 case NaClValidationFailedNotImplemented: |
| 23 case NaClValidationFailedCpuNotSupported: | 23 case NaClValidationFailedCpuNotSupported: |
| 24 case NaClValidationFailedSegmentationIssue: | 24 case NaClValidationFailedSegmentationIssue: |
| 25 default: | 25 default: |
| 26 return LOAD_VALIDATION_FAILED; | 26 return LOAD_VALIDATION_FAILED; |
| 27 } | 27 } |
| 28 } | 28 } |
| 29 | 29 |
| 30 typedef NaClValidationStatus (*ValidateFunc) ( | 30 Bool UseDfaValidator() { |
| 31 uintptr_t, uint8_t*, size_t, int, int, | 31 if (getenv("NACL_DANGEROUS_USE_DFA_VALIDATOR") != NULL) { |
| 32 const NaClCPUFeatures*, struct NaClValidationCache*); | 32 return TRUE; |
| 33 } | |
| 34 return FALSE; | |
| 35 } | |
| 33 | 36 |
| 34 static ValidateFunc NaClSelectValidator(struct NaClApp *nap) { | 37 void NaClSelectValidator(struct NaClValidatorInterface **val) { |
| 35 ValidateFunc ret = NACL_SUBARCH_NAME(ApplyValidator, | 38 /* TODO: make it more nested. */ |
|
Nick Bray
2012/04/27 22:21:36
I started with it being nested, but unless you ind
pasko-google - do not use
2012/05/12 12:18:40
to me it looks almost equally horrible, so I'd bet
| |
| 36 NACL_TARGET_ARCH, NACL_TARGET_SUBARCH); | 39 #if defined(__i386__) && defined(NACL_STANDALONE) |
| 37 /* Avoid linking two validators into Chromium to keep download size small. */ | 40 if (UseDfaValidator()) { |
| 38 #if defined(__arm__) || !defined(NACL_STANDALONE) | 41 fprintf(stderr, "DANGER! USING THE UNSTABLE DFA VALIDATOR!\n"); |
|
Nick Bray
2012/04/27 22:21:36
Nit: Experimental? Untested?
pasko-google - do not use
2012/05/12 12:18:40
Done.
| |
| 39 UNREFERENCED_PARAMETER(nap); | 42 NaClDfaValidatorInit_x86_32(val); |
| 43 } else { | |
| 44 NaClValidatorInit_x86_32(val); | |
| 45 } | |
| 46 #elif defined(__i386__) | |
| 47 NaClValidatorInit_x86_32(val); | |
| 48 #elif defined(__x86_64__) && defined(NACL_STANDALONE) | |
| 49 if (UseDfaValidator()) { | |
| 50 fprintf(stderr, "DANGER! USING THE UNSTABLE DFA VALIDATOR!\n"); | |
| 51 NaClDfaValidatorInit_x86_64(val); | |
| 52 } else { | |
| 53 NaClValidatorInit_x86_64(val); | |
| 54 } | |
| 55 #elif defined(__x86_64__) | |
| 56 NaClValidatorInit_x86_64(val); | |
| 57 #elif defined(__arm__) | |
| 58 NaClValidatorInitArm(val); | |
| 40 #else | 59 #else |
| 41 if (nap->enable_dfa_validator) { | 60 #error "No validator available for this architecture!" |
| 42 ret = NACL_SUBARCH_NAME(ApplyDfaValidator, | 61 #endif |
| 43 NACL_TARGET_ARCH, NACL_TARGET_SUBARCH); | 62 } |
| 63 | |
| 64 #if 0 | |
| 65 void NaClSelectValidator(struct NaClApp *nap) { | |
| 66 nap->validate_func = NACL_SUBARCH_NAME(ApplyValidator, | |
| 67 NACL_TARGET_ARCH, NACL_TARGET_SUBARCH); | |
| 68 #if !defined(__arm__) && defined(NACL_STANDALONE) | |
| 69 if (getenv("NACL_DANGEROUS_USE_DFA_VALIDATOR") != NULL) { | |
| 70 fprintf(stderr, "DANGER! USING THE UNSTABLE DFA VALIDATOR!\n"); | |
| 71 nap->validate_func = NACL_SUBARCH_NAME(ApplyDfaValidator, | |
| 72 NACL_TARGET_ARCH, NACL_TARGET_SUBARCH); | |
| 44 } | 73 } |
| 45 #endif | 74 #endif |
| 46 return ret; | 75 nap->validate_copy_func = ValidatorCopyNotImplemented; |
| 76 nap->validate_code_replacement_func = ValidatorCodeReplacementNotImplemented; | |
| 77 #ifndef __arm__ | |
| 78 nap->validate_copy_func = NACL_SUBARCH_NAME(ApplyValidatorCopy, | |
| 79 NACL_TARGET_ARCH, NACL_TARGET_SUBARCH); | |
| 80 nap->validate_code_replacement_func = NACL_SUBARCH_NAME( | |
| 81 ApplyValidatorCodeReplacement, NACL_TARGET_ARCH, NACL_TARGET_SUBARCH); | |
| 82 #endif | |
| 47 } | 83 } |
| 84 #endif | |
| 48 | 85 |
| 49 int NaClValidateCode(struct NaClApp *nap, uintptr_t guest_addr, | 86 int NaClValidateCode(struct NaClApp *nap, uintptr_t guest_addr, |
| 50 uint8_t *data, size_t size) { | 87 uint8_t *data, size_t size) { |
| 51 NaClValidationStatus status = NaClValidationSucceeded; | 88 NaClValidationStatus status = NaClValidationSucceeded; |
| 52 struct NaClValidationCache *cache = nap->validation_cache; | 89 struct NaClValidationCache *cache = nap->validation_cache; |
| 53 ValidateFunc validate_func = NaClSelectValidator(nap); | 90 struct NaClValidatorInterface *validator = nap->validator; |
| 54 | 91 |
| 55 if (size < kMinimumCachedCodeSize) { | 92 if (size < kMinimumCachedCodeSize) { |
| 56 /* | 93 /* |
| 57 * Don't cache the validation of small code chunks for three reasons: | 94 * Don't cache the validation of small code chunks for three reasons: |
| 58 * 1) The size of the validation cache will be bounded. Cache entries are | 95 * 1) The size of the validation cache will be bounded. Cache entries are |
| 59 * better used for bigger code. | 96 * better used for bigger code. |
| 60 * 2) The per-transaction overhead of validation caching is more noticeable | 97 * 2) The per-transaction overhead of validation caching is more noticeable |
| 61 * for small code. | 98 * for small code. |
| 62 * 3) JITs tend to generate a lot of small code chunks, and JITed code may | 99 * 3) JITs tend to generate a lot of small code chunks, and JITed code may |
| 63 * never be seen again. Currently code size is the best mechanism we | 100 * never be seen again. Currently code size is the best mechanism we |
| 64 * have for heuristically distinguishing between JIT and static code. | 101 * have for heuristically distinguishing between JIT and static code. |
| 65 * (In practice most Mono JIT blocks are less than 1k, and a quick look | 102 * (In practice most Mono JIT blocks are less than 1k, and a quick look |
| 66 * didn't show any above 35k.) | 103 * didn't show any above 35k.) |
| 67 * The choice of what constitutes "small" is arbitrary, and should be | 104 * The choice of what constitutes "small" is arbitrary, and should be |
| 68 * empirically tuned. | 105 * empirically tuned. |
| 69 * TODO(ncbray) let the syscall specify if the code is cached or not. | 106 * TODO(ncbray) let the syscall specify if the code is cached or not. |
| 70 */ | 107 */ |
| 71 cache = NULL; | 108 cache = NULL; |
| 72 } | 109 } |
| 73 | 110 |
| 74 /* As fixed feature mode implies the text should be readonly, and | 111 /* As fixed feature mode implies the text should be readonly, and |
| 75 * stubout mode implies updating the text, disallow their use together. | 112 * stubout mode implies updating the text, disallow their use together. |
| 76 */ | 113 */ |
| 77 if (nap->validator_stub_out_mode && nap->fixed_feature_cpu_mode) { | 114 if (nap->validator_stub_out_mode && nap->fixed_feature_cpu_mode) { |
| 78 NaClLog(LOG_FATAL, | 115 NaClLog(LOG_FATAL, |
| 79 "stub_out_mode and fixed_feature_cpu_mode are incompatible\n"); | 116 "stub_out_mode and fixed_feature_cpu_mode are incompatible\n"); |
| 80 return LOAD_VALIDATION_FAILED; | 117 return LOAD_VALIDATION_FAILED; |
| 81 } | 118 } |
| 119 | |
| 82 if (nap->validator_stub_out_mode) { | 120 if (nap->validator_stub_out_mode) { |
| 83 /* Validation caching is currently incompatible with stubout. */ | 121 /* Validation caching is currently incompatible with stubout. */ |
| 84 cache = NULL; | 122 cache = NULL; |
| 85 /* In stub out mode, we do two passes. The second pass acts as a | 123 /* In stub out mode, we do two passes. The second pass acts as a |
| 86 sanity check that bad instructions were indeed overwritten with | 124 sanity check that bad instructions were indeed overwritten with |
| 87 allowable HLTs. */ | 125 allowable HLTs. */ |
| 88 status = validate_func(guest_addr, data, size, | 126 status = validator->Validate(guest_addr, data, size, |
| 89 TRUE, /* stub out */ | 127 TRUE, /* stub out */ |
| 90 FALSE, /* text is not read-only */ | 128 FALSE, /* text is not read-only */ |
| 91 &nap->cpu_features, | 129 &nap->cpu_features, |
| 92 cache); | 130 cache); |
| 93 } | 131 } |
| 94 if (status == NaClValidationSucceeded) { | 132 if (status == NaClValidationSucceeded) { |
| 95 /* Fixed feature CPU mode implies read-only. */ | 133 /* Fixed feature CPU mode implies read-only. */ |
| 96 int readonly_text = nap->fixed_feature_cpu_mode; | 134 int readonly_text = nap->fixed_feature_cpu_mode; |
| 97 status = validate_func(guest_addr, data, size, | 135 status = validator->Validate(guest_addr, data, size, |
| 98 FALSE, /* do not stub out */ | 136 FALSE, /* do not stub out */ |
| 99 readonly_text, | 137 readonly_text, |
| 100 &nap->cpu_features, | 138 &nap->cpu_features, |
| 101 cache); | 139 cache); |
| 102 } | 140 } |
| 103 return NaClValidateStatus(status); | 141 return NaClValidateStatus(status); |
| 104 } | 142 } |
| 105 | 143 |
| 106 int NaClValidateCodeReplacement(struct NaClApp *nap, uintptr_t guest_addr, | 144 int NaClValidateCodeReplacement(struct NaClApp *nap, uintptr_t guest_addr, |
| 107 uint8_t *data_old, uint8_t *data_new, | 145 uint8_t *data_old, uint8_t *data_new, |
| 108 size_t size) { | 146 size_t size) { |
| 109 if (nap->validator_stub_out_mode) return LOAD_BAD_FILE; | 147 if (nap->validator_stub_out_mode) return LOAD_BAD_FILE; |
| 110 if (nap->fixed_feature_cpu_mode) return LOAD_BAD_FILE; | 148 if (nap->fixed_feature_cpu_mode) return LOAD_BAD_FILE; |
| 111 | 149 |
| 112 if ((guest_addr % nap->bundle_size) != 0 || | 150 if ((guest_addr % nap->bundle_size) != 0 || |
| 113 (size % nap->bundle_size) != 0) { | 151 (size % nap->bundle_size) != 0) { |
| 114 return LOAD_BAD_FILE; | 152 return LOAD_BAD_FILE; |
| 115 } | 153 } |
| 116 | 154 |
| 117 return NaClValidateStatus( | 155 return NaClValidateStatus(nap->validator->ValidateCodeReplacement( |
| 118 NACL_SUBARCH_NAME(ApplyValidatorCodeReplacement, | 156 guest_addr, data_old, data_new, size, &nap->cpu_features)); |
| 119 NACL_TARGET_ARCH, | |
| 120 NACL_TARGET_SUBARCH) | |
| 121 (guest_addr, data_old, data_new, size, &nap->cpu_features)); | |
| 122 } | 157 } |
| 123 | 158 |
| 124 int NaClCopyCode(struct NaClApp *nap, uintptr_t guest_addr, | 159 int NaClCopyCode(struct NaClApp *nap, uintptr_t guest_addr, |
| 125 uint8_t *data_old, uint8_t *data_new, | 160 uint8_t *data_old, uint8_t *data_new, |
| 126 size_t size) { | 161 size_t size) { |
| 127 /* Fixed-feature mode disables any code copying for now. Currently | 162 /* Fixed-feature mode disables any code copying for now. Currently |
| 128 * the only use of NaClCodeCopy() seems to be for dynamic code | 163 * the only use of NaClCodeCopy() seems to be for dynamic code |
| 129 * modification, which should fail in NaClValidateCodeReplacement() | 164 * modification, which should fail in NaClValidateCodeReplacement() |
| 130 * before reaching this. | 165 * before reaching this. |
| 131 */ | 166 */ |
| 132 if (nap->fixed_feature_cpu_mode) return LOAD_BAD_FILE; | 167 if (nap->fixed_feature_cpu_mode) return LOAD_BAD_FILE; |
| 133 return NaClValidateStatus( | 168 return NaClValidateStatus(nap->validator->ValidateCopy( |
|
Nick Bray
2012/04/27 22:21:36
Bad name. Validating a copy of what? Hence why I
| |
| 134 NACL_SUBARCH_NAME(ApplyValidatorCopy, | 169 guest_addr, data_old, data_new, size, &nap->cpu_features)); |
| 135 NACL_TARGET_ARCH, | |
| 136 NACL_TARGET_SUBARCH) | |
| 137 (guest_addr, data_old, data_new, size, &nap->cpu_features)); | |
| 138 } | 170 } |
| 139 | 171 |
| 140 NaClErrorCode NaClValidateImage(struct NaClApp *nap) { | 172 NaClErrorCode NaClValidateImage(struct NaClApp *nap) { |
| 141 uintptr_t memp; | 173 uintptr_t memp; |
| 142 uintptr_t endp; | 174 uintptr_t endp; |
| 143 size_t regionsize; | 175 size_t regionsize; |
| 144 NaClErrorCode rcode; | 176 NaClErrorCode rcode; |
| 145 | 177 |
| 146 memp = nap->mem_start + NACL_TRAMPOLINE_END; | 178 memp = nap->mem_start + NACL_TRAMPOLINE_END; |
| 147 endp = nap->mem_start + nap->static_text_end; | 179 endp = nap->mem_start + nap->static_text_end; |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 165 NaClLog(LOG_ERROR, | 197 NaClLog(LOG_ERROR, |
| 166 "Run sel_ldr in debug mode to ignore validation failure.\n"); | 198 "Run sel_ldr in debug mode to ignore validation failure.\n"); |
| 167 NaClLog(LOG_ERROR, | 199 NaClLog(LOG_ERROR, |
| 168 "Run ncval <module-name> for validation error details.\n"); | 200 "Run ncval <module-name> for validation error details.\n"); |
| 169 rcode = LOAD_VALIDATION_FAILED; | 201 rcode = LOAD_VALIDATION_FAILED; |
| 170 } | 202 } |
| 171 } | 203 } |
| 172 } | 204 } |
| 173 return rcode; | 205 return rcode; |
| 174 } | 206 } |
| OLD | NEW |