OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [kernel/] [exec_domain.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.