xref: /minix/minix/commands/swifi/fault_model.c (revision 83133719)
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