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
  22
  23static void default_handler(int, struct pt_regs *);
  24
  25static struct exec_domain *exec_domains = &default_exec_domain;
  26static DEFINE_RWLOCK(exec_domains_lock);
  27
  28
  29static u_long ident_map[32] = {
  30        0,      1,      2,      3,      4,      5,      6,      7,
  31        8,      9,      10,     11,     12,     13,     14,     15,
  32        16,     17,     18,     19,     20,     21,     22,     23,
  33        24,     25,     26,     27,     28,     29,     30,     31
  34};
  35
  36struct exec_domain default_exec_domain = {
  37        .name           = "Linux",              /* name */
  38        .handler        = default_handler,      /* lcall7 causes a seg fault. */
  39        .pers_low       = 0,                    /* PER_LINUX personality. */
  40        .pers_high      = 0,                    /* PER_LINUX personality. */
  41        .signal_map     = ident_map,            /* Identity map signals. */
  42        .signal_invmap  = ident_map,            /*  - both ways. */
  43};
  44
  45
  46static void
  47default_handler(int segment, struct pt_regs *regp)
  48{
  49        set_personality(0);
  50
  51        if (current_thread_info()->exec_domain->handler != default_handler)
  52                current_thread_info()->exec_domain->handler(segment, regp);
  53        else
  54                send_sig(SIGSEGV, current, 1);
  55}
  56
  57static struct exec_domain *
  58lookup_exec_domain(u_long personality)
  59{
  60        struct exec_domain *    ep;
  61        u_long                  pers = personality(personality);
  62
  63        read_lock(&exec_domains_lock);
  64        for (ep = exec_domains; ep; ep = ep->next) {
  65                if (pers >= ep->pers_low && pers <= ep->pers_high)
  66                        if (try_module_get(ep->module))
  67                                goto out;
  68        }
  69
  70#ifdef CONFIG_MODULES
  71        read_unlock(&exec_domains_lock);
  72        request_module("personality-%ld", pers);
  73        read_lock(&exec_domains_lock);
  74
  75        for (ep = exec_domains; ep; ep = ep->next) {
  76                if (pers >= ep->pers_low && pers <= ep->pers_high)
  77                        if (try_module_get(ep->module))
  78                                goto out;
  79        }
  80#endif
  81
  82        ep = &default_exec_domain;
  83out:
  84        read_unlock(&exec_domains_lock);
  85        return (ep);
  86}
  87
  88int
  89register_exec_domain(struct exec_domain *ep)
  90{
  91        struct exec_domain      *tmp;
  92        int                     err = -EBUSY;
  93
  94        if (ep == NULL)
  95                return -EINVAL;
  96
  97        if (ep->next != NULL)
  98                return -EBUSY;
  99
 100        write_lock(&exec_domains_lock);
 101        for (tmp = exec_domains; tmp; tmp = tmp->next) {
 102                if (tmp == ep)
 103                        goto out;
 104        }
 105
 106        ep->next = exec_domains;
 107        exec_domains = ep;
 108        err = 0;
 109
 110out:
 111        write_unlock(&exec_domains_lock);
 112        return (err);
 113}
 114
 115int
 116unregister_exec_domain(struct exec_domain *ep)
 117{
 118        struct exec_domain      **epp;
 119
 120        epp = &exec_domains;
 121        write_lock(&exec_domains_lock);
 122        for (epp = &exec_domains; *epp; epp = &(*epp)->next) {
 123                if (ep == *epp)
 124                        goto unregister;
 125        }
 126        write_unlock(&exec_domains_lock);
 127        return -EINVAL;
 128
 129unregister:
 130        *epp = ep->next;
 131        ep->next = NULL;
 132        write_unlock(&exec_domains_lock);
 133        return 0;
 134}
 135
 136int
 137__set_personality(u_long personality)
 138{
 139        struct exec_domain      *ep, *oep;
 140
 141        ep = lookup_exec_domain(personality);
 142        if (ep == current_thread_info()->exec_domain) {
 143                current->personality = personality;
 144                module_put(ep->module);
 145                return 0;
 146        }
 147
 148        if (atomic_read(&current->fs->count) != 1) {
 149                struct fs_struct *fsp, *ofsp;
 150
 151                fsp = copy_fs_struct(current->fs);
 152                if (fsp == NULL) {
 153                        module_put(ep->module);
 154                        return -ENOMEM;
 155                }
 156
 157                task_lock(current);
 158                ofsp = current->fs;
 159                current->fs = fsp;
 160                task_unlock(current);
 161
 162                put_fs_struct(ofsp);
 163        }
 164
 165        /*
 166         * At that point we are guaranteed to be the sole owner of
 167         * current->fs.
 168         */
 169
 170        current->personality = personality;
 171        oep = current_thread_info()->exec_domain;
 172        current_thread_info()->exec_domain = ep;
 173
 174        module_put(oep->module);
 175        return 0;
 176}
 177
 178#ifdef CONFIG_PROC_FS
 179static int execdomains_proc_show(struct seq_file *m, void *v)
 180{
 181        struct exec_domain      *ep;
 182
 183        read_lock(&exec_domains_lock);
 184        for (ep = exec_domains; ep; ep = ep->next)
 185                seq_printf(m, "%d-%d\t%-16s\t[%s]\n",
 186                               ep->pers_low, ep->pers_high, ep->name,
 187                               module_name(ep->module));
 188        read_unlock(&exec_domains_lock);
 189        return 0;
 190}
 191
 192static int execdomains_proc_open(struct inode *inode, struct file *file)
 193{
 194        return single_open(file, execdomains_proc_show, NULL);
 195}
 196
 197static const struct file_operations execdomains_proc_fops = {
 198        .open           = execdomains_proc_open,
 199        .read           = seq_read,
 200        .llseek         = seq_lseek,
 201        .release        = single_release,
 202};
 203
 204static int __init proc_execdomains_init(void)
 205{
 206        proc_create("execdomains", 0, NULL, &execdomains_proc_fops);
 207        return 0;
 208}
 209module_init(proc_execdomains_init);
 210#endif
 211
 212SYSCALL_DEFINE1(personality, u_long, personality)
 213{
 214        u_long old = current->personality;
 215
 216        if (personality != 0xffffffff) {
 217                set_personality(personality);
 218                if (current->personality != personality)
 219                        return -EINVAL;
 220        }
 221
 222        return (long)old;
 223}
 224
 225
 226EXPORT_SYMBOL(register_exec_domain);
 227EXPORT_SYMBOL(unregister_exec_domain);
 228EXPORT_SYMBOL(__set_personality);
 229