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 : * ncval.c - command line validator for NaCl.
9 : * Mostly for testing.
10 : */
11 :
12 :
13 : #ifndef NACL_TRUSTED_BUT_NOT_TCB
14 : #error("This file is not meant for use in the TCB")
15 : #endif
16 :
17 : #include "native_client/src/include/portability.h"
18 :
19 : #include <stdio.h>
20 : #include <stdlib.h>
21 : #include <stdarg.h>
22 : #include <string.h>
23 : #include <errno.h>
24 : #include <sys/timeb.h>
25 : #include <time.h>
26 : #include "native_client/src/include/nacl_macros.h"
27 : #include "native_client/src/shared/gio/gio.h"
28 : #include "native_client/src/shared/platform/nacl_log.h"
29 : #include "native_client/src/shared/utils/flags.h"
30 : #include "native_client/src/trusted/validator/ncfileutil.h"
31 : #include "native_client/src/trusted/validator/x86/nacl_cpuid.h"
32 : #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter.h"
33 : #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter_internal.h"
34 : #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter_detailed.h"
35 : #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_jumps.h"
36 : #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_opcode_histogram.h"
37 : #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_memory_protect.h"
38 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode.h"
39 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode_verbose.h"
40 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate.h"
41 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate_detailed.h"
42 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate_internaltypes.h"
43 : #include "native_client/src/trusted/validator_x86/nc_read_segment.h"
44 : #include "native_client/src/trusted/validator_x86/ncdis_segments.h"
45 :
46 : #if NACL_TARGET_SUBARCH == 64
47 : #include "native_client/src/trusted/validator/x86/decoder/nc_decode_tables.h"
48 : #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncval_decode_tables.h"
49 : #include "native_client/src/trusted/validator_x86/ncdis_decode_tables.h"
50 : #endif
51 :
52 : /* To turn on debugging of instruction decoding, change value of
53 : * DEBUGGING to 1.
54 : */
55 : #define DEBUGGING 0
56 :
57 : #include "native_client/src/shared/utils/debugging.h"
58 :
59 : /* When true, ncval will override the default reporter with the
60 : * appropriate verbose reporter.
61 : */
62 : static Bool override_reporter =
63 : #if DEBUGGING || !defined(NCVAL_TESTING)
64 : TRUE
65 : #else
66 : FALSE
67 : #endif
68 : ;
69 :
70 : /* Forward declarations. */
71 : static void usage(int exit_code);
72 :
73 : #if NACL_TARGET_SUBARCH == 32
74 : /* Flag defining if statistics should be printed for callback validator
75 : * model.
76 : */
77 : static Bool NACL_FLAGS_stats_print = FALSE;
78 : #endif
79 :
80 : /* Flag defining if detailed error messages should be generated. When
81 : * false, runs performance model as used by sel_ldr.
82 : */
83 : static Bool NACL_FLAGS_detailed_errors = TRUE;
84 :
85 : /* Flag defining the name of a hex text to be used as the code segment.
86 : */
87 : static char *NACL_FLAGS_hex_text = "";
88 :
89 : /* Define if we should process segments (rather than sections) when applying SFI
90 : * validator.
91 : */
92 : static Bool NACL_FLAGS_analyze_segments = FALSE;
93 :
94 : /* Define how many times we will analyze the code segment.
95 : * Note: Values, other than 1, is only used for profiling.
96 : */
97 : static int NACL_FLAGS_validate_attempts = 1;
98 :
99 : /* Define the set of CPU features to use while validating. */
100 : static NaClCPUFeaturesX86 ncval_cpu_features;
101 :
102 : /* Define whether timing should be applied when running the validator. */
103 : static Bool NACL_FLAGS_print_timing = FALSE;
104 :
105 : /* Define the block alignment size to use. */
106 : static int NACL_FLAGS_block_alignment = 32;
107 :
108 : /* Define what level of errors will be printed.
109 : * Note: If multiple flags are true, the one with
110 : * the highest severity will be selected.
111 : */
112 : static Bool NACL_FLAGS_warnings = FALSE;
113 : static Bool NACL_FLAGS_errors = FALSE;
114 : static Bool NACL_FLAGS_fatal = FALSE;
115 :
116 : /* Define if special stubout tests should be run. Such
117 : * tests apply stubout, and then print out the modified
118 : * disassembled code.
119 : */
120 : static Bool NACL_FLAGS_stubout_memory = FALSE;
121 :
122 : #if NACL_TARGET_SUBARCH == 64
123 : /* Flag that allows validator decoder to be used in place of full decoder.
124 : */
125 : static Bool NACL_FLAGS_validator_decoder = FALSE;
126 : #endif
127 :
128 : /* Generates NaClErrorMapping for error level suffix. */
129 : #define NaClError(s) { #s , LOG_## s}
130 :
131 : /**************************************************
132 : * Driver to apply the validator to a code segment
133 : *************************************************/
134 :
135 : /* Reports if named module is safe. */
136 74 : static void NaClReportFileSafety(Bool success, const char *fname) {
137 74 : if (NACL_FLAGS_stubout_memory) {
138 : /* The validator has been run to test stubbing out. Stubbing out,
139 : * in this tool, means replacing instructions (modeled using hex
140 : * text) that are unsafe and rejected by the validator, and are
141 : * replaced with HALT instructions.
142 : */
143 0 : NaClLog(LOG_INFO, "STUBBED OUT as follows:\n");
144 : } else {
145 : #ifndef NCVAL_TESTING
146 74 : if (success) {
147 32 : NaClLog(LOG_INFO, "*** %s is safe ***\n", fname);
148 : } else {
149 42 : NaClLog(LOG_INFO, "*** %s IS UNSAFE ***\n", fname);
150 : }
151 : #endif
152 : }
153 74 : }
154 :
155 : /* Reports if module is safe. */
156 : static void NaClReportSafety(Bool success,
157 74 : const char* filename) {
158 74 : if (0 != strcmp(NACL_FLAGS_hex_text, "")) {
159 : /* Special hex text processing, rather than filename. */
160 62 : if (0 == strcmp(NACL_FLAGS_hex_text, "-")) {
161 62 : NaClReportFileSafety(success, "<input>");
162 62 : return;
163 : }
164 : }
165 12 : NaClReportFileSafety(success, filename);
166 : }
167 :
168 : /* The model of data to be passed to the load/analyze steps. */
169 : typedef void* NaClRunValidatorData;
170 :
171 : /* The routine that loads the code segment(s) into memory (within
172 : * the data arg). Returns true iff load was successful.
173 : */
174 : typedef Bool (*NaClValidateLoad)(int argc, const char* argv[],
175 : NaClRunValidatorData data);
176 :
177 : /* The actual validation analysis, applied to the data returned by
178 : * ValidateLoad. Assume that this function also deallocates any memory
179 : * in loaded_data. Returns true iff analysis doesn't find any problems.
180 : */
181 : typedef Bool (*NaClValidateAnalyze)(NaClRunValidatorData data);
182 :
183 : /* Runs the validator using the given (command line) arguments.
184 : *
185 : * Parameters:
186 : * data - The model of data to be passed to the load/analyze steps.
187 : * Allows top-level call to pass control information
188 : * to the load and analyze functions, and between these
189 : * two functions.
190 : * load - The function to load in the data needed to validate.
191 : * analyze - The function to call to do validator analysis once
192 : * the data has been read in.
193 : */
194 : static Bool NaClRunValidator(int argc, const char* argv[],
195 : NaClRunValidatorData data,
196 : NaClValidateLoad load,
197 68 : NaClValidateAnalyze analyze) {
198 : clock_t clock_0;
199 : clock_t clock_l;
200 : clock_t clock_v;
201 : Bool return_value;
202 :
203 68 : clock_0 = clock();
204 68 : return_value = load(argc, argv, data);
205 68 : if (!return_value) {
206 0 : NaClValidatorMessage(LOG_ERROR, NULL, "Unable to load code to validate\n");
207 0 : return FALSE;
208 : }
209 68 : clock_l = clock();
210 68 : return_value = analyze(data);
211 68 : clock_v = clock();
212 :
213 68 : if (NACL_FLAGS_print_timing) {
214 3 : NaClValidatorMessage(
215 : LOG_INFO, NULL,
216 : "load time: %0.6f analysis time: %0.6f\n",
217 : (double)(clock_l - clock_0) / (double)CLOCKS_PER_SEC,
218 : (double)(clock_v - clock_l) / (double)CLOCKS_PER_SEC);
219 : }
220 68 : return return_value;
221 : }
222 :
223 : /* Default loader that does nothing. Typically this is because
224 : * the data argument already contains the bytes to validate.
225 : */
226 : Bool NaClValidateNoLoad(int argc, const char* argv[],
227 62 : NaClRunValidatorData data) {
228 62 : return TRUE;
229 : }
230 :
231 : /* Local file data for validator run. */
232 : typedef struct ValidateData {
233 : /* The name of the elf file to validate. */
234 : const char *fname;
235 : /* The elf file to validate. */
236 : ncfile *ncf;
237 : } ValidateData;
238 :
239 : /* Load the elf file and return the loaded elf file. */
240 : static Bool ValidateElfLoad(int argc, const char *argv[],
241 6 : ValidateData *data) {
242 6 : if (argc != 2) {
243 0 : NaClLog(LOG_ERROR, "expected: %s file\n", argv[0]);
244 0 : usage(2);
245 : }
246 6 : data->fname = argv[1];
247 :
248 : /* TODO(karl): Once we fix elf values put in by compiler, so that
249 : * we no longer get load errors from ncfilutil.c, find a way to
250 : * terminate early if errors occur during loading.
251 : */
252 6 : data->ncf = nc_loadfile(data->fname);
253 6 : if (data->ncf == NULL) {
254 0 : NaClLog(LOG_ERROR, "nc_loadfile(%s): %s\n", data->fname, strerror(errno));
255 0 : usage(2);
256 : }
257 6 : return NULL != data->ncf;
258 : }
259 :
260 : /***************************************************
261 : * Code to run SFI validator on hex text examples. *
262 : ***************************************************/
263 :
264 : /* Defines the maximum number of characters allowed on an input line
265 : * of the input text defined by the commands command line option.
266 : */
267 : #define NACL_MAX_INPUT_LINE 4096
268 :
269 : typedef struct NaClValidatorByteArray {
270 : uint8_t bytes[NACL_MAX_INPUT_LINE];
271 : NaClPcAddress base;
272 : NaClMemorySize num_bytes;
273 : } NaClValidatorByteArray;
274 :
275 : static void HexFatal(const char *format, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2);
276 :
277 : /* Print out given error message about the hex input file, and then exit. */
278 0 : static void HexFatal(const char *format, ...) {
279 : va_list ap;
280 0 : va_start(ap, format);
281 0 : NaClLogV(LOG_ERROR, format, ap);
282 0 : va_end(ap);
283 : /* always succed, so that the testing framework works. */
284 0 : exit(0);
285 : }
286 :
287 : /* Load the hex input file from the given command line arguments,
288 : * and put it into the given data structure.
289 : */
290 : static int ValidateHexLoad(int argc, const char *argv[],
291 62 : NaClValidatorByteArray *data) {
292 62 : if (argc != 1) {
293 0 : HexFatal("expected: %s <options>\n", argv[0]);
294 : }
295 62 : if (0 == strcmp(NACL_FLAGS_hex_text, "-")) {
296 62 : data->num_bytes = (NaClMemorySize)
297 : NaClReadHexTextWithPc(stdin, &data->base, data->bytes,
298 : NACL_MAX_INPUT_LINE);
299 : } else {
300 0 : FILE *input = fopen(NACL_FLAGS_hex_text, "r");
301 0 : if (NULL == input) {
302 0 : HexFatal("Can't open hex text file: %s\n", NACL_FLAGS_hex_text);
303 : }
304 0 : data->num_bytes = (NaClMemorySize)
305 : NaClReadHexTextWithPc(input, &data->base, data->bytes,
306 : NACL_MAX_INPUT_LINE);
307 0 : fclose(input);
308 0 : --argc;
309 : }
310 62 : return argc;
311 : }
312 :
313 : #if NACL_TARGET_SUBARCH == 32
314 : /***************************************
315 : * Code to run segment based validator.*
316 : ***************************************/
317 :
318 6 : int AnalyzeSegmentSections(ncfile *ncf, struct NCValidatorState *vstate) {
319 6 : int badsections = 0;
320 : int ii;
321 6 : const Elf_Phdr *phdr = ncf->pheaders;
322 :
323 30 : for (ii = 0; ii < ncf->phnum; ii++) {
324 24 : NaClLog(LOG_INFO,
325 : "segment[%d] p_type %"NACL_PRIdElf_Word
326 : " p_offset %"NACL_PRIxElf_Off" vaddr %"NACL_PRIxElf_Addr
327 : " paddr %"NACL_PRIxElf_Addr" align %"NACL_PRIuElf_Xword"\n",
328 : ii, phdr[ii].p_type, phdr[ii].p_offset,
329 : phdr[ii].p_vaddr, phdr[ii].p_paddr,
330 : phdr[ii].p_align);
331 :
332 24 : NaClLog(LOG_INFO,
333 : " filesz %"NACL_PRIxElf_Xword" memsz %"NACL_PRIxElf_Xword
334 : " flags %"NACL_PRIxElf_Word"\n",
335 : phdr[ii].p_filesz, phdr[ii].p_memsz, phdr[ii].p_flags);
336 24 : if ((PT_LOAD != phdr[ii].p_type) ||
337 : (0 == (phdr[ii].p_flags & PF_X)))
338 : continue;
339 6 : NaClLog(LOG_INFO, "parsing segment %d\n", ii);
340 6 : NCValidateSegment(ncf->data + (phdr[ii].p_vaddr - ncf->vbase),
341 : phdr[ii].p_vaddr, phdr[ii].p_memsz, vstate);
342 : }
343 6 : return -badsections;
344 : }
345 :
346 : /* Initialize segment validator, using detailed (summary) error
347 : * messages if selected.
348 : */
349 : struct NCValidatorState* NCValInit(const NaClPcAddress vbase,
350 : const NaClMemorySize codesize,
351 68 : const uint8_t alignment) {
352 68 : return NACL_FLAGS_detailed_errors
353 : ? NCValidateInitDetailed(vbase, codesize, alignment, &ncval_cpu_features)
354 : : NCValidateInit(vbase, codesize, alignment, &ncval_cpu_features);
355 : }
356 :
357 :
358 6 : static Bool AnalyzeSegmentCodeSegments(ncfile *ncf, const char *fname) {
359 : NaClPcAddress vbase, vlimit;
360 : struct NCValidatorState *vstate;
361 : Bool result;
362 :
363 6 : GetVBaseAndLimit(ncf, &vbase, &vlimit);
364 6 : vstate = NCValInit(vbase, vlimit - vbase, ncf->ncalign);
365 6 : if (vstate == NULL) return FALSE;
366 6 : if (override_reporter) {
367 6 : NCValidateSetErrorReporter(vstate, &kNCVerboseErrorReporter);
368 : }
369 6 : if (AnalyzeSegmentSections(ncf, vstate) < 0) {
370 0 : NaClLog(LOG_INFO, "%s: text validate failed\n", fname);
371 : }
372 6 : result = (0 == NCValidateFinish(vstate)) ? TRUE : FALSE;
373 6 : NaClReportSafety(result, fname);
374 6 : if (NACL_FLAGS_stats_print) NCStatsPrint(vstate);
375 6 : NCValidateFreeState(&vstate);
376 6 : NaClLog(LOG_INFO, "Validated %s\n", fname);
377 6 : return result;
378 : }
379 : #endif
380 :
381 : #if NACL_TARGET_SUBARCH == 64
382 : /******************************
383 : * Code to run SFI validator. *
384 : ******************************/
385 :
386 : /* Define what should be used as the base register for
387 : * memory accesses.
388 : */
389 : static NaClOpKind nacl_base_register =
390 : (64 == NACL_TARGET_SUBARCH ? RegR15 : RegUnknown);
391 :
392 : /* Create validator state using detailed (summary) error messages
393 : * if selected.
394 : */
395 : struct NaClValidatorState* NaClValStateCreate(
396 : const NaClPcAddress vbase,
397 : const NaClMemorySize sz,
398 : const uint8_t alignment,
399 : const NaClOpKind base_register) {
400 : return
401 : NACL_FLAGS_detailed_errors
402 : ? NaClValidatorStateCreateDetailed(vbase, sz, alignment, base_register,
403 : &ncval_cpu_features)
404 : : NaClValidatorStateCreate(vbase, sz, alignment, base_register,
405 : &ncval_cpu_features);
406 : }
407 :
408 : /* Returns the decoder tables to use. */
409 : static const NaClDecodeTables* NaClGetDecoderTables() {
410 : return NACL_FLAGS_validator_decoder
411 : ? kNaClValDecoderTables
412 : : kNaClDecoderTables;
413 : }
414 :
415 : /* Analyze each section in the given elf file, using the given validator
416 : * state.
417 : */
418 : static void AnalyzeSfiSections(ncfile *ncf, struct NaClValidatorState *vstate) {
419 : int ii;
420 : const Elf_Phdr *phdr = ncf->pheaders;
421 :
422 : for (ii = 0; ii < ncf->phnum; ii++) {
423 : /* TODO(karl) fix types for this? */
424 : NaClValidatorMessage(
425 : LOG_INFO, vstate,
426 : "segment[%d] p_type %d p_offset %"NACL_PRIxElf_Off
427 : " vaddr %"NACL_PRIxElf_Addr
428 : " paddr %"NACL_PRIxElf_Addr
429 : " align %"NACL_PRIuElf_Xword"\n",
430 : ii, phdr[ii].p_type, phdr[ii].p_offset,
431 : phdr[ii].p_vaddr, phdr[ii].p_paddr,
432 : phdr[ii].p_align);
433 : NaClValidatorMessage(
434 : LOG_INFO, vstate,
435 : " filesz %"NACL_PRIxElf_Xword
436 : " memsz %"NACL_PRIxElf_Xword
437 : " flags %"NACL_PRIxElf_Word"\n",
438 : phdr[ii].p_filesz, phdr[ii].p_memsz,
439 : phdr[ii].p_flags);
440 : if ((PT_LOAD != phdr[ii].p_type) ||
441 : (0 == (phdr[ii].p_flags & PF_X)))
442 : continue;
443 : NaClValidatorMessage(LOG_INFO, vstate, "parsing segment %d\n", ii);
444 : NaClValidateSegmentUsingTables(ncf->data + (phdr[ii].p_vaddr - ncf->vbase),
445 : phdr[ii].p_vaddr, phdr[ii].p_memsz, vstate,
446 : NaClGetDecoderTables());
447 : }
448 : }
449 :
450 : static void AnalyzeSfiSegments(ncfile *ncf, NaClValidatorState *state) {
451 : int ii;
452 : const Elf_Shdr *shdr = ncf->sheaders;
453 :
454 : for (ii = 0; ii < ncf->shnum; ii++) {
455 : NaClValidatorMessage(
456 : LOG_INFO, state,
457 : "section %d sh_addr %"NACL_PRIxElf_Addr" offset %"NACL_PRIxElf_Off
458 : " flags %"NACL_PRIxElf_Xword"\n",
459 : ii, shdr[ii].sh_addr, shdr[ii].sh_offset, shdr[ii].sh_flags);
460 : if ((shdr[ii].sh_flags & SHF_EXECINSTR) != SHF_EXECINSTR)
461 : continue;
462 : NaClValidatorMessage(LOG_INFO, state, "parsing section %d\n", ii);
463 : NaClValidateSegmentUsingTables(ncf->data + (shdr[ii].sh_addr - ncf->vbase),
464 : shdr[ii].sh_addr, shdr[ii].sh_size, state,
465 : NaClGetDecoderTables());
466 : }
467 : }
468 :
469 : /* Analyze each code segment in the given elf file, stored in the
470 : * file with the given path fname.
471 : */
472 : static Bool AnalyzeSfiCodeSegments(ncfile *ncf, const char *fname) {
473 : /* TODO(karl) convert these to be PcAddress and MemorySize */
474 : NaClPcAddress vbase, vlimit;
475 : NaClValidatorState *vstate;
476 : Bool return_value = TRUE;
477 :
478 : GetVBaseAndLimit(ncf, &vbase, &vlimit);
479 : vstate = NaClValStateCreate(vbase, vlimit - vbase,
480 : ncf->ncalign, nacl_base_register);
481 : if (vstate == NULL) {
482 : NaClValidatorMessage(LOG_ERROR, vstate, "Unable to create validator state");
483 : return FALSE;
484 : }
485 : if (override_reporter) {
486 : NaClValidatorStateSetErrorReporter(vstate, &kNaClVerboseErrorReporter);
487 : }
488 : if (NACL_FLAGS_analyze_segments) {
489 : AnalyzeSfiSegments(ncf, vstate);
490 : } else {
491 : AnalyzeSfiSections(ncf, vstate);
492 : }
493 : return_value = NaClValidatesOk(vstate);
494 : NaClReportSafety(return_value, fname);
495 : NaClValidatorStateDestroy(vstate);
496 : return return_value;
497 : }
498 : #endif
499 :
500 : /***************************
501 : * Top-level driver code. *
502 : **************************/
503 :
504 : /* Analyze the code segments of the elf file in the validator date. */
505 6 : static Bool ValidateAnalyze(ValidateData *data) {
506 : int i;
507 6 : Bool results = TRUE;
508 12 : for (i = 0; i < NACL_FLAGS_validate_attempts; ++i) {
509 : Bool return_value =
510 : #if NACL_TARGET_SUBARCH == 64
511 : AnalyzeSfiCodeSegments(data->ncf, data->fname);
512 : #else
513 6 : AnalyzeSegmentCodeSegments(data->ncf, data->fname);
514 : #endif
515 6 : if (!return_value) {
516 2 : results = FALSE;
517 : }
518 : }
519 6 : nc_freefile(data->ncf);
520 6 : return results;
521 : }
522 :
523 : /* Define a sequence of bytes to validate whose virtual address begins at the
524 : * given base.
525 : */
526 : typedef struct NaClValidateBytes {
527 : /* The sequence of bytes to validate. */
528 : uint8_t* bytes;
529 : /* The number of bytes in the sequence. */
530 : NaClMemorySize num_bytes;
531 : /* The virtual base adddress associated with the first byte in the
532 : * sequence.
533 : */
534 : NaClPcAddress base;
535 : } NaClValidateBytes;
536 :
537 : /* Apply the validator to the sequence of bytes in the given data. */
538 62 : static Bool NaClValidateAnalyzeBytes(NaClValidateBytes* data) {
539 62 : Bool return_value = FALSE;
540 : #if NACL_TARGET_SUBARCH == 64
541 : NaClValidatorState* state;
542 : state = NaClValStateCreate(data->base,
543 : data->num_bytes,
544 : (uint8_t) NACL_FLAGS_block_alignment,
545 : nacl_base_register);
546 : if (NULL == state) {
547 : NaClValidatorMessage(LOG_ERROR, NULL, "Unable to create validator state");
548 : return FALSE;
549 : }
550 : if (NACL_FLAGS_stubout_memory) {
551 : NaClValidatorStateSetDoStubOut(state, TRUE);
552 : }
553 : if (override_reporter) {
554 : NaClValidatorStateSetErrorReporter(state, &kNaClVerboseErrorReporter);
555 : }
556 : NaClValidateSegmentUsingTables(data->bytes, data->base, data->num_bytes,
557 : state, NaClGetDecoderTables());
558 : return_value = NaClValidatesOk(state);
559 : if (state->did_stub_out) {
560 : /* Used for golden file testing. */
561 : printf("Some instructions were replaced with HLTs.\n");
562 : }
563 : NaClValidatorStateDestroy(state);
564 : NaClReportSafety(return_value, "");
565 : #else
566 : struct NCValidatorState *vstate;
567 62 : vstate = NCValInit(data->base, data->num_bytes,
568 : (uint8_t) NACL_FLAGS_block_alignment);
569 62 : if (vstate == NULL) {
570 0 : printf("Unable to create validator state, quitting!\n");
571 : } else {
572 62 : if (NACL_FLAGS_stubout_memory) {
573 0 : NCValidateSetStubOutMode(vstate, 1);
574 : }
575 62 : if (override_reporter) {
576 62 : NCValidateSetErrorReporter(vstate, &kNCVerboseErrorReporter);
577 : }
578 62 : NCValidateSegment(&data->bytes[0], data->base, data->num_bytes, vstate);
579 62 : return_value = (0 == NCValidateFinish(vstate)) ? TRUE : FALSE;
580 62 : if (vstate->stats.didstubout) {
581 : /* Used for golden file testing. */
582 1 : printf("Some instructions were replaced with HLTs.\n");
583 : }
584 62 : NaClReportSafety(return_value, "");
585 62 : if (NACL_FLAGS_stats_print) NCStatsPrint(vstate);
586 62 : NCValidateFreeState(&vstate);
587 : }
588 : #endif
589 62 : return return_value;
590 : }
591 :
592 : /* Given the command line arguments in argc/argv, and the sequence of bytes
593 : * in the given data, apply the validator to the given bytes.
594 : */
595 : Bool NaClRunValidatorBytes(int argc,
596 : const char* argv[],
597 : uint8_t* bytes,
598 : NaClMemorySize num_bytes,
599 62 : NaClPcAddress base) {
600 : NaClValidateBytes data;
601 : int i;
602 62 : Bool results = TRUE;
603 62 : data.bytes = bytes;
604 62 : data.num_bytes = num_bytes;
605 62 : data.base = base;
606 124 : for (i = 0; i < NACL_FLAGS_validate_attempts; ++i) {
607 62 : if (!NaClRunValidator(argc, argv, &data,
608 : (NaClValidateLoad) NaClValidateNoLoad,
609 : (NaClValidateAnalyze) NaClValidateAnalyzeBytes)) {
610 38 : results = FALSE;
611 : }
612 : }
613 62 : return results;
614 : }
615 :
616 :
617 : static const char usage_str[] =
618 : "usage: ncval [options] file\n"
619 : "\n"
620 : "\tValidates an x86-%d nexe file.\n"
621 : "\n"
622 : "Options are:\n"
623 : "\n"
624 : "--alignment=N\n"
625 : "\tSet block alignment to N bytes (only 16 or 32 allowed).\n"
626 : "--annotate\n"
627 : "\tRun validator using annotations that will be understood\n"
628 : "\tby ncval_annotate.py.\n"
629 : "--attempts=N\n"
630 : "\tRun the validator on the nexe file (after loading) N times.\n"
631 : "\tNote: this flag should only be used for profiling.\n"
632 : "--CLFLUSH\n"
633 : "\tModel a CPU that supports the clflush instruction.\n"
634 : "--CMOV\n"
635 : "\tModel a CPU that supports the cmov instructions.\n"
636 : #ifdef NCVAL_TESTING
637 : "--conds\n"
638 : "\tPrint out pre/post conditions associated with each instruction.\n"
639 : #endif
640 : "--cpuid-all\n"
641 : "\tModel a CPU that supports all available features.\n"
642 : "--cpuid-none\n"
643 : "\tModel a CPU that supports no avaliable features.\n"
644 : "--CX8\n"
645 : "\tModel a CPU that supports the cmpxchg8b instruction.\n"
646 : "--detailed\n"
647 : "\tPrint out detailed error messages, rather than use performant\n"
648 : "\tcode used by sel_ldr\n"
649 : "--errors\n"
650 : "\tPrint out error and fatal error messages, but not\n"
651 : "\tinformative and warning messages\n"
652 : "--fatal\n"
653 : "\tOnly print out fatal error messages.\n"
654 : "--FXSR\n"
655 : "\tModel a CPU that supports the sfence instructions.\n"
656 : "--help\n"
657 : "\tPrint this message, and then exit.\n"
658 : "--hex_text=<file>\n"
659 : "\tRead text file of hex bytes, and use that\n"
660 : "\tas the definition of the code segment. Note: -hex_text=- will\n"
661 : "\tread from stdin instead of a file.\n"
662 : #if NACL_TARGET_SUBARCH == 64
663 : "--histogram\n"
664 : "\tPrint out a histogram of found opcodes.\n"
665 : "--identity_mask\n"
666 : "\tMask jumps using 0xFF instead of one matching\n"
667 : "\tthe block alignment.\n"
668 : #endif
669 : "--local_cpuid\n"
670 : "\tSet cpuid to values defined by local host this command is run on.\n"
671 : "--LZCNT\n"
672 : "\tModel a CPU that supports the lzcnt instruction.\n"
673 : #if NACL_TARGET_SUBARCH == 64
674 : "--max_errors=N\n"
675 : "\tPrint out at most N error messages. If N is zero,\n"
676 : "\tno messages are printed. If N is < 0, all messages are printed.\n"
677 : #endif
678 : "--MMX\n"
679 : "\tModel a CPU that supports MMX instructions.\n"
680 : "--MOVBE\n"
681 : "\tModel a CPU that supports the movbe instruction.\n"
682 : "--MSR\n"
683 : "\tModel a CPU that supports the rdmsr and wrmsr instructions.\n"
684 : "--POPCNT\n"
685 : "\tModel a CPU that supports the popcnt instruction.\n"
686 : #if NACL_TARGET_SUBARCH == 64
687 : "--readwrite_sfi\n"
688 : "\tCheck for memory read and write software fault isolation.\n"
689 : "--segments\n"
690 : "\tAnalyze code in segments in elf file, instead of headers.\n"
691 : #endif
692 : "--SSE\n"
693 : "\tModel a CPU that supports SSE instructions.\n"
694 : "--SSE2\n"
695 : "\tModel a CPU that supports SSE 2 instructions.\n"
696 : "--SSE3\n"
697 : "\tModel a CPU that supports SSE 3 instructions.\n"
698 : "--SSSE3\n"
699 : "\tModel a CPU that supports SSSE 3 instructions.\n"
700 : "--SSE41\n"
701 : "\tModel a CPU that supports SSE 4.1 instructions.\n"
702 : "--SSE42\n"
703 : "\tModel a CPU that supports SSE 4.2 instructions.\n"
704 : "--SSE4A\n"
705 : "\tModel a CPU that supports SSE 4A instructions.\n"
706 : #if NACL_TARGET_SUBARCH == 32
707 : "--stats\n"
708 : "\tPrint statistics collected by the validator.\n"
709 : #endif
710 : "--stubout\n"
711 : "\tRun using stubout mode, replacing bad instructions with halts.\n"
712 : "\tStubbed out disassembly will be printed after validator\n"
713 : "\terror messages. Note: Only applied if --hex_text option is\n"
714 : "\talso specified\n"
715 : "-t\n"
716 : "\tTime the validator and print out results.\n"
717 : "--TSC\n"
718 : "\tModel a CPU that supports the rdtsc instruction.\n"
719 : "--x87\n"
720 : "\tModel a CPU that supports x87 instructions.\n"
721 : #if NACL_TARGET_SUBARCH == 64
722 : "--validator_decoder\n"
723 : "\tUse validator (partial) decoder instead of full decoder.\n"
724 : #endif
725 : "--VMX\n"
726 : "\tModel a CPU that supports VMX instructions.\n"
727 : "--3DNOW\n"
728 : "\tModel a CPU that supports 3DNOW instructions.\n"
729 : "--E3DNOW\n"
730 : "\tModel a CPU that supports E3DNOW instructions.\n"
731 : "\n"
732 : "--SVM\n"
733 : "\tModel a the CPU supports SVM instrutions.\n"
734 : "--time\n"
735 : "\tTime the validator and print out results. Same as option -t.\n"
736 : #if NACL_TARGET_SUBARCH == 64
737 : "--trace_insts\n"
738 : "\tTurn on validator trace of instructions, as processed..\n"
739 : "--trace_verbose\n"
740 : "\tTurn on all trace validator messages. Note: this\n"
741 : "\tflag also implies --trace.\n"
742 : #endif
743 : "--warnings\n"
744 : "\tPrint out warnings, errors, and fatal errors, but not\n"
745 : "\tinformative messages.\n"
746 : #if NACL_TARGET_SUBARCH == 64
747 : "--write_sfi\n"
748 : "\tOnly check for memory write software fault isolation.\n"
749 : #endif
750 : "\n";
751 :
752 0 : static void usage(int exit_code) {
753 0 : printf(usage_str, NACL_TARGET_SUBARCH);
754 0 : exit(exit_code);
755 : }
756 :
757 : /* Checks if arg is one of the expected "Bool" flags, and if so, sets
758 : * the corresponding flag and returns true.
759 : */
760 359 : static Bool GrokABoolFlag(const char *arg) {
761 : /* A set of boolean flags to be checked */
762 : static struct {
763 : const char *flag_name;
764 : Bool *flag_ptr;
765 : } flags[] = {
766 : { "--segments" , &NACL_FLAGS_analyze_segments },
767 : #ifndef NCVAL_TESTING
768 : { "--detailed", &NACL_FLAGS_detailed_errors },
769 : #endif
770 : { "--stubout", &NACL_FLAGS_stubout_memory },
771 : #if NACL_TARGET_SUBARCH == 64
772 : { "--trace_insts", &NACL_FLAGS_validator_trace_instructions },
773 : #endif
774 : { "-t", &NACL_FLAGS_print_timing },
775 : #if NACL_TARGET_SUBARCH == 32
776 : { "--stats", &NACL_FLAGS_stats_print },
777 : #endif
778 : { "--annotate", &NACL_FLAGS_ncval_annotate },
779 : #if NACL_TARGET_SUBARCH == 64
780 : { "--histogram", &NACL_FLAGS_opcode_histogram },
781 : #endif
782 : { "--time" , &NACL_FLAGS_print_timing },
783 : #if NACL_TARGET_SUBARCH == 64
784 : { "--warnings", &NACL_FLAGS_warnings },
785 : { "--errors" , &NACL_FLAGS_errors },
786 : { "--fatal" , &NACL_FLAGS_fatal },
787 : { "--validator_decoder", &NACL_FLAGS_validator_decoder },
788 : #endif
789 : { "--identity_mask", &NACL_FLAGS_identity_mask },
790 : };
791 :
792 : /* A set of CPU features to check. */
793 : static struct {
794 : const char *feature_name;
795 : NaClCPUFeatureID feature;
796 : } features[] = {
797 : { "--x87" , NaClCPUFeature_x87 },
798 : { "--MMX" , NaClCPUFeature_MMX },
799 : { "--SSE" , NaClCPUFeature_SSE },
800 : { "--SSE2" , NaClCPUFeature_SSE2 },
801 : { "--SSE3" , NaClCPUFeature_SSE3 },
802 : { "--SSSE3" , NaClCPUFeature_SSSE3 },
803 : { "--SSE41" , NaClCPUFeature_SSE41 },
804 : { "--SSE42" , NaClCPUFeature_SSE42 },
805 : { "--MOVBE" , NaClCPUFeature_MOVBE },
806 : { "--POPCNT" , NaClCPUFeature_POPCNT },
807 : { "--CX8" , NaClCPUFeature_CX8 },
808 : { "--CX16" , NaClCPUFeature_CX16 },
809 : { "--CMOV" , NaClCPUFeature_CMOV },
810 : { "--MON" , NaClCPUFeature_MON },
811 : { "--FXSR" , NaClCPUFeature_FXSR },
812 : { "--CLFLUSH", NaClCPUFeature_CLFLUSH },
813 : { "--TSC" , NaClCPUFeature_TSC },
814 : { "--MSR" , NaClCPUFeature_MSR },
815 : { "--VME" , NaClCPUFeature_VME },
816 : { "--PSN" , NaClCPUFeature_PSN },
817 : { "--VMX" , NaClCPUFeature_VMX },
818 : { "--3DNOW" , NaClCPUFeature_3DNOW },
819 : { "--EMMX" , NaClCPUFeature_EMMX },
820 : { "--E3DNOW" , NaClCPUFeature_E3DNOW },
821 : { "--LZCNT" , NaClCPUFeature_LZCNT },
822 : { "--SSE4A" , NaClCPUFeature_SSE4A },
823 : { "--LM" , NaClCPUFeature_LM },
824 : { "--SVM" , NaClCPUFeature_SVM },
825 : };
826 :
827 : int i;
828 : Bool flag_state;
829 2635 : for (i = 0; i < NACL_ARRAY_SIZE(flags); ++i) {
830 2379 : if (GrokBoolFlag(flags[i].flag_name, arg, flags[i].flag_ptr)) {
831 103 : return TRUE;
832 : }
833 : }
834 7424 : for (i = 0; i < NACL_ARRAY_SIZE(features); ++i) {
835 7168 : if (GrokBoolFlag(features[i].feature_name, arg, &flag_state)) {
836 0 : NaClSetCPUFeature(&ncval_cpu_features, features[i].feature, flag_state);
837 0 : return TRUE;
838 : }
839 : }
840 :
841 256 : return FALSE;
842 : }
843 :
844 : /* Checks if arg is one of the expected "int" flags, and if so, sets
845 : * the corresponding flag and returns true.
846 : */
847 256 : static Bool GrokAnIntFlag(const char *arg) {
848 : /* A set of boolean flags to be checked */
849 : static struct {
850 : const char *flag_name;
851 : int *flag_ptr;
852 : } flags[] = {
853 : { "--alignment" , &NACL_FLAGS_block_alignment },
854 : { "--max_errors", &NACL_FLAGS_max_reported_errors},
855 : { "--attempts" , &NACL_FLAGS_validate_attempts },
856 : };
857 : int i;
858 713 : for (i = 0; i < NACL_ARRAY_SIZE(flags); ++i) {
859 582 : if (GrokIntFlag(flags[i].flag_name, arg, flags[i].flag_ptr)) {
860 125 : return TRUE;
861 : }
862 : }
863 131 : return FALSE;
864 : }
865 :
866 68 : static int GrokFlags(int argc, const char *argv[]) {
867 : int i;
868 : int new_argc;
869 68 : Bool help = FALSE;
870 : #if NACL_TARGET_SUBARCH == 64
871 : Bool write_sandbox = !NACL_FLAGS_read_sandbox;
872 : #endif
873 68 : if (argc == 0) return 0;
874 68 : new_argc = 1;
875 427 : for (i = 1; i < argc; ++i) {
876 : Bool flag;
877 359 : const char *arg = argv[i];
878 359 : if (GrokABoolFlag(arg) ||
879 : GrokAnIntFlag(arg) ||
880 : GrokCstringFlag("--hex_text", arg, &NACL_FLAGS_hex_text)) {
881 : /* Valid processed flag, continue to next flag. */
882 69 : } else if (GrokBoolFlag("--help", arg, &help)) {
883 0 : usage(0);
884 : #if NACL_TARGET_SUBARCH == 64
885 : } else if (0 == strcmp("--trace_verbose", arg)) {
886 : NaClValidatorFlagsSetTraceVerbose();
887 : } else if (GrokBoolFlag("--write_sfi", arg, &write_sandbox)) {
888 : NACL_FLAGS_read_sandbox = !write_sandbox;
889 : } else if (GrokBoolFlag("--readwrite_sfi", arg, &NACL_FLAGS_read_sandbox)) {
890 : write_sandbox = !NACL_FLAGS_read_sandbox;
891 : continue;
892 : #endif
893 69 : } else if (0 == strcmp("--cpuid-all", arg)) {
894 62 : NaClSetAllCPUFeatures(&ncval_cpu_features);
895 7 : } else if (0 == strcmp("--cpuid-none", arg)) {
896 1 : NaClClearCPUFeatures(&ncval_cpu_features);
897 6 : } else if (GrokBoolFlag("--local_cpuid", arg, &flag)) {
898 0 : NaClGetCurrentCPUFeatures(&ncval_cpu_features);
899 : } else {
900 6 : argv[new_argc++] = argv[i];
901 : }
902 : }
903 :
904 : /* Before returning, update internals to match command line
905 : * values found.
906 : */
907 68 : if (NACL_FLAGS_warnings) {
908 0 : NaClLogSetVerbosity(LOG_WARNING);
909 : }
910 68 : if (NACL_FLAGS_errors) {
911 0 : NaClLogSetVerbosity(LOG_ERROR);
912 : }
913 68 : if (NACL_FLAGS_fatal) {
914 0 : NaClLogSetVerbosity(LOG_FATAL);
915 : }
916 68 : NCValidatorSetMaxDiagnostics(NACL_FLAGS_max_reported_errors);
917 68 : if (NACL_FLAGS_stubout_memory && (NACL_FLAGS_validate_attempts != 1)) {
918 0 : fprintf(stderr, "Can't specify --stubout when --attempts!=1\n");
919 : }
920 :
921 68 : return new_argc;
922 : }
923 :
924 : /* Decode and print out code segment if stubout memory is specified
925 : * command line.
926 : */
927 : static void NaClMaybeDecodeDataSegment(
928 62 : uint8_t *mbase, NaClPcAddress vbase, NaClMemorySize size) {
929 62 : if (NACL_FLAGS_stubout_memory) {
930 : /* Disassemble data segment to see how halts were inserted.
931 : * Note: We use the full decoder (rather than the validator decoder)
932 : * because the validator decoders are partial decodings, and can be
933 : * confusing to the reader.
934 : */
935 0 : NaClDisassembleSegment(mbase, vbase, size,
936 : NACL_DISASSEMBLE_FLAG(NaClDisassembleFull));
937 : }
938 62 : }
939 :
940 68 : int main(int argc, const char *argv[]) {
941 68 : int result = 0;
942 : struct GioFile gio_out_stream;
943 68 : struct Gio *gout = (struct Gio*) &gio_out_stream;
944 :
945 68 : if (argc < 2) {
946 0 : fprintf(stderr, "expected: %s file\n", argv[0]);
947 0 : usage(1);
948 : }
949 :
950 : /* Set up logging. */
951 68 : if (!GioFileRefCtor(&gio_out_stream, stdout)) {
952 0 : fprintf(stderr, "Unable to create gio file for stdout!\n");
953 0 : return 1;
954 : }
955 68 : NaClLogModuleInitExtended(LOG_INFO, gout);
956 68 : NaClLogDisableTimestamp();
957 :
958 : /* By default, assume no local cpu features are available. */
959 68 : NaClClearCPUFeatures(&ncval_cpu_features);
960 :
961 : /* Validate the specified input. */
962 68 : argc = GrokFlags(argc, argv);
963 68 : if (0 == strcmp(NACL_FLAGS_hex_text, "")) {
964 : /* Run validator on elf file. */
965 : ValidateData data;
966 : Bool success = NaClRunValidator(
967 : argc, argv, &data,
968 : (NaClValidateLoad) ValidateElfLoad,
969 6 : (NaClValidateAnalyze) ValidateAnalyze);
970 6 : NaClReportSafety(success, argv[1]);
971 6 : result = (success ? 0 : 1);
972 : } else {
973 : /* Run validator on hex text file. */
974 : NaClValidatorByteArray data;
975 62 : argc = ValidateHexLoad(argc, argv, &data);
976 62 : NaClRunValidatorBytes(
977 : argc, argv, (uint8_t*) &data.bytes,
978 : data.num_bytes, data.base);
979 62 : NaClMaybeDecodeDataSegment(&data.bytes[0], data.base, data.num_bytes);
980 : /* always succeed, so that the testing framework works. */
981 62 : result = 0;
982 : }
983 :
984 68 : NaClLogModuleFini();
985 68 : GioFileDtor(gout);
986 68 : return result;
987 : }
|