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 u_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(u_long personality)
  60{
  61        struct exec_domain *    ep;
  62        u_long                  pers = personality(personality);
  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-%ld", 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
 138__set_personality(u_long personality)
 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;
 145                module_put(ep->module);
 146                return 0;
 147        }
 148
 149        current->personality = personality;
 150        oep = current_thread_info()->exec_domain;
 151        current_thread_info()->exec_domain = ep;
 152
 153        module_put(oep->module);
 154        return 0;
 155}
 156
 157#ifdef CONFIG_PROC_FS
 158static int execdomains_proc_show(struct seq_file *m, void *v)
 159{
 160        struct exec_domain      *ep;
 161
 162        read_lock(&exec_domains_lock);
 163        for (ep = exec_domains; ep; ep = ep->next)
 164                seq_printf(m, "%d-%d\t%-16s\t[%s]\n",
 165                               ep->pers_low, ep->pers_high, ep->name,
 166                               module_name(ep->module));
 167        read_unlock(&exec_domains_lock);
 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;
 187}
 188module_init(proc_execdomains_init);
 189#endif
 190
 191SYSCALL_DEFINE1(personality, u_long, personality)
 192{
 193        u_long old = current->personality;
 194
 195        if (personality != 0xffffffff) {
 196                set_personality(personality);
 197                if (current->personality != personality)
 198                        return -EINVAL;
 199        }
 200
 201        return (long)old;
 202}
 203
 204
 205EXPORT_SYMBOL(register_exec_domain);
 206EXPORT_SYMBOL(unregister_exec_domain);
 207EXPORT_SYMBOL(__set_personality);
 208