1 /* 2 * fault-model.c -- fault injection code for drivers 3 * 4 * Copyright (C) 2003 Mike Swift 5 * Copyright (c) 1999 Wee Teck Ng 6 * 7 * The source code in this file can be freely used, adapted, 8 * and redistributed in source or binary form, so long as an 9 * acknowledgment appears in derived source files. No warranty 10 * is attached; * we cannot take responsibility for errors or 11 * fitness for use. 12 * 13 */ 14 15 16 /* 17 * Fault injector for testing the usefulness of NOOKS 18 * 19 * Adapted from the SWIFI tools used by Wee Teck Ng to evaluate the RIO 20 * file cache at the University of Michigan 21 * 22 */ 23 24 /* 25 * This tool can inject faults into modules, whether they are loaded into a 26 * nook or loaded into the kernel (for comparison testing). 27 * 28 * There are several classes of faults emulated: 29 * - Corruption of text 30 * - corruption 31 * - simulated programming faults 32 * - skip initialization (immediate write to EBP-x) 33 * - remove instruction (replace with NOP) 34 * - incorrect source/destination (corrupted) 35 * - remove jmp or rep instruction 36 * - change address computation for memory access (not stack) 37 * - change termination condition for loop (change repeat to repeat 38 * -while equal, change condition to !condition 39 - remove instructions loading registers from arguments (ebp+x) 40 * 41 * - Corruption of stack 42 * - Corruption of heap 43 * - copy overruns 44 * - use after free 45 */ 46 47 #if 0 48 #include <linux/kernel.h> 49 #include <linux/kallsyms.h> 50 #include <linux/module.h> 51 #include <linux/mm.h> 52 #include <linux/slab.h> 53 #include <linux/vmalloc.h> 54 #include <linux/smp_lock.h> 55 #include <asm/uaccess.h> 56 #include <asm/delay.h> 57 #include <asm/page.h> 58 #endif 59 #include "ddb.h" 60 #include "db_sym.h" 61 #include "swifi.h" 62 63 #include "extra.h" 64 #include <assert.h> 65 66 #define CRASH_INTERVAL 8192 67 #define FI_MASK 0xfff 68 #define P50 0x3fffffff /* 50% of max rand */ 69 #define P94 0x7851eb84 /* 94% of max rand */ 70 #define NOP 0x90 71 72 unsigned long randomSeed=0; /* random number */ 73 unsigned long injectFault=1; /* inject fault ? */ 74 unsigned long diskTest=0; /* run disk test instead of rio */ 75 unsigned long faultInjected=0; /* has fault been injected? */ 76 unsigned long crashInterval=0; /* interval between injecting fault */ 77 unsigned long crashCount=0; /* number of times fault is injected */ 78 unsigned long faultType; 79 unsigned long numFaults; 80 char *crashAddr=0; /* track current malloc */ 81 int crashToggle=1; 82 int text_fault(char *mod_name, pswifi_result_t res); 83 int stack_fault(pswifi_result_t res); 84 int heap_fault(pswifi_result_t res); 85 int direct_fault(int fault_address, int fault_content, pswifi_result_t res); 86 int direct_fault1(int fault_address, int fault_content, pswifi_result_t res); 87 int while1(void); 88 89 int *testVA; 90 91 #if 0 92 #define PDEBUG(fmt, args...) \ 93 do { \ 94 printk( KERN_ALERT "SWIFI: " fmt, ## args); \ 95 } while (0) 96 #else 97 #include <stdio.h> 98 #define PDEBUG(args) /* (printf args) */ 99 #endif 100 101 #define inline 102 103 #ifdef CONFIG_SWIFI 104 105 #if 0 106 static inline long 107 get_mod_name(const char *user_name, char **buf) 108 { 109 unsigned long page; 110 long retval; 111 112 page = __get_free_page(GFP_KERNEL); 113 if (!page) 114 return -ENOMEM; 115 116 retval = strncpy_from_user((char *)page, user_name, PAGE_SIZE); 117 if (retval > 0) { 118 if (retval < PAGE_SIZE) { 119 *buf = (char *)page; 120 return retval; 121 } 122 retval = -ENAMETOOLONG; 123 } else if (!retval) 124 retval = -EINVAL; 125 126 free_page(page); 127 return retval; 128 } 129 130 static inline void 131 put_mod_name(char *buf) 132 { 133 free_page((unsigned long)buf); 134 } 135 #endif 136 137 long 138 sys_inject_fault(char * module_name, 139 unsigned long argFaultType, 140 unsigned long argRandomSeed, 141 unsigned long argNumFaults, 142 pswifi_result_t result_record, 143 unsigned long argInjectFault) 144 { 145 int result = 0; 146 unsigned long fault_address = 0; 147 unsigned long fault_data = 0 ; 148 char * kern_name = NULL; 149 #if 0 150 struct module * mod = NULL; 151 int found = 0; 152 #endif 153 pswifi_result_t res = NULL; 154 155 if (argNumFaults > SWIFI_MAX_FAULTS) { 156 result = -E2BIG; 157 goto Cleanup; 158 } 159 res = (pswifi_result_t) malloc((1+argNumFaults) * sizeof(swifi_result_t)); 160 if (res == NULL) { 161 result = -ENOMEM; 162 goto Cleanup; 163 } 164 memset(res, 0, (1 + argNumFaults) * sizeof(swifi_result_t)); 165 166 /* 167 // Capture the name of the module from usermode 168 */ 169 170 #if 0 171 result = get_mod_name(module_name, &kern_name); 172 if (result < 0) { 173 goto Cleanup; 174 } 175 #endif 176 177 kern_name= module_name; 178 179 180 181 182 #if 0 183 lock_kernel(); 184 185 for (mod = module_list; mod ; mod = mod->next) { 186 if (strcmp(kern_name, mod->name) == 0) { 187 found = 1; 188 break; 189 } 190 } 191 unlock_kernel(); 192 if (!found) { 193 result = -ENOENT; 194 goto Cleanup; 195 } 196 #endif 197 198 numFaults = argNumFaults; 199 faultType = argFaultType; 200 randomSeed = argRandomSeed; 201 injectFault = argInjectFault; 202 203 204 if(faultType>=DISK_TEST) { 205 faultType=faultType-DISK_TEST; 206 diskTest=1; 207 } 208 if(faultType==STATS) { 209 #if 0 210 extern long time_vmp, n_vmp; 211 extern long time_pmp, n_pmp; 212 213 PDEBUG("# vm_map_protect=%ld, total cycle=%ld\n", n_vmp, time_vmp); 214 PDEBUG("# pmap_protect=%ld, total cycle=%ld\n", n_pmp, time_pmp); 215 n_vmp=0; time_vmp=0; 216 n_pmp=0; time_pmp=0; 217 #endif 218 } else if (faultType == DIRECT_FAULT) { 219 fault_address = numFaults; 220 fault_data = randomSeed; 221 PDEBUG(("sys inject fault, type %ld, addr=%lx, flip bit%lx\n", 222 faultType, fault_address, fault_data)); 223 } else if (faultType == DIRECT_FAULT1) { 224 fault_address = numFaults; 225 fault_data = randomSeed; 226 PDEBUG(("sys inject fault, type %ld, addr=%lx, zero bytes %lx\n", 227 faultType, fault_address, fault_data)); 228 } else { 229 PDEBUG(("sys inject fault, type %ld, seed=%ld, fault=%ld\n", 230 faultType, randomSeed, numFaults)); 231 } 232 faultInjected=1; 233 234 srandom(randomSeed); 235 /* set warm reboot, leave RAM unchanged 236 * 0 : don't inject fault 237 * 1 : run POST, wipe out memory 238 * 2 : don't test memory 239 * 3 : don't change memory (doesn't work) 240 * 4 : don't sync registry 241 */ 242 243 /* default number of faults is 5 */ 244 if(numFaults<=0 || numFaults>100) numFaults=5; 245 246 switch(faultType) 247 { 248 case TEXT_FAULT: 249 result = text_fault(module_name, res); 250 break; 251 case STACK_FAULT: 252 result = stack_fault(res); 253 break; 254 case HEAP_FAULT: 255 result = heap_fault(res); 256 break; 257 case INIT_FAULT: 258 case NOP_FAULT: 259 case DST_FAULT: 260 case SRC_FAULT: 261 case BRANCH_FAULT: 262 case PTR_FAULT: 263 case LOOP_FAULT: 264 case INTERFACE_FAULT: 265 case IRQ_FAULT: 266 result = text_fault(module_name, res); 267 break; 268 case FREE_FAULT: 269 case BCOPY_FAULT: 270 case SYNC_FAULT: 271 case ALLOC_FAULT: 272 crashInterval=CRASH_INTERVAL; /* interval between crash */ 273 break; 274 case MEM_LEAK_FAULT: 275 crashToggle=0; 276 crashInterval=CRASH_INTERVAL; /* interval between crash */ 277 break; 278 case PANIC_FAULT: 279 panic("testing panic"); 280 result = 0; 281 break; 282 /* case WP_FAULT: page_reg_fault(random()); break; */ 283 case DIRECT_FAULT: 284 { 285 direct_fault(fault_address, fault_data, res); 286 break; 287 } 288 case DIRECT_FAULT1: 289 { 290 result = direct_fault1(fault_address, fault_data, res); 291 292 break; 293 } 294 /* case PAGE_REG_DUMP: rio_dump(); break; */ 295 case WHILE1_FAULT: 296 { 297 298 result = while1(); 299 300 break; 301 } 302 /* case CPU_RESET_FAULT: cpu_reset(); break; */; 303 case COW_FAULT: 304 { 305 /* test writing to kernel text. freebsd currently do a COW on a 306 * write to kernel text. 307 */ 308 unsigned long *addr1, *addr2; 309 310 addr1 = (unsigned long *) 0xf0212000; 311 addr2 = (unsigned long *) 0xf0212010; 312 PDEBUG(("%p=%lx, %p=%lx\n", addr1, *addr1, addr2, *addr2)); 313 /* 314 __asm__ ("movl $0xf0212000, %eax\n\t" \ 315 "movl $6, 0(%eax)\n\t" \ 316 "movl $6, 4(%eax)\n\t"); 317 */ 318 /* Not implemented on MINIX */ 319 assert(0); 320 addr1 = (unsigned long *) 0xf0212000; 321 addr2 = (unsigned long *) 0xf0212010; 322 PDEBUG(("after injecting fault\n")); 323 PDEBUG(("%p=%lx, %p=%lx\n", addr1, *addr1, addr2, *addr2)); 324 result = 0; 325 break; 326 } 327 328 case DEBUGGER_FAULT: 329 PDEBUG(("Debugger fault")); 330 /* 331 __asm__ ("movl %cr4, %ecx\n\t" \ 332 "movl $42, %ecx; .byte 0x0f, 0x32\n\t" \ 333 "movl $377, %ecx; .byte 0x0f, 0x32\n\t"); 334 */ 335 /* Not implemented on MINIX */ 336 assert(0); 337 result = 0; 338 break; 339 default: PDEBUG(("unknown fault type %ld\n", faultType)); break; 340 } 341 if (copy_to_user(result_record, res, argNumFaults * sizeof(swifi_result_t))) { 342 result = -EFAULT; 343 } 344 Cleanup: 345 #if 0 346 if (kern_name != NULL) { 347 put_mod_name(kern_name); 348 } 349 #endif 350 if (res != NULL) { 351 free(res); 352 } 353 354 return (result); 355 } 356 357 int while1(void) 358 { 359 int i=0; 360 361 PDEBUG(("entering into while 1 loop\n")); 362 while(1) { 363 udelay(20000); 364 PDEBUG(("delay %4d secs, cpl=0x%x, ipend=0x%x\n", i+=5, 20, 30)); 365 if(i>(100 * 2500)) 366 break; 367 } 368 return(0); 369 } 370 371 372 int direct_fault(int fault_address, int fault_content, pswifi_result_t res) 373 { 374 unsigned long *addr; 375 int flip_bit=0; 376 377 378 addr = (unsigned long *) (PAGE_OFFSET + fault_address); 379 380 PDEBUG(("%p:0x%lx => ", addr, *addr)); 381 382 flip_bit = 1 << fault_content; 383 384 res[0].address = (unsigned long) addr; 385 res[0].old = *addr; 386 res[0].new = (*addr) ^ flip_bit; 387 388 if (injectFault) { 389 *addr = (*addr) ^ flip_bit; 390 } 391 PDEBUG(("%lx\n", *addr)); 392 return(0); 393 } 394 395 int direct_fault1(int fault_address, int fault_content, pswifi_result_t res) 396 { 397 unsigned long *addr, data; 398 399 400 addr = (unsigned long *) (PAGE_OFFSET + fault_address); 401 402 PDEBUG(("%p:%lx => ", addr, *addr)); 403 404 405 data = *addr; 406 if(fault_content==1) { 407 data = data & 0xffffff00; 408 data = data | 0x00000090; 409 } else if(fault_content==2) { 410 data = data & 0xffff0000; 411 data = data | 0x00009090; 412 } else if(fault_content==3) { 413 data = data & 0xff000000; 414 data = data | 0x00909090; 415 } else if(fault_content==4) { 416 data = 0x90909090; 417 } 418 res[0].address = (unsigned long) addr; 419 res[0].old = *addr; 420 res[0].new = data; 421 if (injectFault) { 422 *addr = data; 423 } 424 425 PDEBUG(("%lx\n", *addr)); 426 427 428 return(0); 429 } 430 431 432 433 434 /* 435 #include <linux/sched.h> 436 */ 437 438 #define MAX_NUM_TASKS 20 439 440 struct task_struct * 441 find_task(void) 442 { 443 struct task_struct * task = NULL, *result = NULL ; 444 int i,j; 445 i = 1 + (random() % MAX_NUM_TASKS); 446 j = i; 447 448 449 do { 450 #if 0 451 read_lock(&tasklist_lock); 452 #endif 453 for_each_task(task) { 454 if (--i == 0) { 455 result = task; 456 break; 457 } 458 } 459 #if 0 460 read_unlock(&tasklist_lock); 461 #endif 462 } while ((i > 0) && (i != j)); 463 464 return(result); 465 } 466 467 int 468 stack_fault(pswifi_result_t res) 469 { 470 unsigned long *addr, size, taddr; 471 int flip_bit=0; 472 int count=0; 473 struct task_struct *task = NULL; 474 475 while(count < numFaults) { 476 task = find_task(); 477 if (task == NULL) { 478 return(-1); 479 } 480 481 size = (unsigned long) task + TASK_SIZE - task->thread.esp; 482 483 PDEBUG(("stack range=%lx-%lx\n", 484 (unsigned long) task->thread.esp, 485 (unsigned long) task + TASK_SIZE)); 486 487 addr = (unsigned long *) ((long) task->thread.esp + 488 (random()&~0x3)%size); 489 taddr=(unsigned long) addr; 490 flip_bit = random() & 0x1f; 491 PDEBUG(("%lx:%lx flip bit %d => ", taddr, *addr, flip_bit)); 492 flip_bit = 1 << flip_bit; 493 res[count].address = taddr; 494 res[count].old = *addr; 495 res[count].new = (*addr) ^ flip_bit; 496 if (injectFault) { 497 *addr = ((*addr)^flip_bit); 498 } 499 PDEBUG(("%lx\n", *addr)); 500 count++; 501 } 502 return(0); 503 } 504 505 506 507 /* 508 // Instead of dealing with heaps directly, we look at the area cache of pages 509 // and vm pages and find an address there. 510 */ 511 512 513 int heap_fault(pswifi_result_t res) 514 { 515 #ifdef notdef 516 unsigned long *addr, taddr; 517 int flip_bit=0; 518 int count=0; 519 unsigned long flags; 520 struct list_head *next; 521 522 addr = (unsigned long *) (map->address + (random()&~0xf)%map->size); 523 524 taddr=(unsigned long) addr; 525 flip_bit = random() & 0x1f; 526 PDEBUG("heap range=%lx-%lx ", map->address, map->address + map->size); 527 PDEBUG("%lx:%lx flip bit %d => ", taddr, *addr, flip_bit); 528 flip_bit = 1 << flip_bit; 529 res[count].address = taddr; 530 res[count].old = *addr; 531 res[count].new = (*addr) ^ flip_bit; 532 533 if (injectFault) { 534 *addr = ((*addr)^flip_bit); 535 } 536 PDEBUG("%lx\n", *addr); 537 count++; 538 } while (count < numFaults); 539 #endif 540 return(-1); 541 542 } 543 544 545 unsigned long 546 do_fault_copy_from_user (void *kaddr, const void *udaddr, unsigned long len, 547 unsigned long (* copy_fn) (void *, const void *, unsigned long)) 548 { 549 unsigned int prob, i=0; 550 551 if ( faultInjected && (faultType==BCOPY_FAULT) ) { 552 553 if (++crashCount == crashInterval) { 554 555 crashCount=0; 556 prob = random(); 557 crashInterval = CRASH_INTERVAL + (random() & FI_MASK); 558 559 if (prob < P50) { /* corrupt 1 QW */ 560 i=1; 561 } else if (prob < P94) { /* corrupt 2 - 1024 QW */ 562 i = prob & 0x3fe; 563 while(!i) { 564 i = random() & 0x3fe; 565 } 566 } else { /* corrupt 2-4 pages */ 567 i= prob & 0xc00; 568 while(!i) { 569 i = random() & 0xc00; 570 } 571 } 572 PDEBUG(("copyin: %p to %p, len=%ld overrun=%d, Intvl=%ld, inj=%ld\n", 573 udaddr, kaddr, len, i, crashInterval, faultInjected)); 574 if (faultInjected++ <numFaults) { 575 len += i; 576 } else { 577 faultInjected = 0; 578 } 579 i = 1; 580 } 581 return(copy_fn(kaddr, udaddr, len)); 582 } else { 583 return(copy_fn(kaddr, udaddr, len)); 584 } 585 } 586 587 unsigned long 588 do_fault_copy_to_user(void *udaddr, const void *kaddr, unsigned long len, 589 unsigned long (* copy_fn) (void *, 590 const void *, 591 unsigned long)) 592 { 593 unsigned int prob, i=0; 594 595 if( faultInjected && (faultType==BCOPY_FAULT) ){ 596 crashCount++; 597 if (crashCount == crashInterval) { 598 crashCount=0; 599 prob = random(); 600 crashInterval = CRASH_INTERVAL + (random() & FI_MASK); 601 602 if ( prob < P50) { /* corrupt 1 QW */ 603 i=1; 604 } else if(prob < P94) { /* corrupt 2 - 1024 QW */ 605 i = prob & 0x3fe; 606 while (!i) { 607 i = random() & 0x3fe; 608 } 609 } else { 610 i = prob & 0xc00; 611 while(!i) { 612 i = random() & 0xc00; 613 } 614 } 615 PDEBUG(("copyout: %p to %p, len=%ld overrun=%d, Intvl=%ld, inj=%ld\n", 616 kaddr, udaddr, len, i, crashInterval, faultInjected)); 617 if (faultInjected++ <numFaults) { 618 len+=i; 619 } else { 620 faultInjected = 0; 621 } 622 i=1; 623 } 624 return(copy_fn(udaddr, kaddr, len)); 625 } else 626 return(copy_fn(udaddr, kaddr, len)); 627 } 628 629 630 unsigned long 631 swifi___generic_copy_from_user (void *kaddr, void *udaddr, unsigned long len) 632 { 633 return(do_fault_copy_from_user(kaddr, 634 udaddr, 635 len, 636 __generic_copy_from_user)); 637 } 638 639 unsigned long 640 swifi___generic_copy_to_user(void *udaddr, void *kaddr, unsigned long len) 641 { 642 return(do_fault_copy_to_user(udaddr, 643 kaddr, 644 len, 645 __generic_copy_to_user)); 646 } 647 648 649 650 void * 651 swifi_memcpy_fn (void *to, void *from, size_t len) 652 { 653 unsigned int prob, i=0; 654 655 if( faultInjected && (faultType==BCOPY_FAULT) ) { 656 crashCount++; 657 if (crashCount == crashInterval) { 658 crashCount=0; 659 prob = random(); 660 crashInterval = CRASH_INTERVAL + (random() & FI_MASK); 661 662 if (prob < P50) { /* corrupt 1 QW */ 663 i=1; 664 } else if (prob < P94) { /* corrupt 2 - 1024 QW */ 665 i= prob & 0x3fe; 666 while(!i) { 667 i = random() & 0x3fe; 668 } 669 } else { /* corrupt 2-4 pages */ 670 i=prob&0xc00; 671 while(!i) { 672 i = random() & 0xc00; 673 } 674 } 675 676 PDEBUG(("memcpy: %p to %p, len=%d overrun=%d, Intvl=%ld, inj=%ld\n", 677 from, to, len, i, crashInterval, faultInjected)); 678 if(faultInjected++ <numFaults) len+=i; 679 else faultInjected=0; 680 i=1; 681 } 682 return(memcpy(to, from, len)); 683 } else 684 return(memcpy(to, from, len)); 685 } 686 687 688 void * 689 swifi_memmove_fn (void *to, void *from, size_t len) 690 { 691 unsigned int prob, i=0; 692 693 if( faultInjected && (faultType==BCOPY_FAULT) ) { 694 crashCount++; 695 if (crashCount == crashInterval) { 696 crashCount=0; 697 prob = random(); 698 crashInterval = CRASH_INTERVAL + (random() & FI_MASK); 699 700 if (prob < P50) { /* corrupt 1 QW */ 701 i=1; 702 } else if (prob < P94) { /* corrupt 2 - 1024 QW */ 703 i= prob & 0x3fe; 704 while(!i) { 705 i = random() & 0x3fe; 706 } 707 } else { /* corrupt 2-4 pages */ 708 i=prob&0xc00; 709 while(!i) { 710 i = random() & 0xc00; 711 } 712 } 713 714 PDEBUG(("memmove: %p to %p, len=%d overrun=%d, Intvl=%ld, inj=%ld\n", 715 from, to, len, i, crashInterval, faultInjected)); 716 if(faultInjected++ <numFaults) len+=i; 717 else faultInjected=0; 718 i=1; 719 } 720 return(memmove(to, from, len)); 721 } else 722 return(memmove(to, from, len)); 723 } 724 725 726 void * 727 memmove_fn(void *to, void *from, size_t len) 728 { 729 return(memmove(to, from, len)); 730 } 731 732 733 734 void * 735 memcpy_fn(void *to, void *from, size_t len) 736 { 737 return(memcpy(to, from, len)); 738 } 739 740 741 742 743 void 744 do_fault_kfree(void *addr, void (* kfree_fn)(const void *)) 745 { 746 if(addr == crashAddr) { 747 crashAddr=0; 748 } 749 if (faultInjected && (faultType==FREE_FAULT || 750 faultType==MEM_LEAK_FAULT)) { 751 crashCount++; 752 if(crashCount>=crashInterval) { 753 754 /* alternate between premature freeing and non-free */ 755 if(crashToggle) { 756 if(crashAddr) { 757 PDEBUG(("malloc : freeing %p prematurely\n", 758 crashAddr)); 759 kfree_fn(crashAddr); 760 kfree_fn(addr); 761 crashAddr=0; 762 crashToggle=0; 763 crashCount=0; 764 crashInterval = CRASH_INTERVAL + (random()&FI_MASK); 765 if (faultInjected++ > numFaults) { 766 faultInjected=0; 767 } 768 } 769 } else { 770 PDEBUG(("free: don't free %p\n", addr)); 771 if(faultInjected++ > numFaults) { 772 faultInjected=0; 773 } 774 if(faultType==FREE_FAULT) { 775 crashToggle=1; 776 } 777 crashCount=0; 778 crashInterval = CRASH_INTERVAL + (random()&FI_MASK); 779 } 780 } 781 } else { 782 kfree_fn(addr); 783 } 784 } 785 786 #if 0 787 void 788 swifi_kfree(const void *addr) 789 { 790 do_fault_kfree((void *) addr, kfree); 791 } 792 #endif 793 794 795 void do_vfree(const void * addr) 796 { 797 vfree((void *) addr); 798 } 799 800 801 void 802 swifi_vfree(void *addr) 803 { 804 do_fault_kfree(addr, do_vfree); 805 } 806 807 808 809 810 void * 811 do_fault_kmalloc(size_t size, 812 int flags, 813 void * (* kmalloc_fn)(size_t size, int flags)) 814 { 815 if (faultInjected && (faultType==ALLOC_FAULT)) { 816 crashCount++; 817 if(crashCount>=crashInterval) { 818 PDEBUG(("kmalloc : returning null\n")); 819 crashCount=0; 820 crashInterval = CRASH_INTERVAL + (random()&FI_MASK); 821 if (faultInjected++ > numFaults) { 822 faultInjected=0; 823 return(NULL); 824 } 825 826 } 827 } 828 829 return(kmalloc_fn(size, flags)); 830 } 831 832 833 #if 0 834 void * 835 swifi_kmalloc(size_t size, int flags) 836 { 837 return(do_fault_kmalloc(size, flags, kmalloc)); 838 } 839 #endif 840 841 842 843 void * do_fault_vmalloc(unsigned long size, 844 int gfp_mask, 845 pgprot_t prot, 846 void * (*vmalloc_fn)(unsigned long size, 847 int gfp_mask, 848 pgprot_t prot)) 849 { 850 if (faultInjected && (faultType==ALLOC_FAULT)) { 851 crashCount++; 852 if(crashCount>=crashInterval) { 853 PDEBUG(("vmalloc : returning null\n")); 854 crashCount=0; 855 crashInterval = CRASH_INTERVAL + (random()&FI_MASK); 856 if (faultInjected++ > numFaults) { 857 faultInjected=0; 858 return(NULL); 859 } 860 861 } 862 } 863 return(vmalloc_fn(size, gfp_mask, prot)); 864 } 865 866 void * 867 swifi___vmalloc(unsigned long size, int gfp_mask, pgprot_t prot) 868 { 869 return(do_fault_vmalloc(size, gfp_mask, prot, __vmalloc)); 870 } 871 872 873 874 #if 0 875 typedef struct section_callback { 876 const char * module_name; 877 const char * section_name; 878 unsigned long sec_start; 879 unsigned long sec_end; 880 } section_callback_t; 881 882 static int 883 text_section_callback(void *token, 884 const char *modname, 885 const char *secname, 886 ElfW(Addr) secstart, 887 ElfW(Addr) secend, 888 ElfW(Word) secflags) 889 { 890 section_callback_t * info = (section_callback_t *) token; 891 892 if ((strcmp(modname, info->module_name) == 0) && 893 (strcmp(secname, info->section_name) == 0)) { 894 info->sec_start = secstart; 895 info->sec_end = secend; 896 return(1); 897 } 898 return(0); 899 } 900 #endif 901 902 903 int text_fault(char *mod_name, pswifi_result_t res) 904 { 905 unsigned long *addr, text_size, offset, page, taddr; 906 unsigned long btext, etext; 907 908 int count, flip_bit=0, len, rc; 909 unsigned char *c; 910 #if 0 911 struct module * module; 912 section_callback_t info; 913 #endif 914 915 #define MAX_NUM_MODULES 10 916 917 /* inject faults into text space */ 918 919 for(count=0; count<numFaults; count++) { 920 int i = 1 + (random() % MAX_NUM_MODULES); 921 int j = i; 922 #if 0 923 module = mod; 924 #endif 925 926 #if 0 927 info.module_name = module->name; 928 info.module_name = "<module-name>"; 929 info.section_name = ".text"; 930 931 kallsyms_sections(&info, text_section_callback); 932 if (info.sec_start == 0 ) { 933 return(-1); 934 } 935 #endif 936 937 load_nlist(mod_name, &btext, &etext); 938 939 #if 0 940 btext = info.sec_start; 941 etext = info.sec_end; 942 #endif 943 text_size = etext - btext; 944 945 PDEBUG(("text=%lx-%lx, size=%lx\n", btext, etext, text_size)); 946 947 addr = (unsigned long *) 948 (btext + ((unsigned long) (random()&~0xf) % text_size)); 949 950 /* now the tricky part */ 951 952 taddr=(unsigned long) addr; 953 if( faultType==INIT_FAULT || 954 faultType==NOP_FAULT || 955 faultType==DST_FAULT || 956 faultType==SRC_FAULT || 957 faultType==BRANCH_FAULT || 958 faultType==PTR_FAULT || 959 faultType==LOOP_FAULT || 960 faultType==INTERFACE_FAULT || 961 faultType==IRQ_FAULT ) { 962 addr = (unsigned long *) find_faulty_instr(taddr, faultType, &len); 963 /* do it over again if we can't find the right instruction */ 964 if(!addr || !len ) { 965 i--; 966 continue; 967 } 968 } 969 970 printf("len = %d\n", len); 971 972 PDEBUG(("target addr=%lx, instr addr=%p, %lx=>", taddr, addr, 973 text_read_ul(addr))); 974 975 offset = (unsigned long) addr&PAGE_MASK; 976 page = (unsigned long) addr&~PAGE_MASK; 977 978 /* it doesn't matter what we used here to unprotect page, 979 * as this routine will not be in production code. 980 */ 981 982 res[count].address = taddr; 983 res[count].old = text_read_ul(addr); 984 res[count].new = text_read_ul(addr); 985 986 if (faultType==TEXT_FAULT) { 987 988 flip_bit = random() & 0x1f; 989 PDEBUG(("flip bit %d => ", flip_bit)); 990 flip_bit = 1 << flip_bit; 991 992 res[count].new = text_read_ul(addr) ^ flip_bit; 993 994 if (injectFault) { 995 text_write_ul(addr, text_read_ul(addr)^flip_bit); 996 } 997 998 } else if (faultType==NOP_FAULT || 999 faultType==INIT_FAULT || 1000 faultType==BRANCH_FAULT || 1001 faultType==INTERFACE_FAULT || 1002 faultType==IRQ_FAULT) { 1003 c = (unsigned char *) addr; 1004 1005 for (j = 0; j < len; j++) { 1006 /* replace these bytes with NOP (*c=NOP) */ 1007 if (j < sizeof(unsigned long)) { 1008 ((unsigned char *) &res[count].new)[j] = NOP; 1009 } 1010 if (injectFault) { 1011 text_write_ub(c, NOP); 1012 } 1013 1014 c++; 1015 } 1016 } else if (faultType==DST_FAULT || faultType==SRC_FAULT) { 1017 /* skip thru the prefix and opcode, and flip bits in following bytes */ 1018 int prefix; 1019 c=(unsigned char *) addr; 1020 do { 1021 switch (text_read_ub(c)) { 1022 case 0x66: case 0x67: case 0x26: case 0x36: 1023 case 0x2e: case 0x3e: case 0x64: case 0x65: 1024 case 0xf0: case 0xf2: case 0xf3: 1025 prefix = 1; 1026 break; 1027 default: 1028 prefix = 0; 1029 break; 1030 } 1031 if (prefix) { 1032 c++; 1033 } 1034 } while (prefix); 1035 if(text_read_ub(c)>=0xd8 && text_read_ub(c)<=0xdf) { 1036 /* don't mess with fp instruction, yet. 1037 * but there shouldn't be any fp instr in kernel. 1038 */ 1039 PDEBUG(("floating point instruction, bailing out\n")); 1040 i--; 1041 continue; 1042 } else if(text_read_ub(c)==0x0f) { 1043 c++; 1044 } 1045 if(text_read_ub(c)==0x0f) { 1046 c++; 1047 } 1048 c++; 1049 len = len-((long) c - (long) addr); 1050 if (len == 0) 1051 { 1052 printf("tex_fault: len = %d\n", len); 1053 count--; 1054 continue; 1055 } 1056 if (len == 0) 1057 { 1058 int i; 1059 1060 printf( 1061 "text_fault: bad length at address %p, c = %p, fault type %ld\n", 1062 addr, c, faultType); 1063 printf("bytes:"); 1064 for (i= 0; i<16; i++) 1065 printf(" 0x%02x", text_read_ub((char *)addr+i)); 1066 printf("\n"); 1067 abort(); 1068 *(int *)-4 = 0; 1069 } 1070 flip_bit = random() % (len*8); 1071 PDEBUG(("flip bit %d (len=%d) => ", flip_bit, len)); 1072 for(j=0; j<len; j++) { 1073 /* go to the right byte */ 1074 if(flip_bit<8) { 1075 flip_bit = 1 << flip_bit; 1076 1077 if (j < sizeof(unsigned long)) { 1078 ((unsigned char *) &res[count].new)[j] = 1079 (text_read_ub(c) ^ flip_bit); 1080 } 1081 1082 1083 if (injectFault) { 1084 text_write_ub(c, (text_read_ub(c)^flip_bit)); 1085 } 1086 1087 j=len; 1088 } 1089 c++; 1090 flip_bit = flip_bit-8; 1091 } 1092 } else if(faultType==PTR_FAULT) { 1093 /* 5f) ptr: if instruction has regmodrm byte (i_has_modrm), 1094 * flip 1 bit in lower byte (0x0f) or any bit in following 1095 * bytes (sib, imm or disp). 1096 */ 1097 int prefix; 1098 c=(unsigned char *) addr; 1099 do { 1100 switch (text_read_ub(c)) { 1101 case 0x66: case 0x67: case 0x26: case 0x36: 1102 case 0x2e: case 0x3e: case 0x64: case 0x65: 1103 case 0xf0: case 0xf2: case 0xf3: 1104 prefix = 1; 1105 break; 1106 default: 1107 prefix = 0; 1108 break; 1109 } 1110 if (prefix) { 1111 c++; 1112 } 1113 } while (prefix); 1114 if(text_read_ub(c)>=0xd8 && text_read_ub(c)<=0xdf) { 1115 /* don't mess with fp instruction, yet */ 1116 PDEBUG(("floating point instruction, bailing out\n")); 1117 i--; 1118 continue; 1119 } else if(text_read_ub(c)==0x0f) { 1120 c++; 1121 } 1122 if(text_read_ub(c)==0x0f) { 1123 c++; 1124 } 1125 c++; 1126 len = len-((long) c - (long) addr); 1127 flip_bit = random() % (len*8-4); 1128 PDEBUG(("flip bit %d (len=%d) => ", flip_bit, len)); 1129 1130 /* mod/rm byte is special */ 1131 1132 if (flip_bit < 4) { 1133 flip_bit = 1 << flip_bit; 1134 1135 rc = c - (unsigned char *) addr; 1136 if (rc < sizeof(unsigned long)) { 1137 ((unsigned char *) &res[count].new)[rc] = text_read_ub(c) ^ flip_bit; 1138 1139 } 1140 if (injectFault) { 1141 text_write_ub(c, text_read_ub(c)^flip_bit); 1142 } 1143 1144 } 1145 c++; 1146 flip_bit=flip_bit-4; 1147 1148 for(j=1; j<len; j++) { 1149 /* go to the right byte */ 1150 if (flip_bit<8) { 1151 flip_bit = 1 << flip_bit; 1152 1153 rc = (c - (unsigned char *) addr); 1154 if (rc < sizeof(unsigned long)) { 1155 ((unsigned char *) &res[count].new)[rc] = 1156 text_read_ub(c) ^ flip_bit; 1157 1158 } 1159 if (injectFault) { 1160 text_write_ub(c, text_read_ub(c)^flip_bit); 1161 } 1162 1163 j=len; 1164 } 1165 c++; 1166 flip_bit = flip_bit-8; 1167 } 1168 } else if(faultType==LOOP_FAULT) { 1169 c=(unsigned char *) addr; 1170 /* replace rep with repe, and vice versa */ 1171 if(text_read_ub(c)==0xf3) { 1172 if (j < sizeof(unsigned long)) { 1173 ((unsigned char *) &res[count].new)[j] = NOP; 1174 } 1175 1176 rc = (c - (unsigned char *) addr); 1177 if (rc < sizeof(unsigned long)) { 1178 ((unsigned char *) &res[count].new)[rc] = 0xf2; 1179 1180 } 1181 if (injectFault) { 1182 text_write_ub(c, 0xf2); 1183 } 1184 } else if(text_read_ub(c)==0xf2) { 1185 rc = (c - (unsigned char *) addr); 1186 if (rc < sizeof(unsigned long)) { 1187 ((unsigned char *) &res[count].new)[rc] = 0xf3; 1188 1189 } 1190 if (injectFault) { 1191 text_write_ub(c, 0xf3); 1192 } 1193 } else if( (text_read_ub(c)&0xf0)==0x70 ) { 1194 /* if we've jxx imm8 instruction, 1195 * incl even byte instruction, eg jo (70) to jno (71) 1196 * decl odd byte instruction, eg jnle (7f) to jle (7e) 1197 */ 1198 if(text_read_ub(c)%2 == 0) { 1199 rc = (c - (unsigned char *) addr); 1200 if (rc < sizeof(unsigned long)) { 1201 ((unsigned char *) &res[count].new)[rc] = text_read_ub(c) + 1; 1202 1203 } 1204 1205 if (injectFault) { 1206 text_write_ub(c, text_read_ub(c)+1); 1207 } 1208 } else { 1209 1210 rc = (c - (unsigned char *) addr); 1211 if (rc < sizeof(unsigned long)) { 1212 ((unsigned char *) &res[count].new)[rc] = text_read_ub(c) - 1; 1213 1214 } 1215 1216 if (injectFault) { 1217 text_write_ub(c, text_read_ub(c)-1); 1218 } 1219 } 1220 } else if(text_read_ub(c)==0x66 || text_read_ub(c)==0x67) { 1221 /* override prefix */ 1222 c++; 1223 } else if(text_read_ub(c++)==0xf && (text_read_ub(c)&0xf0)==0x80 ) { 1224 /* if we've jxx imm16/32 instruction, 1225 * incl even byte instruction, eg jo (80) to jno (81) 1226 * decl odd byte instruction, eg jnle (8f) to jle (8e) 1227 */ 1228 if(text_read_ub(c)%2 == 0) { 1229 rc = (c - (unsigned char *) addr); 1230 if (rc < sizeof(unsigned long)) { 1231 ((unsigned char *) &res[count].new)[rc] = text_read_ub(c) + 1; 1232 1233 } 1234 if (injectFault) { 1235 text_write_ub(c, text_read_ub(c)+1); 1236 } 1237 } else { 1238 rc = (c - (unsigned char *) addr); 1239 if (rc < sizeof(unsigned long)) { 1240 ((unsigned char *) &res[count].new)[rc] = text_read_ub(c) -1; 1241 1242 } 1243 1244 if (injectFault) { 1245 text_write_ub(c, text_read_ub(c)-1); 1246 } 1247 } 1248 } 1249 1250 } 1251 PDEBUG(("%lx\n", text_read_ul(addr))); 1252 } 1253 return(0); 1254 } 1255 1256 1257 #else /* CONFIG_SWIFI */ 1258 1259 long 1260 sys_inject_fault(char * module_name, 1261 unsigned long argFaultType, 1262 unsigned long argRandomSeed, 1263 unsigned long argNumFaults, 1264 pswifi_result_t result_record, 1265 unsigned long do_inject) 1266 { 1267 return(0); 1268 } 1269 1270 #endif /* CONFIG_SWIFI */ 1271