ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / kernel / exec_domain.c
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
10 #include <linux/config.h>
11 #include <linux/init.h>
12 #include <linux/kernel.h>
13 #include <linux/kmod.h>
14 #include <linux/module.h>
15 #include <linux/personality.h>
16 #include <linux/sched.h>
17 #include <linux/sysctl.h>
18 #include <linux/types.h>
19
20
21 static void default_handler(int, struct pt_regs *);
22
23 static struct exec_domain *exec_domains = &default_exec_domain;
24 static rwlock_t exec_domains_lock = RW_LOCK_UNLOCKED;
25
26
27 static u_long ident_map[32] = {
28         0,      1,      2,      3,      4,      5,      6,      7,
29         8,      9,      10,     11,     12,     13,     14,     15,
30         16,     17,     18,     19,     20,     21,     22,     23,
31         24,     25,     26,     27,     28,     29,     30,     31
32 };
33
34 struct exec_domain default_exec_domain = {
35         .name           = "Linux",              /* name */
36         .handler        = default_handler,      /* lcall7 causes a seg fault. */
37         .pers_low       = 0,                    /* PER_LINUX personality. */
38         .pers_high      = 0,                    /* PER_LINUX personality. */
39         .signal_map     = ident_map,            /* Identity map signals. */
40         .signal_invmap  = ident_map,            /*  - both ways. */
41 };
42
43
44 static void
45 default_handler(int segment, struct pt_regs *regp)
46 {
47         u_long                  pers = 0;
48
49         /*
50          * This may have been a static linked SVr4 binary, so we would
51          * have the personality set incorrectly. Or it might have been
52          * a Solaris/x86 binary. We can tell which because the former
53          * uses lcall7, while the latter used lcall 0x27.
54          * Try to find or load the appropriate personality, and fall back
55          * to just forcing a SEGV.
56          *
57          * XXX: this is IA32-specific and should be moved to the MD-tree.
58          */
59         switch (segment) {
60 #ifdef __i386__
61         case 0x07:
62                 pers = abi_defhandler_lcall7;
63                 break;
64         case 0x27:
65                 pers = PER_SOLARIS;
66                 break;
67 #endif
68         }
69         set_personality(pers);
70
71         if (current_thread_info()->exec_domain->handler != default_handler)
72                 current_thread_info()->exec_domain->handler(segment, regp);
73         else
74                 send_sig(SIGSEGV, current, 1);
75 }
76
77 static struct exec_domain *
78 lookup_exec_domain(u_long personality)
79 {
80         struct exec_domain *    ep;
81         u_long                  pers = personality(personality);
82                 
83         read_lock(&exec_domains_lock);
84         for (ep = exec_domains; ep; ep = ep->next) {
85                 if (pers >= ep->pers_low && pers <= ep->pers_high)
86                         if (try_module_get(ep->module))
87                                 goto out;
88         }
89
90 #ifdef CONFIG_KMOD
91         read_unlock(&exec_domains_lock);
92         request_module("personality-%ld", pers);
93         read_lock(&exec_domains_lock);
94
95         for (ep = exec_domains; ep; ep = ep->next) {
96                 if (pers >= ep->pers_low && pers <= ep->pers_high)
97                         if (try_module_get(ep->module))
98                                 goto out;
99         }
100 #endif
101
102         ep = &default_exec_domain;
103 out:
104         read_unlock(&exec_domains_lock);
105         return (ep);
106 }
107
108 int
109 register_exec_domain(struct exec_domain *ep)
110 {
111         struct exec_domain      *tmp;
112         int                     err = -EBUSY;
113
114         if (ep == NULL)
115                 return -EINVAL;
116
117         if (ep->next != NULL)
118                 return -EBUSY;
119
120         write_lock(&exec_domains_lock);
121         for (tmp = exec_domains; tmp; tmp = tmp->next) {
122                 if (tmp == ep)
123                         goto out;
124         }
125
126         ep->next = exec_domains;
127         exec_domains = ep;
128         err = 0;
129
130 out:
131         write_unlock(&exec_domains_lock);
132         return (err);
133 }
134
135 int
136 unregister_exec_domain(struct exec_domain *ep)
137 {
138         struct exec_domain      **epp;
139
140         epp = &exec_domains;
141         write_lock(&exec_domains_lock);
142         for (epp = &exec_domains; *epp; epp = &(*epp)->next) {
143                 if (ep == *epp)
144                         goto unregister;
145         }
146         write_unlock(&exec_domains_lock);
147         return -EINVAL;
148
149 unregister:
150         *epp = ep->next;
151         ep->next = NULL;
152         write_unlock(&exec_domains_lock);
153         return 0;
154 }
155
156 int
157 __set_personality(u_long personality)
158 {
159         struct exec_domain      *ep, *oep;
160
161         ep = lookup_exec_domain(personality);
162         if (ep == current_thread_info()->exec_domain) {
163                 current->personality = personality;
164                 return 0;
165         }
166
167         if (atomic_read(&current->fs->count) != 1) {
168                 struct fs_struct *fsp, *ofsp;
169
170                 fsp = copy_fs_struct(current->fs);
171                 if (fsp == NULL) {
172                         module_put(ep->module);
173                         return -ENOMEM;
174                 }
175
176                 task_lock(current);
177                 ofsp = current->fs;
178                 current->fs = fsp;
179                 task_unlock(current);
180
181                 put_fs_struct(ofsp);
182         }
183
184         /*
185          * At that point we are guaranteed to be the sole owner of
186          * current->fs.
187          */
188
189         current->personality = personality;
190         oep = current_thread_info()->exec_domain;
191         current_thread_info()->exec_domain = ep;
192         set_fs_altroot();
193
194         module_put(oep->module);
195         return 0;
196 }
197
198 int
199 get_exec_domain_list(char *page)
200 {
201         struct exec_domain      *ep;
202         int                     len = 0;
203
204         read_lock(&exec_domains_lock);
205         for (ep = exec_domains; ep && len < PAGE_SIZE - 80; ep = ep->next)
206                 len += sprintf(page + len, "%d-%d\t%-16s\t[%s]\n",
207                                ep->pers_low, ep->pers_high, ep->name,
208                                module_name(ep->module));
209         read_unlock(&exec_domains_lock);
210         return (len);
211 }
212
213 asmlinkage long
214 sys_personality(u_long personality)
215 {
216         u_long old = current->personality;
217
218         if (personality != 0xffffffff) {
219                 set_personality(personality);
220                 if (current->personality != personality)
221                         return -EINVAL;
222         }
223
224         return (long)old;
225 }
226
227
228 EXPORT_SYMBOL(register_exec_domain);
229 EXPORT_SYMBOL(unregister_exec_domain);
230 EXPORT_SYMBOL(__set_personality);
231
232 /*
233  * We have to have all sysctl handling for the Linux-ABI
234  * in one place as the dynamic registration of sysctls is
235  * horribly crufty in Linux <= 2.4.
236  *
237  * I hope the new sysctl schemes discussed for future versions
238  * will obsolete this.
239  *
240  *                              --hch
241  */
242
243 u_long abi_defhandler_coff = PER_SCOSVR3;
244 u_long abi_defhandler_elf = PER_LINUX;
245 u_long abi_defhandler_lcall7 = PER_SVR4;
246 u_long abi_defhandler_libcso = PER_SVR4;
247 u_int abi_traceflg;
248 int abi_fake_utsname;
249
250 static struct ctl_table abi_table[] = {
251         {
252                 .ctl_name       = ABI_DEFHANDLER_COFF,
253                 .procname       = "defhandler_coff",
254                 .data           = &abi_defhandler_coff,
255                 .maxlen         = sizeof(int),
256                 .mode           = 0644,
257                 .proc_handler   = &proc_doulongvec_minmax,
258         },
259         {
260                 .ctl_name       = ABI_DEFHANDLER_ELF,
261                 .procname       = "defhandler_elf",
262                 .data           = &abi_defhandler_elf,
263                 .maxlen         = sizeof(int),
264                 .mode           = 0644,
265                 .proc_handler   = &proc_doulongvec_minmax,
266         },
267         {
268                 .ctl_name       = ABI_DEFHANDLER_LCALL7,
269                 .procname       = "defhandler_lcall7",
270                 .data           = &abi_defhandler_lcall7,
271                 .maxlen         = sizeof(int),
272                 .mode           = 0644,
273                 .proc_handler   = &proc_doulongvec_minmax,
274         },
275         {
276                 .ctl_name       = ABI_DEFHANDLER_LIBCSO,
277                 .procname       = "defhandler_libcso",
278                 .data           = &abi_defhandler_libcso,
279                 .maxlen         = sizeof(int),
280                 .mode           = 0644,
281                 .proc_handler   = &proc_doulongvec_minmax,
282         },
283         {
284                 .ctl_name       = ABI_TRACE,
285                 .procname       = "trace",
286                 .data           = &abi_traceflg,
287                 .maxlen         = sizeof(u_int),
288                 .mode           = 0644,
289                 .proc_handler   = &proc_dointvec,
290         },
291         {
292                 .ctl_name       = ABI_FAKE_UTSNAME,
293                 .procname       = "fake_utsname",
294                 .data           = &abi_fake_utsname,
295                 .maxlen         = sizeof(int),
296                 .mode           = 0644,
297                 .proc_handler   = &proc_dointvec,
298         },
299         { .ctl_name = 0 }
300 };
301
302 static struct ctl_table abi_root_table[] = {
303         {
304                 .ctl_name       = CTL_ABI,
305                 .procname       = "abi",
306                 .mode           = 0555,
307                 .child          = abi_table,
308         },
309         { .ctl_name = 0 }
310 };
311
312 static int __init
313 abi_register_sysctl(void)
314 {
315         register_sysctl_table(abi_root_table, 1);
316         return 0;
317 }
318
319 __initcall(abi_register_sysctl);
320
321
322 EXPORT_SYMBOL(abi_defhandler_coff);
323 EXPORT_SYMBOL(abi_defhandler_elf);
324 EXPORT_SYMBOL(abi_defhandler_lcall7);
325 EXPORT_SYMBOL(abi_defhandler_libcso);
326 EXPORT_SYMBOL(abi_traceflg);
327 EXPORT_SYMBOL(abi_fake_utsname);