1*1ec454baSMasami Hiramatsu /* 2*1ec454baSMasami Hiramatsu * x86 decoder sanity test - based on test_get_insn.c 3*1ec454baSMasami Hiramatsu * 4*1ec454baSMasami Hiramatsu * This program is free software; you can redistribute it and/or modify 5*1ec454baSMasami Hiramatsu * it under the terms of the GNU General Public License as published by 6*1ec454baSMasami Hiramatsu * the Free Software Foundation; either version 2 of the License, or 7*1ec454baSMasami Hiramatsu * (at your option) any later version. 8*1ec454baSMasami Hiramatsu * 9*1ec454baSMasami Hiramatsu * This program is distributed in the hope that it will be useful, 10*1ec454baSMasami Hiramatsu * but WITHOUT ANY WARRANTY; without even the implied warranty of 11*1ec454baSMasami Hiramatsu * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12*1ec454baSMasami Hiramatsu * GNU General Public License for more details. 13*1ec454baSMasami Hiramatsu * 14*1ec454baSMasami Hiramatsu * You should have received a copy of the GNU General Public License 15*1ec454baSMasami Hiramatsu * along with this program; if not, write to the Free Software 16*1ec454baSMasami Hiramatsu * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17*1ec454baSMasami Hiramatsu * 18*1ec454baSMasami Hiramatsu * Copyright (C) IBM Corporation, 2009 19*1ec454baSMasami Hiramatsu * Copyright (C) Hitachi, Ltd., 2011 20*1ec454baSMasami Hiramatsu */ 21*1ec454baSMasami Hiramatsu 22*1ec454baSMasami Hiramatsu #include <stdlib.h> 23*1ec454baSMasami Hiramatsu #include <stdio.h> 24*1ec454baSMasami Hiramatsu #include <string.h> 25*1ec454baSMasami Hiramatsu #include <assert.h> 26*1ec454baSMasami Hiramatsu #include <unistd.h> 27*1ec454baSMasami Hiramatsu #include <sys/types.h> 28*1ec454baSMasami Hiramatsu #include <sys/stat.h> 29*1ec454baSMasami Hiramatsu #include <fcntl.h> 30*1ec454baSMasami Hiramatsu 31*1ec454baSMasami Hiramatsu #define unlikely(cond) (cond) 32*1ec454baSMasami Hiramatsu #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) 33*1ec454baSMasami Hiramatsu 34*1ec454baSMasami Hiramatsu #include <asm/insn.h> 35*1ec454baSMasami Hiramatsu #include <inat.c> 36*1ec454baSMasami Hiramatsu #include <insn.c> 37*1ec454baSMasami Hiramatsu 38*1ec454baSMasami Hiramatsu /* 39*1ec454baSMasami Hiramatsu * Test of instruction analysis against tampering. 40*1ec454baSMasami Hiramatsu * Feed random binary to instruction decoder and ensure not to 41*1ec454baSMasami Hiramatsu * access out-of-instruction-buffer. 42*1ec454baSMasami Hiramatsu */ 43*1ec454baSMasami Hiramatsu 44*1ec454baSMasami Hiramatsu #define DEFAULT_MAX_ITER 10000 45*1ec454baSMasami Hiramatsu #define INSN_NOP 0x90 46*1ec454baSMasami Hiramatsu 47*1ec454baSMasami Hiramatsu static const char *prog; /* Program name */ 48*1ec454baSMasami Hiramatsu static int verbose; /* Verbosity */ 49*1ec454baSMasami Hiramatsu static int x86_64; /* x86-64 bit mode flag */ 50*1ec454baSMasami Hiramatsu static unsigned int seed; /* Random seed */ 51*1ec454baSMasami Hiramatsu static unsigned long iter_start; /* Start of iteration number */ 52*1ec454baSMasami Hiramatsu static unsigned long iter_end = DEFAULT_MAX_ITER; /* End of iteration number */ 53*1ec454baSMasami Hiramatsu static FILE *input_file; /* Input file name */ 54*1ec454baSMasami Hiramatsu 55*1ec454baSMasami Hiramatsu static void usage(const char *err) 56*1ec454baSMasami Hiramatsu { 57*1ec454baSMasami Hiramatsu if (err) 58*1ec454baSMasami Hiramatsu fprintf(stderr, "Error: %s\n\n", err); 59*1ec454baSMasami Hiramatsu fprintf(stderr, "Usage: %s [-y|-n|-v] [-s seed[,no]] [-m max] [-i input]\n", prog); 60*1ec454baSMasami Hiramatsu fprintf(stderr, "\t-y 64bit mode\n"); 61*1ec454baSMasami Hiramatsu fprintf(stderr, "\t-n 32bit mode\n"); 62*1ec454baSMasami Hiramatsu fprintf(stderr, "\t-v Verbose mode\n"); 63*1ec454baSMasami Hiramatsu fprintf(stderr, "\t-s Give a random seed (and iteration number)\n"); 64*1ec454baSMasami Hiramatsu fprintf(stderr, "\t-m Give a maximum iteration number\n"); 65*1ec454baSMasami Hiramatsu fprintf(stderr, "\t-i Give an input file with decoded binary\n"); 66*1ec454baSMasami Hiramatsu exit(1); 67*1ec454baSMasami Hiramatsu } 68*1ec454baSMasami Hiramatsu 69*1ec454baSMasami Hiramatsu static void dump_field(FILE *fp, const char *name, const char *indent, 70*1ec454baSMasami Hiramatsu struct insn_field *field) 71*1ec454baSMasami Hiramatsu { 72*1ec454baSMasami Hiramatsu fprintf(fp, "%s.%s = {\n", indent, name); 73*1ec454baSMasami Hiramatsu fprintf(fp, "%s\t.value = %d, bytes[] = {%x, %x, %x, %x},\n", 74*1ec454baSMasami Hiramatsu indent, field->value, field->bytes[0], field->bytes[1], 75*1ec454baSMasami Hiramatsu field->bytes[2], field->bytes[3]); 76*1ec454baSMasami Hiramatsu fprintf(fp, "%s\t.got = %d, .nbytes = %d},\n", indent, 77*1ec454baSMasami Hiramatsu field->got, field->nbytes); 78*1ec454baSMasami Hiramatsu } 79*1ec454baSMasami Hiramatsu 80*1ec454baSMasami Hiramatsu static void dump_insn(FILE *fp, struct insn *insn) 81*1ec454baSMasami Hiramatsu { 82*1ec454baSMasami Hiramatsu fprintf(fp, "Instruction = {\n"); 83*1ec454baSMasami Hiramatsu dump_field(fp, "prefixes", "\t", &insn->prefixes); 84*1ec454baSMasami Hiramatsu dump_field(fp, "rex_prefix", "\t", &insn->rex_prefix); 85*1ec454baSMasami Hiramatsu dump_field(fp, "vex_prefix", "\t", &insn->vex_prefix); 86*1ec454baSMasami Hiramatsu dump_field(fp, "opcode", "\t", &insn->opcode); 87*1ec454baSMasami Hiramatsu dump_field(fp, "modrm", "\t", &insn->modrm); 88*1ec454baSMasami Hiramatsu dump_field(fp, "sib", "\t", &insn->sib); 89*1ec454baSMasami Hiramatsu dump_field(fp, "displacement", "\t", &insn->displacement); 90*1ec454baSMasami Hiramatsu dump_field(fp, "immediate1", "\t", &insn->immediate1); 91*1ec454baSMasami Hiramatsu dump_field(fp, "immediate2", "\t", &insn->immediate2); 92*1ec454baSMasami Hiramatsu fprintf(fp, "\t.attr = %x, .opnd_bytes = %d, .addr_bytes = %d,\n", 93*1ec454baSMasami Hiramatsu insn->attr, insn->opnd_bytes, insn->addr_bytes); 94*1ec454baSMasami Hiramatsu fprintf(fp, "\t.length = %d, .x86_64 = %d, .kaddr = %p}\n", 95*1ec454baSMasami Hiramatsu insn->length, insn->x86_64, insn->kaddr); 96*1ec454baSMasami Hiramatsu } 97*1ec454baSMasami Hiramatsu 98*1ec454baSMasami Hiramatsu static void dump_stream(FILE *fp, const char *msg, unsigned long nr_iter, 99*1ec454baSMasami Hiramatsu unsigned char *insn_buf, struct insn *insn) 100*1ec454baSMasami Hiramatsu { 101*1ec454baSMasami Hiramatsu int i; 102*1ec454baSMasami Hiramatsu 103*1ec454baSMasami Hiramatsu fprintf(fp, "%s:\n", msg); 104*1ec454baSMasami Hiramatsu 105*1ec454baSMasami Hiramatsu dump_insn(stderr, insn); 106*1ec454baSMasami Hiramatsu 107*1ec454baSMasami Hiramatsu fprintf(fp, "You can reproduce this with below command(s);\n"); 108*1ec454baSMasami Hiramatsu 109*1ec454baSMasami Hiramatsu /* Input a decoded instruction sequence directly */ 110*1ec454baSMasami Hiramatsu fprintf(fp, " $ echo "); 111*1ec454baSMasami Hiramatsu for (i = 0; i < MAX_INSN_SIZE; i++) 112*1ec454baSMasami Hiramatsu fprintf(fp, " %02x", insn_buf[i]); 113*1ec454baSMasami Hiramatsu fprintf(fp, " | %s -i -\n", prog); 114*1ec454baSMasami Hiramatsu 115*1ec454baSMasami Hiramatsu if (!input_file) { 116*1ec454baSMasami Hiramatsu fprintf(fp, "Or \n"); 117*1ec454baSMasami Hiramatsu /* Give a seed and iteration number */ 118*1ec454baSMasami Hiramatsu fprintf(fp, " $ %s -s 0x%x,%lu\n", prog, seed, nr_iter); 119*1ec454baSMasami Hiramatsu } 120*1ec454baSMasami Hiramatsu } 121*1ec454baSMasami Hiramatsu 122*1ec454baSMasami Hiramatsu static void init_random_seed(void) 123*1ec454baSMasami Hiramatsu { 124*1ec454baSMasami Hiramatsu int fd; 125*1ec454baSMasami Hiramatsu 126*1ec454baSMasami Hiramatsu fd = open("/dev/urandom", O_RDONLY); 127*1ec454baSMasami Hiramatsu if (fd < 0) 128*1ec454baSMasami Hiramatsu goto fail; 129*1ec454baSMasami Hiramatsu 130*1ec454baSMasami Hiramatsu if (read(fd, &seed, sizeof(seed)) != sizeof(seed)) 131*1ec454baSMasami Hiramatsu goto fail; 132*1ec454baSMasami Hiramatsu 133*1ec454baSMasami Hiramatsu close(fd); 134*1ec454baSMasami Hiramatsu return; 135*1ec454baSMasami Hiramatsu fail: 136*1ec454baSMasami Hiramatsu usage("Failed to open /dev/urandom"); 137*1ec454baSMasami Hiramatsu } 138*1ec454baSMasami Hiramatsu 139*1ec454baSMasami Hiramatsu /* Read given instruction sequence from the input file */ 140*1ec454baSMasami Hiramatsu static int read_next_insn(unsigned char *insn_buf) 141*1ec454baSMasami Hiramatsu { 142*1ec454baSMasami Hiramatsu char buf[256] = "", *tmp; 143*1ec454baSMasami Hiramatsu int i; 144*1ec454baSMasami Hiramatsu 145*1ec454baSMasami Hiramatsu tmp = fgets(buf, ARRAY_SIZE(buf), input_file); 146*1ec454baSMasami Hiramatsu if (tmp == NULL || feof(input_file)) 147*1ec454baSMasami Hiramatsu return 0; 148*1ec454baSMasami Hiramatsu 149*1ec454baSMasami Hiramatsu for (i = 0; i < MAX_INSN_SIZE; i++) { 150*1ec454baSMasami Hiramatsu insn_buf[i] = (unsigned char)strtoul(tmp, &tmp, 16); 151*1ec454baSMasami Hiramatsu if (*tmp != ' ') 152*1ec454baSMasami Hiramatsu break; 153*1ec454baSMasami Hiramatsu } 154*1ec454baSMasami Hiramatsu 155*1ec454baSMasami Hiramatsu return i; 156*1ec454baSMasami Hiramatsu } 157*1ec454baSMasami Hiramatsu 158*1ec454baSMasami Hiramatsu static int generate_insn(unsigned char *insn_buf) 159*1ec454baSMasami Hiramatsu { 160*1ec454baSMasami Hiramatsu int i; 161*1ec454baSMasami Hiramatsu 162*1ec454baSMasami Hiramatsu if (input_file) 163*1ec454baSMasami Hiramatsu return read_next_insn(insn_buf); 164*1ec454baSMasami Hiramatsu 165*1ec454baSMasami Hiramatsu /* Fills buffer with random binary up to MAX_INSN_SIZE */ 166*1ec454baSMasami Hiramatsu for (i = 0; i < MAX_INSN_SIZE - 1; i += 2) 167*1ec454baSMasami Hiramatsu *(unsigned short *)(&insn_buf[i]) = random() & 0xffff; 168*1ec454baSMasami Hiramatsu 169*1ec454baSMasami Hiramatsu while (i < MAX_INSN_SIZE) 170*1ec454baSMasami Hiramatsu insn_buf[i++] = random() & 0xff; 171*1ec454baSMasami Hiramatsu 172*1ec454baSMasami Hiramatsu return i; 173*1ec454baSMasami Hiramatsu } 174*1ec454baSMasami Hiramatsu 175*1ec454baSMasami Hiramatsu static void parse_args(int argc, char **argv) 176*1ec454baSMasami Hiramatsu { 177*1ec454baSMasami Hiramatsu int c; 178*1ec454baSMasami Hiramatsu char *tmp = NULL; 179*1ec454baSMasami Hiramatsu int set_seed = 0; 180*1ec454baSMasami Hiramatsu 181*1ec454baSMasami Hiramatsu prog = argv[0]; 182*1ec454baSMasami Hiramatsu while ((c = getopt(argc, argv, "ynvs:m:i:")) != -1) { 183*1ec454baSMasami Hiramatsu switch (c) { 184*1ec454baSMasami Hiramatsu case 'y': 185*1ec454baSMasami Hiramatsu x86_64 = 1; 186*1ec454baSMasami Hiramatsu break; 187*1ec454baSMasami Hiramatsu case 'n': 188*1ec454baSMasami Hiramatsu x86_64 = 0; 189*1ec454baSMasami Hiramatsu break; 190*1ec454baSMasami Hiramatsu case 'v': 191*1ec454baSMasami Hiramatsu verbose = 1; 192*1ec454baSMasami Hiramatsu break; 193*1ec454baSMasami Hiramatsu case 'i': 194*1ec454baSMasami Hiramatsu if (strcmp("-", optarg) == 0) 195*1ec454baSMasami Hiramatsu input_file = stdin; 196*1ec454baSMasami Hiramatsu else 197*1ec454baSMasami Hiramatsu input_file = fopen(optarg, "r"); 198*1ec454baSMasami Hiramatsu if (!input_file) 199*1ec454baSMasami Hiramatsu usage("Failed to open input file"); 200*1ec454baSMasami Hiramatsu break; 201*1ec454baSMasami Hiramatsu case 's': 202*1ec454baSMasami Hiramatsu seed = (unsigned int)strtoul(optarg, &tmp, 0); 203*1ec454baSMasami Hiramatsu if (*tmp == ',') { 204*1ec454baSMasami Hiramatsu optarg = tmp + 1; 205*1ec454baSMasami Hiramatsu iter_start = strtoul(optarg, &tmp, 0); 206*1ec454baSMasami Hiramatsu } 207*1ec454baSMasami Hiramatsu if (*tmp != '\0' || tmp == optarg) 208*1ec454baSMasami Hiramatsu usage("Failed to parse seed"); 209*1ec454baSMasami Hiramatsu set_seed = 1; 210*1ec454baSMasami Hiramatsu break; 211*1ec454baSMasami Hiramatsu case 'm': 212*1ec454baSMasami Hiramatsu iter_end = strtoul(optarg, &tmp, 0); 213*1ec454baSMasami Hiramatsu if (*tmp != '\0' || tmp == optarg) 214*1ec454baSMasami Hiramatsu usage("Failed to parse max_iter"); 215*1ec454baSMasami Hiramatsu break; 216*1ec454baSMasami Hiramatsu default: 217*1ec454baSMasami Hiramatsu usage(NULL); 218*1ec454baSMasami Hiramatsu } 219*1ec454baSMasami Hiramatsu } 220*1ec454baSMasami Hiramatsu 221*1ec454baSMasami Hiramatsu /* Check errors */ 222*1ec454baSMasami Hiramatsu if (iter_end < iter_start) 223*1ec454baSMasami Hiramatsu usage("Max iteration number must be bigger than iter-num"); 224*1ec454baSMasami Hiramatsu 225*1ec454baSMasami Hiramatsu if (set_seed && input_file) 226*1ec454baSMasami Hiramatsu usage("Don't use input file (-i) with random seed (-s)"); 227*1ec454baSMasami Hiramatsu 228*1ec454baSMasami Hiramatsu /* Initialize random seed */ 229*1ec454baSMasami Hiramatsu if (!input_file) { 230*1ec454baSMasami Hiramatsu if (!set_seed) /* No seed is given */ 231*1ec454baSMasami Hiramatsu init_random_seed(); 232*1ec454baSMasami Hiramatsu srand(seed); 233*1ec454baSMasami Hiramatsu } 234*1ec454baSMasami Hiramatsu } 235*1ec454baSMasami Hiramatsu 236*1ec454baSMasami Hiramatsu int main(int argc, char **argv) 237*1ec454baSMasami Hiramatsu { 238*1ec454baSMasami Hiramatsu struct insn insn; 239*1ec454baSMasami Hiramatsu int insns = 0; 240*1ec454baSMasami Hiramatsu int errors = 0; 241*1ec454baSMasami Hiramatsu unsigned long i; 242*1ec454baSMasami Hiramatsu unsigned char insn_buf[MAX_INSN_SIZE * 2]; 243*1ec454baSMasami Hiramatsu 244*1ec454baSMasami Hiramatsu parse_args(argc, argv); 245*1ec454baSMasami Hiramatsu 246*1ec454baSMasami Hiramatsu /* Prepare stop bytes with NOPs */ 247*1ec454baSMasami Hiramatsu memset(insn_buf + MAX_INSN_SIZE, INSN_NOP, MAX_INSN_SIZE); 248*1ec454baSMasami Hiramatsu 249*1ec454baSMasami Hiramatsu for (i = 0; i < iter_end; i++) { 250*1ec454baSMasami Hiramatsu if (generate_insn(insn_buf) <= 0) 251*1ec454baSMasami Hiramatsu break; 252*1ec454baSMasami Hiramatsu 253*1ec454baSMasami Hiramatsu if (i < iter_start) /* Skip to given iteration number */ 254*1ec454baSMasami Hiramatsu continue; 255*1ec454baSMasami Hiramatsu 256*1ec454baSMasami Hiramatsu /* Decode an instruction */ 257*1ec454baSMasami Hiramatsu insn_init(&insn, insn_buf, x86_64); 258*1ec454baSMasami Hiramatsu insn_get_length(&insn); 259*1ec454baSMasami Hiramatsu 260*1ec454baSMasami Hiramatsu if (verbose && !insn_complete(&insn)) 261*1ec454baSMasami Hiramatsu dump_stream(stdout, "Info: Found an undecodable input", i, insn_buf, &insn); 262*1ec454baSMasami Hiramatsu 263*1ec454baSMasami Hiramatsu if (insn.next_byte <= insn.kaddr || 264*1ec454baSMasami Hiramatsu insn.kaddr + MAX_INSN_SIZE < insn.next_byte) { 265*1ec454baSMasami Hiramatsu /* Access out-of-range memory */ 266*1ec454baSMasami Hiramatsu dump_stream(stdout, "Error: Found an access violation", i, insn_buf, &insn); 267*1ec454baSMasami Hiramatsu errors++; 268*1ec454baSMasami Hiramatsu } 269*1ec454baSMasami Hiramatsu insns++; 270*1ec454baSMasami Hiramatsu } 271*1ec454baSMasami Hiramatsu 272*1ec454baSMasami Hiramatsu fprintf(stdout, "%s: decoded and checked %d %s instructions with %d errors (seed:0x%x)\n", (errors) ? "Failure" : "Success", insns, (input_file) ? "given" : "random", errors, seed); 273*1ec454baSMasami Hiramatsu 274*1ec454baSMasami Hiramatsu return errors ? 1 : 0; 275*1ec454baSMasami Hiramatsu } 276