arm: protect state after signal handler
[minix.git] / commands / swifi / fault_model.c
blob98afd115eb49f676c33b3aa48defe886c125c37b
1 /*
2 * fault-model.c -- fault injection code for drivers
4 * Copyright (C) 2003 Mike Swift
5 * Copyright (c) 1999 Wee Teck Ng
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.
17 * Fault injector for testing the usefulness of NOOKS
19 * Adapted from the SWIFI tools used by Wee Teck Ng to evaluate the RIO
20 * file cache at the University of Michigan
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).
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)
41 * - Corruption of stack
42 * - Corruption of heap
43 * - copy overruns
44 * - use after free
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"
63 #include "extra.h"
64 #include <assert.h>
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
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);
89 int *testVA;
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
101 #define inline
103 #ifdef CONFIG_SWIFI
105 #if 0
106 static inline long
107 get_mod_name(const char *user_name, char **buf)
109 unsigned long page;
110 long retval;
112 page = __get_free_page(GFP_KERNEL);
113 if (!page)
114 return -ENOMEM;
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;
122 retval = -ENAMETOOLONG;
123 } else if (!retval)
124 retval = -EINVAL;
126 free_page(page);
127 return retval;
130 static inline void
131 put_mod_name(char *buf)
133 free_page((unsigned long)buf);
135 #endif
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)
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;
155 if (argNumFaults > SWIFI_MAX_FAULTS) {
156 result = -E2BIG;
157 goto Cleanup;
159 res = (pswifi_result_t) malloc((1+argNumFaults) * sizeof(swifi_result_t));
160 if (res == NULL) {
161 result = -ENOMEM;
162 goto Cleanup;
164 memset(res, 0, (1 + argNumFaults) * sizeof(swifi_result_t));
167 // Capture the name of the module from usermode
170 #if 0
171 result = get_mod_name(module_name, &kern_name);
172 if (result < 0) {
173 goto Cleanup;
175 #endif
177 kern_name= module_name;
182 #if 0
183 lock_kernel();
185 for (mod = module_list; mod ; mod = mod->next) {
186 if (strcmp(kern_name, mod->name) == 0) {
187 found = 1;
188 break;
191 unlock_kernel();
192 if (!found) {
193 result = -ENOENT;
194 goto Cleanup;
196 #endif
198 numFaults = argNumFaults;
199 faultType = argFaultType;
200 randomSeed = argRandomSeed;
201 injectFault = argInjectFault;
204 if(faultType>=DISK_TEST) {
205 faultType=faultType-DISK_TEST;
206 diskTest=1;
208 if(faultType==STATS) {
209 #if 0
210 extern long time_vmp, n_vmp;
211 extern long time_pmp, n_pmp;
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));
232 faultInjected=1;
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
243 /* default number of faults is 5 */
244 if(numFaults<=0 || numFaults>100) numFaults=5;
246 switch(faultType)
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:
285 direct_fault(fault_address, fault_data, res);
286 break;
288 case DIRECT_FAULT1:
290 result = direct_fault1(fault_address, fault_data, res);
292 break;
294 /* case PAGE_REG_DUMP: rio_dump(); break; */
295 case WHILE1_FAULT:
298 result = while1();
300 break;
302 /* case CPU_RESET_FAULT: cpu_reset(); break; */;
303 case COW_FAULT:
305 /* test writing to kernel text. freebsd currently do a COW on a
306 * write to kernel text.
308 unsigned long *addr1, *addr2;
310 addr1 = (unsigned long *) 0xf0212000;
311 addr2 = (unsigned long *) 0xf0212010;
312 PDEBUG(("%p=%lx, %p=%lx\n", addr1, *addr1, addr2, *addr2));
314 __asm__ ("movl $0xf0212000, %eax\n\t" \
315 "movl $6, 0(%eax)\n\t" \
316 "movl $6, 4(%eax)\n\t");
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;
328 case DEBUGGER_FAULT:
329 PDEBUG(("Debugger fault"));
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");
335 /* Not implemented on MINIX */
336 assert(0);
337 result = 0;
338 break;
339 default: PDEBUG(("unknown fault type %ld\n", faultType)); break;
341 if (copy_to_user(result_record, res, argNumFaults * sizeof(swifi_result_t))) {
342 result = -EFAULT;
344 Cleanup:
345 #if 0
346 if (kern_name != NULL) {
347 put_mod_name(kern_name);
349 #endif
350 if (res != NULL) {
351 free(res);
354 return (result);
357 int while1(void)
359 int i=0;
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;
368 return(0);
372 int direct_fault(int fault_address, int fault_content, pswifi_result_t res)
374 unsigned long *addr;
375 int flip_bit=0;
378 addr = (unsigned long *) (PAGE_OFFSET + fault_address);
380 PDEBUG(("%p:0x%lx => ", addr, *addr));
382 flip_bit = 1 << fault_content;
384 res[0].address = (unsigned long) addr;
385 res[0].old = *addr;
386 res[0].new = (*addr) ^ flip_bit;
388 if (injectFault) {
389 *addr = (*addr) ^ flip_bit;
391 PDEBUG(("%lx\n", *addr));
392 return(0);
395 int direct_fault1(int fault_address, int fault_content, pswifi_result_t res)
397 unsigned long *addr, data;
400 addr = (unsigned long *) (PAGE_OFFSET + fault_address);
402 PDEBUG(("%p:%lx => ", addr, *addr));
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;
418 res[0].address = (unsigned long) addr;
419 res[0].old = *addr;
420 res[0].new = data;
421 if (injectFault) {
422 *addr = data;
425 PDEBUG(("%lx\n", *addr));
428 return(0);
435 #include <linux/sched.h>
438 #define MAX_NUM_TASKS 20
440 struct task_struct *
441 find_task(void)
443 struct task_struct * task = NULL, *result = NULL ;
444 int i,j;
445 i = 1 + (random() % MAX_NUM_TASKS);
446 j = i;
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;
459 #if 0
460 read_unlock(&tasklist_lock);
461 #endif
462 } while ((i > 0) && (i != j));
464 return(result);
468 stack_fault(pswifi_result_t res)
470 unsigned long *addr, size, taddr;
471 int flip_bit=0;
472 int count=0;
473 struct task_struct *task = NULL;
475 while(count < numFaults) {
476 task = find_task();
477 if (task == NULL) {
478 return(-1);
481 size = (unsigned long) task + TASK_SIZE - task->thread.esp;
483 PDEBUG(("stack range=%lx-%lx\n",
484 (unsigned long) task->thread.esp,
485 (unsigned long) task + TASK_SIZE));
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);
499 PDEBUG(("%lx\n", *addr));
500 count++;
502 return(0);
508 // Instead of dealing with heaps directly, we look at the area cache of pages
509 // and vm pages and find an address there.
513 int heap_fault(pswifi_result_t res)
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;
522 addr = (unsigned long *) (map->address + (random()&~0xf)%map->size);
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;
533 if (injectFault) {
534 *addr = ((*addr)^flip_bit);
536 PDEBUG("%lx\n", *addr);
537 count++;
538 } while (count < numFaults);
539 #endif
540 return(-1);
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))
549 unsigned int prob, i=0;
551 if ( faultInjected && (faultType==BCOPY_FAULT) ) {
553 if (++crashCount == crashInterval) {
555 crashCount=0;
556 prob = random();
557 crashInterval = CRASH_INTERVAL + (random() & FI_MASK);
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;
566 } else { /* corrupt 2-4 pages */
567 i= prob & 0xc00;
568 while(!i) {
569 i = random() & 0xc00;
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;
579 i = 1;
581 return(copy_fn(kaddr, udaddr, len));
582 } else {
583 return(copy_fn(kaddr, udaddr, len));
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))
593 unsigned int prob, i=0;
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);
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;
609 } else {
610 i = prob & 0xc00;
611 while(!i) {
612 i = random() & 0xc00;
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;
622 i=1;
624 return(copy_fn(udaddr, kaddr, len));
625 } else
626 return(copy_fn(udaddr, kaddr, len));
630 unsigned long
631 swifi___generic_copy_from_user (void *kaddr, void *udaddr, unsigned long len)
633 return(do_fault_copy_from_user(kaddr,
634 udaddr,
635 len,
636 __generic_copy_from_user));
639 unsigned long
640 swifi___generic_copy_to_user(void *udaddr, void *kaddr, unsigned long len)
642 return(do_fault_copy_to_user(udaddr,
643 kaddr,
644 len,
645 __generic_copy_to_user));
650 void *
651 swifi_memcpy_fn (void *to, void *from, size_t len)
653 unsigned int prob, i=0;
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);
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;
669 } else { /* corrupt 2-4 pages */
670 i=prob&0xc00;
671 while(!i) {
672 i = random() & 0xc00;
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;
682 return(memcpy(to, from, len));
683 } else
684 return(memcpy(to, from, len));
688 void *
689 swifi_memmove_fn (void *to, void *from, size_t len)
691 unsigned int prob, i=0;
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);
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;
707 } else { /* corrupt 2-4 pages */
708 i=prob&0xc00;
709 while(!i) {
710 i = random() & 0xc00;
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;
720 return(memmove(to, from, len));
721 } else
722 return(memmove(to, from, len));
726 void *
727 memmove_fn(void *to, void *from, size_t len)
729 return(memmove(to, from, len));
734 void *
735 memcpy_fn(void *to, void *from, size_t len)
737 return(memcpy(to, from, len));
743 void
744 do_fault_kfree(void *addr, void (* kfree_fn)(const void *))
746 if(addr == crashAddr) {
747 crashAddr=0;
749 if (faultInjected && (faultType==FREE_FAULT ||
750 faultType==MEM_LEAK_FAULT)) {
751 crashCount++;
752 if(crashCount>=crashInterval) {
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;
769 } else {
770 PDEBUG(("free: don't free %p\n", addr));
771 if(faultInjected++ > numFaults) {
772 faultInjected=0;
774 if(faultType==FREE_FAULT) {
775 crashToggle=1;
777 crashCount=0;
778 crashInterval = CRASH_INTERVAL + (random()&FI_MASK);
781 } else {
782 kfree_fn(addr);
786 #if 0
787 void
788 swifi_kfree(const void *addr)
790 do_fault_kfree((void *) addr, kfree);
792 #endif
795 void do_vfree(const void * addr)
797 vfree((void *) addr);
801 void
802 swifi_vfree(void *addr)
804 do_fault_kfree(addr, do_vfree);
810 void *
811 do_fault_kmalloc(size_t size,
812 int flags,
813 void * (* kmalloc_fn)(size_t size, int flags))
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);
829 return(kmalloc_fn(size, flags));
833 #if 0
834 void *
835 swifi_kmalloc(size_t size, int flags)
837 return(do_fault_kmalloc(size, flags, kmalloc));
839 #endif
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))
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);
863 return(vmalloc_fn(size, gfp_mask, prot));
866 void *
867 swifi___vmalloc(unsigned long size, int gfp_mask, pgprot_t prot)
869 return(do_fault_vmalloc(size, gfp_mask, prot, __vmalloc));
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;
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)
890 section_callback_t * info = (section_callback_t *) token;
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);
898 return(0);
900 #endif
903 int text_fault(char *mod_name, pswifi_result_t res)
905 unsigned long *addr, text_size, offset, page, taddr;
906 unsigned long btext, etext;
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
915 #define MAX_NUM_MODULES 10
917 /* inject faults into text space */
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
926 #if 0
927 info.module_name = module->name;
928 info.module_name = "<module-name>";
929 info.section_name = ".text";
931 kallsyms_sections(&info, text_section_callback);
932 if (info.sec_start == 0 ) {
933 return(-1);
935 #endif
937 load_nlist(mod_name, &btext, &etext);
939 #if 0
940 btext = info.sec_start;
941 etext = info.sec_end;
942 #endif
943 text_size = etext - btext;
945 PDEBUG(("text=%lx-%lx, size=%lx\n", btext, etext, text_size));
947 addr = (unsigned long *)
948 (btext + ((unsigned long) (random()&~0xf) % text_size));
950 /* now the tricky part */
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;
970 printf("len = %d\n", len);
972 PDEBUG(("target addr=%lx, instr addr=%p, %lx=>", taddr, addr,
973 text_read_ul(addr)));
975 offset = (unsigned long) addr&PAGE_MASK;
976 page = (unsigned long) addr&~PAGE_MASK;
978 /* it doesn't matter what we used here to unprotect page,
979 * as this routine will not be in production code.
982 res[count].address = taddr;
983 res[count].old = text_read_ul(addr);
984 res[count].new = text_read_ul(addr);
986 if (faultType==TEXT_FAULT) {
988 flip_bit = random() & 0x1f;
989 PDEBUG(("flip bit %d => ", flip_bit));
990 flip_bit = 1 << flip_bit;
992 res[count].new = text_read_ul(addr) ^ flip_bit;
994 if (injectFault) {
995 text_write_ul(addr, text_read_ul(addr)^flip_bit);
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;
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;
1010 if (injectFault) {
1011 text_write_ub(c, NOP);
1014 c++;
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;
1031 if (prefix) {
1032 c++;
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.
1039 PDEBUG(("floating point instruction, bailing out\n"));
1040 i--;
1041 continue;
1042 } else if(text_read_ub(c)==0x0f) {
1043 c++;
1045 if(text_read_ub(c)==0x0f) {
1046 c++;
1048 c++;
1049 len = len-((long) c - (long) addr);
1050 if (len == 0)
1052 printf("tex_fault: len = %d\n", len);
1053 count--;
1054 continue;
1056 if (len == 0)
1058 int i;
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;
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;
1077 if (j < sizeof(unsigned long)) {
1078 ((unsigned char *) &res[count].new)[j] =
1079 (text_read_ub(c) ^ flip_bit);
1083 if (injectFault) {
1084 text_write_ub(c, (text_read_ub(c)^flip_bit));
1087 j=len;
1089 c++;
1090 flip_bit = flip_bit-8;
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).
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;
1110 if (prefix) {
1111 c++;
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++;
1122 if(text_read_ub(c)==0x0f) {
1123 c++;
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));
1130 /* mod/rm byte is special */
1132 if (flip_bit < 4) {
1133 flip_bit = 1 << flip_bit;
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;
1140 if (injectFault) {
1141 text_write_ub(c, text_read_ub(c)^flip_bit);
1145 c++;
1146 flip_bit=flip_bit-4;
1148 for(j=1; j<len; j++) {
1149 /* go to the right byte */
1150 if (flip_bit<8) {
1151 flip_bit = 1 << flip_bit;
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;
1159 if (injectFault) {
1160 text_write_ub(c, text_read_ub(c)^flip_bit);
1163 j=len;
1165 c++;
1166 flip_bit = flip_bit-8;
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;
1176 rc = (c - (unsigned char *) addr);
1177 if (rc < sizeof(unsigned long)) {
1178 ((unsigned char *) &res[count].new)[rc] = 0xf2;
1181 if (injectFault) {
1182 text_write_ub(c, 0xf2);
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;
1190 if (injectFault) {
1191 text_write_ub(c, 0xf3);
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)
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;
1205 if (injectFault) {
1206 text_write_ub(c, text_read_ub(c)+1);
1208 } else {
1210 rc = (c - (unsigned char *) addr);
1211 if (rc < sizeof(unsigned long)) {
1212 ((unsigned char *) &res[count].new)[rc] = text_read_ub(c) - 1;
1216 if (injectFault) {
1217 text_write_ub(c, text_read_ub(c)-1);
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)
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;
1234 if (injectFault) {
1235 text_write_ub(c, text_read_ub(c)+1);
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;
1244 if (injectFault) {
1245 text_write_ub(c, text_read_ub(c)-1);
1251 PDEBUG(("%lx\n", text_read_ul(addr)));
1253 return(0);
1257 #else /* CONFIG_SWIFI */
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)
1267 return(0);
1270 #endif /* CONFIG_SWIFI */