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

Side by Side Diff: src/trusted/validator/driver/ncval.cc

Issue 1234393005: A mechanism to identify/forbid/"rewrite" non-temporal instructions (and other) (Closed) Base URL: https://chromium.googlesource.com/native_client/src/native_client.git@master
Patch Set: Fixing nits Created 5 years, 4 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
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 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdio.h> 8 #include <stdio.h>
9 #include <stdlib.h> 9 #include <stdlib.h>
10 #include <string.h> 10 #include <string.h>
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
48 string message; 48 string message;
49 Error(uint32_t offset, string message) : offset(offset), message(message) {} 49 Error(uint32_t offset, string message) : offset(offset), message(message) {}
50 }; 50 };
51 51
52 52
53 struct UserData { 53 struct UserData {
54 Segment segment; 54 Segment segment;
55 vector<Error> *errors; 55 vector<Error> *errors;
56 vector<Jump> *jumps; 56 vector<Jump> *jumps;
57 set<uint32_t> *bad_jump_targets; 57 set<uint32_t> *bad_jump_targets;
58 uint32_t flags;
58 UserData(Segment segment, 59 UserData(Segment segment,
59 vector<Error> *errors, 60 vector<Error> *errors,
60 vector<Jump> *jumps, 61 vector<Jump> *jumps,
61 set<uint32_t> *bad_jump_targets) 62 set<uint32_t> *bad_jump_targets,
63 uint32_t flags)
62 : segment(segment), 64 : segment(segment),
63 errors(errors), 65 errors(errors),
64 jumps(jumps), 66 jumps(jumps),
65 bad_jump_targets(bad_jump_targets) { 67 bad_jump_targets(bad_jump_targets),
68 flags(flags) {
66 } 69 }
67 }; 70 };
68 71
69 72
70 Bool ProcessInstruction( 73 Bool ProcessInstruction(
71 const uint8_t *begin, const uint8_t *end, 74 const uint8_t *begin, const uint8_t *end,
72 uint32_t validation_info, void *user_data_ptr) { 75 uint32_t validation_info, void *user_data_ptr) {
73 76
74 UserData &user_data = *reinterpret_cast<UserData *>(user_data_ptr); 77 UserData &user_data = *reinterpret_cast<UserData *>(user_data_ptr);
75 vector<Error> &errors = *user_data.errors; 78 vector<Error> &errors = *user_data.errors;
(...skipping 11 matching lines...) Expand all
87 user_data.segment.data); 90 user_data.segment.data);
88 if (validation_info & RELATIVE_8BIT) { 91 if (validation_info & RELATIVE_8BIT) {
89 program_counter += reinterpret_cast<const int8_t *>(end)[-1]; 92 program_counter += reinterpret_cast<const int8_t *>(end)[-1];
90 user_data.jumps->push_back(Jump(offset, program_counter)); 93 user_data.jumps->push_back(Jump(offset, program_counter));
91 } else if (validation_info & RELATIVE_32BIT) { 94 } else if (validation_info & RELATIVE_32BIT) {
92 program_counter += reinterpret_cast<const int32_t *>(end)[-1]; 95 program_counter += reinterpret_cast<const int32_t *>(end)[-1];
93 user_data.jumps->push_back(Jump(offset, program_counter)); 96 user_data.jumps->push_back(Jump(offset, program_counter));
94 } 97 }
95 } 98 }
96 99
100 // If we are not disabling non-temporals, they should pass validation, and
101 // the corresponding validation_info bit is simply cleared.
102 if (user_data.flags != DISABLE_NONTEMPORALS)
103 validation_info &= ~UNSUPPORTED_INSTRUCTION;
104
97 Bool result = (validation_info & (VALIDATION_ERRORS_MASK | BAD_JUMP_TARGET)) 105 Bool result = (validation_info & (VALIDATION_ERRORS_MASK | BAD_JUMP_TARGET))
98 ? FALSE 106 ? FALSE
99 : TRUE; 107 : TRUE;
100 108
101 // We clear bit for each processed error, and in the end if there are still 109 // We clear bit for each processed error, and in the end if there are still
102 // errors we did not report, we produce generic error message. 110 // errors we did not report, we produce generic error message.
103 // This way, if validator interface was changed (new error bits were 111 // This way, if validator interface was changed (new error bits were
104 // introduced), we at least wouldn't ignore them completely. 112 // introduced), we at least wouldn't ignore them completely.
105 113
106 // TODO(shcherbina): deal with code duplication somehow. 114 // TODO(shcherbina): deal with code duplication somehow.
107 115
108 if (validation_info & UNRECOGNIZED_INSTRUCTION) { 116 if (validation_info & UNRECOGNIZED_INSTRUCTION) {
109 validation_info &= ~UNRECOGNIZED_INSTRUCTION; 117 validation_info &= ~UNRECOGNIZED_INSTRUCTION;
110 errors.push_back(Error(offset, "unrecognized instruction")); 118 errors.push_back(Error(offset, "unrecognized instruction"));
111 } 119 }
112 120
113 if (validation_info & DIRECT_JUMP_OUT_OF_RANGE) { 121 if (validation_info & DIRECT_JUMP_OUT_OF_RANGE) {
114 validation_info &= ~DIRECT_JUMP_OUT_OF_RANGE; 122 validation_info &= ~DIRECT_JUMP_OUT_OF_RANGE;
115 errors.push_back(Error(offset, "direct jump out of range")); 123 errors.push_back(Error(offset, "direct jump out of range"));
116 } 124 }
117 125
118 if (validation_info & CPUID_UNSUPPORTED_INSTRUCTION) { 126 if (validation_info & CPUID_UNSUPPORTED_INSTRUCTION) {
119 validation_info &= ~CPUID_UNSUPPORTED_INSTRUCTION; 127 validation_info &= ~CPUID_UNSUPPORTED_INSTRUCTION;
120 errors.push_back(Error(offset, "required CPU feature not found")); 128 errors.push_back(Error(offset, "required CPU feature not found"));
121 } 129 }
122 130
131 if (validation_info & UNSUPPORTED_INSTRUCTION) {
132 validation_info &= ~UNSUPPORTED_INSTRUCTION;
133 errors.push_back(Error(offset, "unsupported instruction"));
134 }
135
123 if (validation_info & FORBIDDEN_BASE_REGISTER) { 136 if (validation_info & FORBIDDEN_BASE_REGISTER) {
124 validation_info &= ~FORBIDDEN_BASE_REGISTER; 137 validation_info &= ~FORBIDDEN_BASE_REGISTER;
125 errors.push_back(Error(offset, "improper memory address - bad base")); 138 errors.push_back(Error(offset, "improper memory address - bad base"));
126 } 139 }
127 140
128 if (validation_info & UNRESTRICTED_INDEX_REGISTER) { 141 if (validation_info & UNRESTRICTED_INDEX_REGISTER) {
129 validation_info &= ~UNRESTRICTED_INDEX_REGISTER; 142 validation_info &= ~UNRESTRICTED_INDEX_REGISTER;
130 errors.push_back(Error(offset, "improper memory address - bad index")); 143 errors.push_back(Error(offset, "improper memory address - bad index"));
131 } 144 }
132 145
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
185 198
186 return result; 199 return result;
187 } 200 }
188 201
189 202
190 Bool ProcessError( 203 Bool ProcessError(
191 const uint8_t *begin, const uint8_t *end, 204 const uint8_t *begin, const uint8_t *end,
192 uint32_t validation_info, void *user_data_ptr) { 205 uint32_t validation_info, void *user_data_ptr) {
193 UNREFERENCED_PARAMETER(begin); 206 UNREFERENCED_PARAMETER(begin);
194 UNREFERENCED_PARAMETER(end); 207 UNREFERENCED_PARAMETER(end);
195 UNREFERENCED_PARAMETER(validation_info); 208 UserData &user_data = *reinterpret_cast<UserData *>(user_data_ptr);
196 UNREFERENCED_PARAMETER(user_data_ptr); 209
197 return FALSE; 210 // We do the same thing as in ProcessInstruction(): If we are not disabling
211 // non-temporals, they should pass validation, and the corresponding
212 // validation_info bit is simply cleared.
213 if (user_data.flags != DISABLE_NONTEMPORALS)
214 validation_info &= ~UNSUPPORTED_INSTRUCTION;
215
216 Bool result = (validation_info & (VALIDATION_ERRORS_MASK | BAD_JUMP_TARGET))
217 ? FALSE
218 : TRUE;
219 return result;
198 } 220 }
199 221
200 222
201 typedef Bool ValidateChunkFunc( 223 typedef Bool ValidateChunkFunc(
202 const uint8_t *data, size_t size, 224 const uint8_t *data, size_t size,
203 uint32_t options, 225 uint32_t options,
204 const NaClCPUFeaturesX86 *cpu_features, 226 const NaClCPUFeaturesX86 *cpu_features,
205 ValidationCallbackFunc user_callback, 227 ValidationCallbackFunc user_callback,
206 void *callback_data); 228 void *callback_data);
207 229
208 230
209 bool ValidateX86( 231 bool ValidateX86(
210 const Segment &segment, 232 const Segment &segment,
211 ValidateChunkFunc validate_chunk, 233 ValidateChunkFunc validate_chunk,
212 vector<Error> *errors) { 234 vector<Error> *errors,
235 uint32_t flags) {
213 236
214 errors->clear(); 237 errors->clear();
215 238
216 if (segment.vaddr % kBundleSize != 0) { 239 if (segment.vaddr % kBundleSize != 0) {
217 errors->push_back(Error( 240 errors->push_back(Error(
218 segment.vaddr, 241 segment.vaddr,
219 "Text segment offset in memory is not bundle-aligned.")); 242 "Text segment offset in memory is not bundle-aligned."));
220 return false; 243 return false;
221 } 244 }
222 245
223 if (segment.size % kBundleSize != 0) { 246 if (segment.size % kBundleSize != 0) {
224 char buf[100]; 247 char buf[100];
225 SNPRINTF(buf, sizeof buf, 248 SNPRINTF(buf, sizeof buf,
226 "Text segment size (0x%" NACL_PRIx32 ") is not " 249 "Text segment size (0x%" NACL_PRIx32 ") is not "
227 "multiple of bundle size.", 250 "multiple of bundle size.",
228 segment.size); 251 segment.size);
229 errors->push_back(Error(segment.vaddr + segment.size, buf)); 252 errors->push_back(Error(segment.vaddr + segment.size, buf));
230 return false; 253 return false;
231 } 254 }
232 255
233 vector<Jump> jumps; 256 vector<Jump> jumps;
234 set<uint32_t> bad_jump_targets; 257 set<uint32_t> bad_jump_targets;
235 258
236 UserData user_data(segment, errors, &jumps, &bad_jump_targets); 259 UserData user_data(segment, errors, &jumps, &bad_jump_targets, flags);
237 260
238 // TODO(shcherbina): customize from command line 261 // TODO(shcherbina): customize from command line
239 262
240 // We collect all errors except bad jump targets, and we separately 263 // We collect all errors except bad jump targets, and we separately
241 // memoize all direct jumps (or calls) and bad jump targets. 264 // memoize all direct jumps (or calls) and bad jump targets.
242 Bool result = validate_chunk( 265 Bool result = validate_chunk(
243 segment.data, segment.size, 266 segment.data, segment.size,
244 CALL_USER_CALLBACK_ON_EACH_INSTRUCTION, &kFullCPUIDFeatures, 267 CALL_USER_CALLBACK_ON_EACH_INSTRUCTION, &kFullCPUIDFeatures,
245 ProcessInstruction, &user_data); 268 ProcessInstruction, &user_data);
246 269
247 // Report destinations of jumps that lead to bad targets. 270 // Report destinations of jumps that lead to bad targets.
248 for (size_t i = 0; i < jumps.size(); i++) { 271 for (size_t i = 0; i < jumps.size(); i++) {
249 const Jump &jump = jumps[i]; 272 const Jump &jump = jumps[i];
250 if (bad_jump_targets.count(jump.to) > 0) 273 if (bad_jump_targets.count(jump.to) > 0)
251 errors->push_back(Error(jump.from, "bad jump target")); 274 errors->push_back(Error(jump.from, "bad jump target"));
252 } 275 }
253 276
254 // Run validator as it is run in loader, without callback on each instruction, 277 // Run validator as it is run in loader, without callback on each instruction,
255 // and ensure that results match. If ncval is guaranteed to return the same 278 // and ensure that results match. If ncval is guaranteed to return the same
256 // result as actual validator, it can be reliably used as validator wrapper 279 // result as actual validator, it can be reliably used as validator wrapper
257 // for testing. 280 // for testing.
258 CHECK(result == validate_chunk( 281 CHECK(result == validate_chunk(
259 segment.data, segment.size, 282 segment.data, segment.size,
260 0, &kFullCPUIDFeatures, 283 0, &kFullCPUIDFeatures,
261 ProcessError, NULL)); 284 ProcessError, &user_data));
262 285
263 return static_cast<bool>(result); 286 return static_cast<bool>(result);
264 } 287 }
265 288
266 289
267 class NcvalArmProblemReporter : public ProblemReporter { 290 class NcvalArmProblemReporter : public ProblemReporter {
268 public: 291 public:
269 explicit NcvalArmProblemReporter(vector<Error> *errors) : errors(errors) {} 292 explicit NcvalArmProblemReporter(vector<Error> *errors) : errors(errors) {}
270 293
271 protected: 294 protected:
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 nacl_arm_dec::RegisterList(nacl_arm_dec::Register::Sp()), 335 nacl_arm_dec::RegisterList(nacl_arm_dec::Register::Sp()),
313 &cpu_features); 336 &cpu_features);
314 337
315 NcvalArmProblemReporter reporter(errors); 338 NcvalArmProblemReporter reporter(errors);
316 return validator.validate(segments, &reporter); 339 return validator.validate(segments, &reporter);
317 } 340 }
318 341
319 342
320 void Usage() { 343 void Usage() {
321 fprintf(stderr, "Usage:\n"); 344 fprintf(stderr, "Usage:\n");
322 fprintf(stderr, " ncval [-v] <ELF file>\n"); 345 fprintf(stderr, " ncval [-vd] <ELF file>\n");
323 } 346 }
324 347
325 348
326 struct Options { 349 struct Options {
327 Options() : input_file(NULL), verbose(false) {} 350 Options() : input_file(NULL), verbose(false), flags(0) {}
328 const char *input_file; 351 const char *input_file;
329 bool verbose; 352 bool verbose;
353 uint32_t flags;
330 }; 354 };
331 355
332 356
333 void ParseOptions(int argc, char **argv, Options *options) { 357 void ParseOptions(int argc, char **argv, Options *options) {
334 int opt; 358 int opt;
335 while ((opt = getopt(argc, argv, "v")) != -1) { 359 while ((opt = getopt(argc, argv, "vd")) != -1) {
336 switch (opt) { 360 switch (opt) {
337 case 'v': 361 case 'v':
338 options->verbose = true; 362 options->verbose = true;
339 break; 363 break;
364 case 'd':
365 options->flags = DISABLE_NONTEMPORALS;
366 break;
340 default: 367 default:
341 fprintf(stderr, "ERROR: unknown option: [%c]\n\n", opt); 368 fprintf(stderr, "ERROR: unknown option: [%c]\n\n", opt);
342 Usage(); 369 Usage();
343 exit(-1); 370 exit(-1);
344 } 371 }
345 } 372 }
346 373
347 if (argc - optind != 1) { 374 if (argc - optind != 1) {
348 fprintf(stderr, "ERROR: too many arguments provided\n\n"); 375 fprintf(stderr, "ERROR: too many arguments provided\n\n");
349 Usage(); 376 Usage();
(...skipping 11 matching lines...) Expand all
361 elf_load::Image image; 388 elf_load::Image image;
362 elf_load::ReadImage(options.input_file, &image); 389 elf_load::ReadImage(options.input_file, &image);
363 390
364 elf_load::Architecture architecture = elf_load::GetElfArch(image); 391 elf_load::Architecture architecture = elf_load::GetElfArch(image);
365 Segment segment = elf_load::GetElfTextSegment(image); 392 Segment segment = elf_load::GetElfTextSegment(image);
366 393
367 vector<Error> errors; 394 vector<Error> errors;
368 bool result = false; 395 bool result = false;
369 switch (architecture) { 396 switch (architecture) {
370 case elf_load::X86_32: 397 case elf_load::X86_32:
371 result = ValidateX86(segment, ValidateChunkIA32, &errors); 398 result = ValidateX86(segment, ValidateChunkIA32, &errors,
399 options.flags);
372 break; 400 break;
373 case elf_load::X86_64: 401 case elf_load::X86_64:
374 result = ValidateX86(segment, ValidateChunkAMD64, &errors); 402 result = ValidateX86(segment, ValidateChunkAMD64, &errors,
403 options.flags);
375 break; 404 break;
376 case elf_load::ARM: 405 case elf_load::ARM:
377 result = ValidateArm(segment, &errors); 406 result = ValidateArm(segment, &errors);
378 break; 407 break;
379 default: 408 default:
380 CHECK(false); 409 CHECK(false);
381 } 410 }
382 411
383 for (size_t i = 0; i < errors.size(); i++) { 412 for (size_t i = 0; i < errors.size(); i++) {
384 const Error &e = errors[i]; 413 const Error &e = errors[i];
385 fprintf(stderr, "%8" NACL_PRIx32 ": %s\n", e.offset, e.message.c_str()); 414 fprintf(stderr, "%8" NACL_PRIx32 ": %s\n", e.offset, e.message.c_str());
386 } 415 }
387 416
388 if (!result) { 417 if (!result) {
389 fprintf(stderr, "Invalid.\n"); 418 fprintf(stderr, "Invalid.\n");
390 return 1; 419 return 1;
391 } 420 }
392 421
393 if (options.verbose) { 422 if (options.verbose) {
394 fprintf(stderr, "Valid.\n"); 423 fprintf(stderr, "Valid.\n");
395 } 424 }
396 return 0; 425 return 0;
397 } 426 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698