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