Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/kernel/exec_domain.c
10814 views
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 ([email protected])
8
*/
9
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>
15
#include <linux/proc_fs.h>
16
#include <linux/sched.h>
17
#include <linux/seq_file.h>
18
#include <linux/syscalls.h>
19
#include <linux/sysctl.h>
20
#include <linux/types.h>
21
#include <linux/fs_struct.h>
22
23
24
static void default_handler(int, struct pt_regs *);
25
26
static struct exec_domain *exec_domains = &default_exec_domain;
27
static DEFINE_RWLOCK(exec_domains_lock);
28
29
30
static unsigned long ident_map[32] = {
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
37
struct 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
47
static void
48
default_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
58
static struct exec_domain *
59
lookup_exec_domain(unsigned int personality)
60
{
61
unsigned int pers = personality(personality);
62
struct exec_domain *ep;
63
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
71
#ifdef CONFIG_MODULES
72
read_unlock(&exec_domains_lock);
73
request_module("personality-%d", pers);
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;
84
out:
85
read_unlock(&exec_domains_lock);
86
return (ep);
87
}
88
89
int
90
register_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
111
out:
112
write_unlock(&exec_domains_lock);
113
return (err);
114
}
115
116
int
117
unregister_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
130
unregister:
131
*epp = ep->next;
132
ep->next = NULL;
133
write_unlock(&exec_domains_lock);
134
return 0;
135
}
136
137
int __set_personality(unsigned int personality)
138
{
139
struct exec_domain *oep = current_thread_info()->exec_domain;
140
141
current_thread_info()->exec_domain = lookup_exec_domain(personality);
142
current->personality = personality;
143
module_put(oep->module);
144
145
return 0;
146
}
147
148
#ifdef CONFIG_PROC_FS
149
static int execdomains_proc_show(struct seq_file *m, void *v)
150
{
151
struct exec_domain *ep;
152
153
read_lock(&exec_domains_lock);
154
for (ep = exec_domains; ep; ep = ep->next)
155
seq_printf(m, "%d-%d\t%-16s\t[%s]\n",
156
ep->pers_low, ep->pers_high, ep->name,
157
module_name(ep->module));
158
read_unlock(&exec_domains_lock);
159
return 0;
160
}
161
162
static int execdomains_proc_open(struct inode *inode, struct file *file)
163
{
164
return single_open(file, execdomains_proc_show, NULL);
165
}
166
167
static const struct file_operations execdomains_proc_fops = {
168
.open = execdomains_proc_open,
169
.read = seq_read,
170
.llseek = seq_lseek,
171
.release = single_release,
172
};
173
174
static int __init proc_execdomains_init(void)
175
{
176
proc_create("execdomains", 0, NULL, &execdomains_proc_fops);
177
return 0;
178
}
179
module_init(proc_execdomains_init);
180
#endif
181
182
SYSCALL_DEFINE1(personality, unsigned int, personality)
183
{
184
unsigned int old = current->personality;
185
186
if (personality != 0xffffffff)
187
set_personality(personality);
188
189
return old;
190
}
191
192
193
EXPORT_SYMBOL(register_exec_domain);
194
EXPORT_SYMBOL(unregister_exec_domain);
195
EXPORT_SYMBOL(__set_personality);
196
197