| OLD | NEW |
| (Empty) |
| 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 /* | |
| 8 * This tool rewrites ELF files to replace instructions that will be | |
| 9 * rejected by the validator with safe HLT instructions. This is | |
| 10 * useful if you have a large library in which many functions do not | |
| 11 * validate but are not immediately required to work. Replacing the | |
| 12 * forbidden instructions with HLTs makes it easier to find the | |
| 13 * instructions that are needed first, and fix and test them. | |
| 14 */ | |
| 15 | |
| 16 #include <assert.h> | |
| 17 #include <stdio.h> | |
| 18 #include <string.h> | |
| 19 | |
| 20 #include "native_client/src/include/elf.h" | |
| 21 #include "native_client/src/shared/gio/gio.h" | |
| 22 #include "native_client/src/shared/platform/nacl_check.h" | |
| 23 #include "native_client/src/shared/utils/types.h" | |
| 24 #include "native_client/src/trusted/validator/ncvalidate.h" | |
| 25 | |
| 26 static Bool FixUpSectionCheckStatus(NaClValidationStatus status) { | |
| 27 switch (status) { | |
| 28 case NaClValidationSucceeded: | |
| 29 return TRUE; | |
| 30 default: | |
| 31 case NaClValidationFailed: | |
| 32 fprintf(stderr, "Errors still exist after attempting to stubout code\n"); | |
| 33 return FALSE; | |
| 34 case NaClValidationFailedOutOfMemory: | |
| 35 fprintf(stderr, "Unable to stubout code, not enough memory\n"); | |
| 36 return FALSE; | |
| 37 case NaClValidationFailedNotImplemented: | |
| 38 fprintf(stderr, "Unable to stubout code, not implemented\n"); | |
| 39 return FALSE; | |
| 40 case NaClValidationFailedCpuNotSupported: | |
| 41 /* This shouldn't happen, but if it does, report the problem. */ | |
| 42 fprintf(stderr, "Unable to stubout code, cpu not supported\n"); | |
| 43 return FALSE; | |
| 44 case NaClValidationFailedSegmentationIssue: | |
| 45 fprintf(stderr, "Unable to stubout code, segmentation issues found\n"); | |
| 46 return FALSE; | |
| 47 } | |
| 48 return FALSE; | |
| 49 } | |
| 50 | |
| 51 static Bool FixUpSection(const struct NaClValidatorInterface *validator, | |
| 52 uintptr_t load_address, | |
| 53 unsigned char *code, | |
| 54 size_t code_size) { | |
| 55 Bool result; | |
| 56 NaClValidationStatus status; | |
| 57 NaClCPUFeatures *cpu_features = malloc(validator->CPUFeatureSize); | |
| 58 if (cpu_features == NULL) { | |
| 59 fprintf(stderr, "Unable to create memory for CPU features\n"); | |
| 60 return FALSE; | |
| 61 } | |
| 62 /* Pretend that the CPU supports every feature so that we will only stub out | |
| 63 * instructions that NaCl will never allow under any condition. | |
| 64 */ | |
| 65 validator->SetAllCPUFeatures(cpu_features); | |
| 66 | |
| 67 status = validator->Validate( | |
| 68 load_address, code, code_size, | |
| 69 /* stubout_mode= */ TRUE, | |
| 70 /* readonly_text= */ FALSE, | |
| 71 cpu_features, | |
| 72 /* metadata= */ NULL, | |
| 73 /* cache= */ NULL); | |
| 74 if (status == NaClValidationSucceeded) { | |
| 75 /* Now run the validator again, so that we report any errors | |
| 76 * that were not fixed by stubbing out. This is done so that | |
| 77 * the user knows that stubout doesn't fix all errors. | |
| 78 */ | |
| 79 status = NACL_SUBARCH_NAME(ApplyValidatorVerbosely, | |
| 80 NACL_TARGET_ARCH, | |
| 81 NACL_TARGET_SUBARCH) | |
| 82 (load_address, code, code_size, cpu_features); | |
| 83 } | |
| 84 | |
| 85 result = FixUpSectionCheckStatus(status); | |
| 86 free(cpu_features); | |
| 87 return result; | |
| 88 } | |
| 89 | |
| 90 static void CheckBounds(unsigned char *data, size_t data_size, | |
| 91 void *ptr, size_t inside_size) { | |
| 92 CHECK(data <= (unsigned char *) ptr); | |
| 93 CHECK((unsigned char *) ptr + inside_size <= data + data_size); | |
| 94 } | |
| 95 | |
| 96 static Bool FixUpELF32(const struct NaClValidatorInterface *validator, | |
| 97 unsigned char *data, | |
| 98 size_t data_size) { | |
| 99 Elf32_Ehdr *header; | |
| 100 int index; | |
| 101 Bool fixed = TRUE; /* until proven otherwise. */ | |
| 102 | |
| 103 header = (Elf32_Ehdr *) data; | |
| 104 CheckBounds(data, data_size, header, sizeof(*header)); | |
| 105 CHECK(memcmp(header->e_ident, ELFMAG, strlen(ELFMAG)) == 0); | |
| 106 | |
| 107 for (index = 0; index < header->e_shnum; index++) { | |
| 108 Elf32_Shdr *section = (Elf32_Shdr *) (data + header->e_shoff + | |
| 109 header->e_shentsize * index); | |
| 110 CheckBounds(data, data_size, section, sizeof(*section)); | |
| 111 | |
| 112 if ((section->sh_flags & SHF_EXECINSTR) != 0) { | |
| 113 CheckBounds(data, data_size, | |
| 114 data + section->sh_offset, section->sh_size); | |
| 115 if (!FixUpSection(validator, | |
| 116 section->sh_addr, | |
| 117 data + section->sh_offset, | |
| 118 section->sh_size)) { | |
| 119 fixed = FALSE; | |
| 120 } | |
| 121 } | |
| 122 } | |
| 123 return fixed; | |
| 124 } | |
| 125 | |
| 126 #if NACL_TARGET_SUBARCH == 64 | |
| 127 static Bool FixUpELF64(const struct NaClValidatorInterface *validator, | |
| 128 unsigned char *data, | |
| 129 size_t data_size) { | |
| 130 Elf64_Ehdr *header; | |
| 131 int index; | |
| 132 Bool fixed = TRUE; /* until proven otherwise. */ | |
| 133 | |
| 134 header = (Elf64_Ehdr *) data; | |
| 135 CheckBounds(data, data_size, header, sizeof(*header)); | |
| 136 CHECK(memcmp(header->e_ident, ELFMAG, strlen(ELFMAG)) == 0); | |
| 137 | |
| 138 for (index = 0; index < header->e_shnum; index++) { | |
| 139 Elf64_Shdr *section = (Elf64_Shdr *) (data + header->e_shoff + | |
| 140 header->e_shentsize * index); | |
| 141 CheckBounds(data, data_size, section, sizeof(*section)); | |
| 142 | |
| 143 if ((section->sh_flags & SHF_EXECINSTR) != 0) { | |
| 144 CheckBounds(data, data_size, | |
| 145 data + section->sh_offset, section->sh_size); | |
| 146 if (!FixUpSection(validator, | |
| 147 section->sh_addr, | |
| 148 data + section->sh_offset, | |
| 149 section->sh_size)) { | |
| 150 fixed = FALSE; | |
| 151 } | |
| 152 } | |
| 153 } | |
| 154 return fixed; | |
| 155 } | |
| 156 #endif | |
| 157 | |
| 158 static Bool FixUpELF(const struct NaClValidatorInterface *validator, | |
| 159 unsigned char *data, | |
| 160 size_t data_size) { | |
| 161 #if NACL_TARGET_SUBARCH == 64 | |
| 162 if (data_size > EI_CLASS && data[EI_CLASS] == ELFCLASS64) | |
| 163 return FixUpELF64(validator, data, data_size); | |
| 164 #endif | |
| 165 return FixUpELF32(validator, data, data_size); | |
| 166 } | |
| 167 | |
| 168 static Bool FixUpELFFile(const struct NaClValidatorInterface *validator, | |
| 169 const char *input_file, | |
| 170 const char *output_file) { | |
| 171 FILE *fp; | |
| 172 size_t file_size; | |
| 173 unsigned char *data; | |
| 174 size_t got; | |
| 175 size_t written; | |
| 176 | |
| 177 /* Read whole ELF file and write it back with modifications. */ | |
| 178 fp = fopen(input_file, "rb"); | |
| 179 if (fp == NULL) { | |
| 180 fprintf(stderr, "Failed to open input file: %s\n", input_file); | |
| 181 return FALSE; | |
| 182 } | |
| 183 /* Find the file size. */ | |
| 184 fseek(fp, 0, SEEK_END); | |
| 185 file_size = ftell(fp); | |
| 186 data = malloc(file_size); | |
| 187 if (data == NULL) { | |
| 188 fprintf(stderr, "Unable to create memory imate of input file: %s\n", | |
| 189 input_file); | |
| 190 return FALSE; | |
| 191 } | |
| 192 fseek(fp, 0, SEEK_SET); | |
| 193 got = fread(data, 1, file_size, fp); | |
| 194 if (got != file_size) { | |
| 195 fprintf(stderr, "Unable to read data from input file: %s\n", | |
| 196 input_file); | |
| 197 return FALSE; | |
| 198 } | |
| 199 fclose(fp); | |
| 200 | |
| 201 if (!FixUpELF(validator, data, file_size)) return FALSE; | |
| 202 | |
| 203 fp = fopen(output_file, "wb"); | |
| 204 if (fp == NULL) { | |
| 205 fprintf(stderr, "Failed to open output file: %s\n", output_file); | |
| 206 return FALSE; | |
| 207 } | |
| 208 written = fwrite(data, 1, file_size, fp); | |
| 209 if (written != file_size) { | |
| 210 fprintf(stderr, "Unable to write data to output file: %s\n", | |
| 211 output_file); | |
| 212 return FALSE; | |
| 213 } | |
| 214 fclose(fp); | |
| 215 return TRUE; | |
| 216 } | |
| 217 | |
| 218 int main(int argc, const char *argv[]) { | |
| 219 /* Be sure to redirect validator error messages to stderr. */ | |
| 220 const struct NaClValidatorInterface *validator; | |
| 221 NaClLogModuleInit(); | |
| 222 validator = NaClCreateValidator(); | |
| 223 if (!validator->stubout_mode_implemented) { | |
| 224 fprintf(stderr, | |
| 225 "This platform does not support stubout mode."); | |
| 226 return 1; | |
| 227 } | |
| 228 if (argc != 4 || strcmp(argv[2], "-o") != 0) { | |
| 229 fprintf(stderr, "Usage: %s <input-file> -o <output-file>\n\n", argv[0]); | |
| 230 fprintf(stderr, | |
| 231 "This tool rewrites ELF objects to replace instructions that are\n" | |
| 232 "rejected by the NaCl validator with safe HLT instructions.\n"); | |
| 233 return 1; | |
| 234 } | |
| 235 return FixUpELFFile(validator, argv[1], argv[3]) ? 0 : 1; | |
| 236 } | |
| OLD | NEW |