ia64: Remove Linux/x86 exec domain support
[linux-2.6-block.git] / kernel / exec_domain.c
CommitLineData
1da177e4
LT
1/*
2 * Handling of different ABIs (personalities).
3 *
4 * We group personalities into execution domains which have their
5 * own handlers for kernel entry points, signal mapping, etc...
6 *
7 * 2001-05-06 Complete rewrite, Christoph Hellwig (hch@infradead.org)
8 */
9
1da177e4
LT
10#include <linux/init.h>
11#include <linux/kernel.h>
12#include <linux/kmod.h>
13#include <linux/module.h>
14#include <linux/personality.h>
6e62775e 15#include <linux/proc_fs.h>
1da177e4 16#include <linux/sched.h>
6e62775e 17#include <linux/seq_file.h>
1da177e4
LT
18#include <linux/syscalls.h>
19#include <linux/sysctl.h>
20#include <linux/types.h>
5ad4e53b 21#include <linux/fs_struct.h>
1da177e4
LT
22
23
24static void default_handler(int, struct pt_regs *);
25
26static struct exec_domain *exec_domains = &default_exec_domain;
27static DEFINE_RWLOCK(exec_domains_lock);
28
29
485d5276 30static unsigned long ident_map[32] = {
1da177e4
LT
31 0, 1, 2, 3, 4, 5, 6, 7,
32 8, 9, 10, 11, 12, 13, 14, 15,
33 16, 17, 18, 19, 20, 21, 22, 23,
34 24, 25, 26, 27, 28, 29, 30, 31
35};
36
37struct exec_domain default_exec_domain = {
38 .name = "Linux", /* name */
39 .handler = default_handler, /* lcall7 causes a seg fault. */
b9e5db6d 40 .pers_low = 0, /* PER_LINUX personality. */
1da177e4
LT
41 .pers_high = 0, /* PER_LINUX personality. */
42 .signal_map = ident_map, /* Identity map signals. */
43 .signal_invmap = ident_map, /* - both ways. */
44};
45
46
47static void
48default_handler(int segment, struct pt_regs *regp)
49{
50 set_personality(0);
51
52 if (current_thread_info()->exec_domain->handler != default_handler)
53 current_thread_info()->exec_domain->handler(segment, regp);
54 else
55 send_sig(SIGSEGV, current, 1);
56}
57
58static struct exec_domain *
485d5276 59lookup_exec_domain(unsigned int personality)
1da177e4 60{
485d5276
ON
61 unsigned int pers = personality(personality);
62 struct exec_domain *ep;
62769dce 63
1da177e4
LT
64 read_lock(&exec_domains_lock);
65 for (ep = exec_domains; ep; ep = ep->next) {
66 if (pers >= ep->pers_low && pers <= ep->pers_high)
67 if (try_module_get(ep->module))
68 goto out;
69 }
70
a1ef5adb 71#ifdef CONFIG_MODULES
1da177e4 72 read_unlock(&exec_domains_lock);
485d5276 73 request_module("personality-%d", pers);
1da177e4
LT
74 read_lock(&exec_domains_lock);
75
76 for (ep = exec_domains; ep; ep = ep->next) {
77 if (pers >= ep->pers_low && pers <= ep->pers_high)
78 if (try_module_get(ep->module))
79 goto out;
80 }
81#endif
82
83 ep = &default_exec_domain;
84out:
85 read_unlock(&exec_domains_lock);
b9e5db6d 86 return ep;
1da177e4
LT
87}
88
89int
90register_exec_domain(struct exec_domain *ep)
91{
92 struct exec_domain *tmp;
93 int err = -EBUSY;
94
95 if (ep == NULL)
96 return -EINVAL;
97
98 if (ep->next != NULL)
99 return -EBUSY;
100
101 write_lock(&exec_domains_lock);
102 for (tmp = exec_domains; tmp; tmp = tmp->next) {
103 if (tmp == ep)
104 goto out;
105 }
106
107 ep->next = exec_domains;
108 exec_domains = ep;
109 err = 0;
110
111out:
112 write_unlock(&exec_domains_lock);
b9e5db6d 113 return err;
1da177e4 114}
b9e5db6d 115EXPORT_SYMBOL(register_exec_domain);
1da177e4
LT
116
117int
118unregister_exec_domain(struct exec_domain *ep)
119{
120 struct exec_domain **epp;
121
122 epp = &exec_domains;
123 write_lock(&exec_domains_lock);
124 for (epp = &exec_domains; *epp; epp = &(*epp)->next) {
125 if (ep == *epp)
126 goto unregister;
127 }
128 write_unlock(&exec_domains_lock);
129 return -EINVAL;
130
131unregister:
132 *epp = ep->next;
133 ep->next = NULL;
134 write_unlock(&exec_domains_lock);
135 return 0;
136}
b9e5db6d 137EXPORT_SYMBOL(unregister_exec_domain);
1da177e4 138
2ee7c922 139int __set_personality(unsigned int personality)
1da177e4 140{
2ee7c922 141 struct exec_domain *oep = current_thread_info()->exec_domain;
1da177e4 142
2ee7c922 143 current_thread_info()->exec_domain = lookup_exec_domain(personality);
1da177e4 144 current->personality = personality;
1da177e4 145 module_put(oep->module);
2ee7c922 146
1da177e4
LT
147 return 0;
148}
b9e5db6d 149EXPORT_SYMBOL(__set_personality);
1da177e4 150
6e62775e
AD
151#ifdef CONFIG_PROC_FS
152static int execdomains_proc_show(struct seq_file *m, void *v)
1da177e4
LT
153{
154 struct exec_domain *ep;
1da177e4
LT
155
156 read_lock(&exec_domains_lock);
6e62775e
AD
157 for (ep = exec_domains; ep; ep = ep->next)
158 seq_printf(m, "%d-%d\t%-16s\t[%s]\n",
1da177e4
LT
159 ep->pers_low, ep->pers_high, ep->name,
160 module_name(ep->module));
161 read_unlock(&exec_domains_lock);
6e62775e
AD
162 return 0;
163}
164
165static int execdomains_proc_open(struct inode *inode, struct file *file)
166{
167 return single_open(file, execdomains_proc_show, NULL);
168}
169
170static const struct file_operations execdomains_proc_fops = {
171 .open = execdomains_proc_open,
172 .read = seq_read,
173 .llseek = seq_lseek,
174 .release = single_release,
175};
176
177static int __init proc_execdomains_init(void)
178{
179 proc_create("execdomains", 0, NULL, &execdomains_proc_fops);
180 return 0;
1da177e4 181}
6e62775e
AD
182module_init(proc_execdomains_init);
183#endif
1da177e4 184
485d5276 185SYSCALL_DEFINE1(personality, unsigned int, personality)
1da177e4 186{
485d5276 187 unsigned int old = current->personality;
1da177e4 188
2ee7c922 189 if (personality != 0xffffffff)
1da177e4 190 set_personality(personality);
1da177e4 191
485d5276 192 return old;
1da177e4 193}