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}
 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 __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
 149static 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
 162static int execdomains_proc_open(struct inode *inode, struct file *file)
 163{
 164        return single_open(file, execdomains_proc_show, NULL);
 165}
 166
 167static 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
 174static int __init proc_execdomains_init(void)
 175{
 176        proc_create("execdomains", 0, NULL, &execdomains_proc_fops);
 177        return 0;
 178}
 179module_init(proc_execdomains_init);
 180#endif
 181
 182SYSCALL_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
 193EXPORT_SYMBOL(register_exec_domain);
 194EXPORT_SYMBOL(unregister_exec_domain);
 195EXPORT_SYMBOL(__set_personality);
 196