]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - kernel/exec_domain.c
drivers/misc: support for the pressure sensor BMP085 from Bosch Sensortec
[mirror_ubuntu-bionic-kernel.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. */
40 .pers_low = 0, /* PER_LINUX personality. */
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);
86 return (ep);
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);
113 return (err);
114}
115
116int
117unregister_exec_domain(struct exec_domain *ep)
118{
119 struct exec_domain **epp;
120
121 epp = &exec_domains;
122 write_lock(&exec_domains_lock);
123 for (epp = &exec_domains; *epp; epp = &(*epp)->next) {
124 if (ep == *epp)
125 goto unregister;
126 }
127 write_unlock(&exec_domains_lock);
128 return -EINVAL;
129
130unregister:
131 *epp = ep->next;
132 ep->next = NULL;
133 write_unlock(&exec_domains_lock);
134 return 0;
135}
136
137int
485d5276 138__set_personality(unsigned int personality)
1da177e4
LT
139{
140 struct exec_domain *ep, *oep;
141
142 ep = lookup_exec_domain(personality);
143 if (ep == current_thread_info()->exec_domain) {
144 current->personality = personality;
6a4d11c2 145 module_put(ep->module);
1da177e4
LT
146 return 0;
147 }
148
1da177e4
LT
149 current->personality = personality;
150 oep = current_thread_info()->exec_domain;
151 current_thread_info()->exec_domain = ep;
1da177e4
LT
152
153 module_put(oep->module);
154 return 0;
155}
156
6e62775e
AD
157#ifdef CONFIG_PROC_FS
158static int execdomains_proc_show(struct seq_file *m, void *v)
1da177e4
LT
159{
160 struct exec_domain *ep;
1da177e4
LT
161
162 read_lock(&exec_domains_lock);
6e62775e
AD
163 for (ep = exec_domains; ep; ep = ep->next)
164 seq_printf(m, "%d-%d\t%-16s\t[%s]\n",
1da177e4
LT
165 ep->pers_low, ep->pers_high, ep->name,
166 module_name(ep->module));
167 read_unlock(&exec_domains_lock);
6e62775e
AD
168 return 0;
169}
170
171static int execdomains_proc_open(struct inode *inode, struct file *file)
172{
173 return single_open(file, execdomains_proc_show, NULL);
174}
175
176static const struct file_operations execdomains_proc_fops = {
177 .open = execdomains_proc_open,
178 .read = seq_read,
179 .llseek = seq_lseek,
180 .release = single_release,
181};
182
183static int __init proc_execdomains_init(void)
184{
185 proc_create("execdomains", 0, NULL, &execdomains_proc_fops);
186 return 0;
1da177e4 187}
6e62775e
AD
188module_init(proc_execdomains_init);
189#endif
1da177e4 190
485d5276 191SYSCALL_DEFINE1(personality, unsigned int, personality)
1da177e4 192{
485d5276 193 unsigned int old = current->personality;
1da177e4
LT
194
195 if (personality != 0xffffffff) {
196 set_personality(personality);
197 if (current->personality != personality)
198 return -EINVAL;
199 }
200
485d5276 201 return old;
1da177e4
LT
202}
203
204
205EXPORT_SYMBOL(register_exec_domain);
206EXPORT_SYMBOL(unregister_exec_domain);
207EXPORT_SYMBOL(__set_personality);