linux/kernel/exec_domain.c
<<
>>
Prefs
   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/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
  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
  30static 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
  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 *
  59lookup_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;
  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}
 115EXPORT_SYMBOL(register_exec_domain);
 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}
 137EXPORT_SYMBOL(unregister_exec_domain);
 138
 139int __set_personality(unsigned int personality)
 140{
 141        struct exec_domain *oep = current_thread_info()->exec_domain;
 142
 143        current_thread_info()->exec_domain = lookup_exec_domain(personality);
 144        current->personality = personality;
 145        module_put(oep->module);
 146
 147        return 0;
 148}
 149EXPORT_SYMBOL(__set_personality);
 150
 151#ifdef CONFIG_PROC_FS
 152static int execdomains_proc_show(struct seq_file *m, void *v)
 153{
 154        struct exec_domain      *ep;
 155
 156        read_lock(&exec_domains_lock);
 157        for (ep = exec_domains; ep; ep = ep->next)
 158                seq_printf(m, "%d-%d\t%-16s\t[%s]\n",
 159                               ep->pers_low, ep->pers_high, ep->name,
 160                               module_name(ep->module));
 161        read_unlock(&exec_domains_lock);
 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;
 181}
 182module_init(proc_execdomains_init);
 183#endif
 184
 185SYSCALL_DEFINE1(personality, unsigned int, personality)
 186{
 187        unsigned int old = current->personality;
 188
 189        if (personality != 0xffffffff)
 190                set_personality(personality);
 191
 192        return old;
 193}
 194