Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | #include <linux/mm.h> #include <linux/smp_lock.h> #include <linux/module.h> static asmlinkage void no_lcall7(struct pt_regs * regs); static unsigned long ident_map[32] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }; struct exec_domain default_exec_domain = { "Linux", /* name */ no_lcall7, /* lcall7 causes a seg fault. */ 0, 0xff, /* All personalities. */ ident_map, /* Identity map signals. */ ident_map, /* - both ways. */ NULL, /* No usage counter. */ NULL /* Nothing after this in the list. */ }; static struct exec_domain *exec_domains = &default_exec_domain; static asmlinkage void no_lcall7(struct pt_regs * regs) { /* * This may have been a static linked SVr4 binary, so we would have the * personality set incorrectly. Check to see whether SVr4 is available, * and use it, otherwise give the user a SEGV. */ if (current->exec_domain && current->exec_domain->module) __MOD_DEC_USE_COUNT(current->exec_domain->module); current->personality = PER_SVR4; current->exec_domain = lookup_exec_domain(current->personality); if (current->exec_domain && current->exec_domain->module) __MOD_INC_USE_COUNT(current->exec_domain->module); if (current->exec_domain && current->exec_domain->handler && current->exec_domain->handler != no_lcall7) { current->exec_domain->handler(regs); return; } send_sig(SIGSEGV, current, 1); } struct exec_domain *lookup_exec_domain(unsigned long personality) { unsigned long pers = personality & PER_MASK; struct exec_domain *it; for (it=exec_domains; it; it=it->next) if (pers >= it->pers_low && pers <= it->pers_high) return it; /* Should never get this far. */ printk(KERN_ERR "No execution domain for personality 0x%02lx\n", pers); return NULL; } int register_exec_domain(struct exec_domain *it) { struct exec_domain *tmp; if (!it) return -EINVAL; if (it->next) return -EBUSY; for (tmp=exec_domains; tmp; tmp=tmp->next) if (tmp == it) return -EBUSY; it->next = exec_domains; exec_domains = it; return 0; } int unregister_exec_domain(struct exec_domain *it) { struct exec_domain ** tmp; tmp = &exec_domains; while (*tmp) { if (it == *tmp) { *tmp = it->next; it->next = NULL; return 0; } tmp = &(*tmp)->next; } return -EINVAL; } asmlinkage long sys_personality(unsigned long personality) { struct exec_domain *it; unsigned long old_personality; int ret; lock_kernel(); ret = current->personality; if (personality == 0xffffffff) goto out; ret = -EINVAL; it = lookup_exec_domain(personality); if (!it) goto out; old_personality = current->personality; if (current->exec_domain && current->exec_domain->module) __MOD_DEC_USE_COUNT(current->exec_domain->module); current->personality = personality; current->exec_domain = it; if (current->exec_domain->module) __MOD_INC_USE_COUNT(current->exec_domain->module); ret = old_personality; out: unlock_kernel(); return ret; } |