The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kernel/exec_domain.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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/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);

Cache object: 4ccf11a6a704d71b89966f4c0824303d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.