linux/arch/x86/ia32/ia32_aout.c
<<
>>
Prefs
   1/*
   2 *  a.out loader for x86-64
   3 *
   4 *  Copyright (C) 1991, 1992, 1996  Linus Torvalds
   5 *  Hacked together by Andi Kleen
   6 */
   7
   8#include <linux/module.h>
   9
  10#include <linux/time.h>
  11#include <linux/kernel.h>
  12#include <linux/mm.h>
  13#include <linux/mman.h>
  14#include <linux/a.out.h>
  15#include <linux/errno.h>
  16#include <linux/signal.h>
  17#include <linux/string.h>
  18#include <linux/fs.h>
  19#include <linux/file.h>
  20#include <linux/stat.h>
  21#include <linux/fcntl.h>
  22#include <linux/ptrace.h>
  23#include <linux/user.h>
  24#include <linux/binfmts.h>
  25#include <linux/personality.h>
  26#include <linux/init.h>
  27#include <linux/jiffies.h>
  28#include <linux/perf_event.h>
  29
  30#include <asm/uaccess.h>
  31#include <asm/pgalloc.h>
  32#include <asm/cacheflush.h>
  33#include <asm/user32.h>
  34#include <asm/ia32.h>
  35
  36#undef WARN_OLD
  37
  38static int load_aout_binary(struct linux_binprm *);
  39static int load_aout_library(struct file *);
  40
  41#ifdef CONFIG_COREDUMP
  42static int aout_core_dump(struct coredump_params *);
  43
  44static unsigned long get_dr(int n)
  45{
  46        struct perf_event *bp = current->thread.ptrace_bps[n];
  47        return bp ? bp->hw.info.address : 0;
  48}
  49
  50/*
  51 * fill in the user structure for a core dump..
  52 */
  53static void dump_thread32(struct pt_regs *regs, struct user32 *dump)
  54{
  55        u32 fs, gs;
  56        memset(dump, 0, sizeof(*dump));
  57
  58/* changed the size calculations - should hopefully work better. lbt */
  59        dump->magic = CMAGIC;
  60        dump->start_code = 0;
  61        dump->start_stack = regs->sp & ~(PAGE_SIZE - 1);
  62        dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
  63        dump->u_dsize = ((unsigned long)
  64                         (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
  65        dump->u_dsize -= dump->u_tsize;
  66        dump->u_debugreg[0] = get_dr(0);
  67        dump->u_debugreg[1] = get_dr(1);
  68        dump->u_debugreg[2] = get_dr(2);
  69        dump->u_debugreg[3] = get_dr(3);
  70        dump->u_debugreg[6] = current->thread.debugreg6;
  71        dump->u_debugreg[7] = current->thread.ptrace_dr7;
  72
  73        if (dump->start_stack < 0xc0000000) {
  74                unsigned long tmp;
  75
  76                tmp = (unsigned long) (0xc0000000 - dump->start_stack);
  77                dump->u_ssize = tmp >> PAGE_SHIFT;
  78        }
  79
  80        dump->regs.ebx = regs->bx;
  81        dump->regs.ecx = regs->cx;
  82        dump->regs.edx = regs->dx;
  83        dump->regs.esi = regs->si;
  84        dump->regs.edi = regs->di;
  85        dump->regs.ebp = regs->bp;
  86        dump->regs.eax = regs->ax;
  87        dump->regs.ds = current->thread.ds;
  88        dump->regs.es = current->thread.es;
  89        savesegment(fs, fs);
  90        dump->regs.fs = fs;
  91        savesegment(gs, gs);
  92        dump->regs.gs = gs;
  93        dump->regs.orig_eax = regs->orig_ax;
  94        dump->regs.eip = regs->ip;
  95        dump->regs.cs = regs->cs;
  96        dump->regs.eflags = regs->flags;
  97        dump->regs.esp = regs->sp;
  98        dump->regs.ss = regs->ss;
  99
 100#if 1 /* FIXME */
 101        dump->u_fpvalid = 0;
 102#else
 103        dump->u_fpvalid = dump_fpu(regs, &dump->i387);
 104#endif
 105}
 106
 107#endif
 108
 109static struct linux_binfmt aout_format = {
 110        .module         = THIS_MODULE,
 111        .load_binary    = load_aout_binary,
 112        .load_shlib     = load_aout_library,
 113#ifdef CONFIG_COREDUMP
 114        .core_dump      = aout_core_dump,
 115#endif
 116        .min_coredump   = PAGE_SIZE
 117};
 118
 119static void set_brk(unsigned long start, unsigned long end)
 120{
 121        start = PAGE_ALIGN(start);
 122        end = PAGE_ALIGN(end);
 123        if (end <= start)
 124                return;
 125        vm_brk(start, end - start);
 126}
 127
 128#ifdef CONFIG_COREDUMP
 129/*
 130 * These are the only things you should do on a core-file: use only these
 131 * macros to write out all the necessary info.
 132 */
 133
 134#include <linux/coredump.h>
 135
 136#define START_DATA(u)   (u.u_tsize << PAGE_SHIFT)
 137#define START_STACK(u)  (u.start_stack)
 138
 139/*
 140 * Routine writes a core dump image in the current directory.
 141 * Currently only a stub-function.
 142 *
 143 * Note that setuid/setgid files won't make a core-dump if the uid/gid
 144 * changed due to the set[u|g]id. It's enforced by the "current->mm->dumpable"
 145 * field, which also makes sure the core-dumps won't be recursive if the
 146 * dumping of the process results in another error..
 147 */
 148
 149static int aout_core_dump(struct coredump_params *cprm)
 150{
 151        mm_segment_t fs;
 152        int has_dumped = 0;
 153        unsigned long dump_start, dump_size;
 154        struct user32 dump;
 155
 156        fs = get_fs();
 157        set_fs(KERNEL_DS);
 158        has_dumped = 1;
 159        strncpy(dump.u_comm, current->comm, sizeof(current->comm));
 160        dump.u_ar0 = offsetof(struct user32, regs);
 161        dump.signal = cprm->siginfo->si_signo;
 162        dump_thread32(cprm->regs, &dump);
 163
 164        /*
 165         * If the size of the dump file exceeds the rlimit, then see
 166         * what would happen if we wrote the stack, but not the data
 167         * area.
 168         */
 169        if ((dump.u_dsize + dump.u_ssize + 1) * PAGE_SIZE > cprm->limit)
 170                dump.u_dsize = 0;
 171
 172        /* Make sure we have enough room to write the stack and data areas. */
 173        if ((dump.u_ssize + 1) * PAGE_SIZE > cprm->limit)
 174                dump.u_ssize = 0;
 175
 176        /* make sure we actually have a data and stack area to dump */
 177        set_fs(USER_DS);
 178        if (!access_ok(VERIFY_READ, (void *) (unsigned long)START_DATA(dump),
 179                       dump.u_dsize << PAGE_SHIFT))
 180                dump.u_dsize = 0;
 181        if (!access_ok(VERIFY_READ, (void *) (unsigned long)START_STACK(dump),
 182                       dump.u_ssize << PAGE_SHIFT))
 183                dump.u_ssize = 0;
 184
 185        set_fs(KERNEL_DS);
 186        /* struct user */
 187        if (!dump_emit(cprm, &dump, sizeof(dump)))
 188                goto end_coredump;
 189        /* Now dump all of the user data.  Include malloced stuff as well */
 190        if (!dump_skip(cprm, PAGE_SIZE - sizeof(dump)))
 191                goto end_coredump;
 192        /* now we start writing out the user space info */
 193        set_fs(USER_DS);
 194        /* Dump the data area */
 195        if (dump.u_dsize != 0) {
 196                dump_start = START_DATA(dump);
 197                dump_size = dump.u_dsize << PAGE_SHIFT;
 198                if (!dump_emit(cprm, (void *)dump_start, dump_size))
 199                        goto end_coredump;
 200        }
 201        /* Now prepare to dump the stack area */
 202        if (dump.u_ssize != 0) {
 203                dump_start = START_STACK(dump);
 204                dump_size = dump.u_ssize << PAGE_SHIFT;
 205                if (!dump_emit(cprm, (void *)dump_start, dump_size))
 206                        goto end_coredump;
 207        }
 208end_coredump:
 209        set_fs(fs);
 210        return has_dumped;
 211}
 212#endif
 213
 214/*
 215 * create_aout_tables() parses the env- and arg-strings in new user
 216 * memory and creates the pointer tables from them, and puts their
 217 * addresses on the "stack", returning the new stack pointer value.
 218 */
 219static u32 __user *create_aout_tables(char __user *p, struct linux_binprm *bprm)
 220{
 221        u32 __user *argv, *envp, *sp;
 222        int argc = bprm->argc, envc = bprm->envc;
 223
 224        sp = (u32 __user *) ((-(unsigned long)sizeof(u32)) & (unsigned long) p);
 225        sp -= envc+1;
 226        envp = sp;
 227        sp -= argc+1;
 228        argv = sp;
 229        put_user((unsigned long) envp, --sp);
 230        put_user((unsigned long) argv, --sp);
 231        put_user(argc, --sp);
 232        current->mm->arg_start = (unsigned long) p;
 233        while (argc-- > 0) {
 234                char c;
 235
 236                put_user((u32)(unsigned long)p, argv++);
 237                do {
 238                        get_user(c, p++);
 239                } while (c);
 240        }
 241        put_user(0, argv);
 242        current->mm->arg_end = current->mm->env_start = (unsigned long) p;
 243        while (envc-- > 0) {
 244                char c;
 245
 246                put_user((u32)(unsigned long)p, envp++);
 247                do {
 248                        get_user(c, p++);
 249                } while (c);
 250        }
 251        put_user(0, envp);
 252        current->mm->env_end = (unsigned long) p;
 253        return sp;
 254}
 255
 256/*
 257 * These are the functions used to load a.out style executables and shared
 258 * libraries.  There is no binary dependent code anywhere else.
 259 */
 260static int load_aout_binary(struct linux_binprm *bprm)
 261{
 262        unsigned long error, fd_offset, rlim;
 263        struct pt_regs *regs = current_pt_regs();
 264        struct exec ex;
 265        int retval;
 266
 267        ex = *((struct exec *) bprm->buf);              /* exec-header */
 268        if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
 269             N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
 270            N_TRSIZE(ex) || N_DRSIZE(ex) ||
 271            i_size_read(file_inode(bprm->file)) <
 272            ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
 273                return -ENOEXEC;
 274        }
 275
 276        fd_offset = N_TXTOFF(ex);
 277
 278        /* Check initial limits. This avoids letting people circumvent
 279         * size limits imposed on them by creating programs with large
 280         * arrays in the data or bss.
 281         */
 282        rlim = rlimit(RLIMIT_DATA);
 283        if (rlim >= RLIM_INFINITY)
 284                rlim = ~0;
 285        if (ex.a_data + ex.a_bss > rlim)
 286                return -ENOMEM;
 287
 288        /* Flush all traces of the currently running executable */
 289        retval = flush_old_exec(bprm);
 290        if (retval)
 291                return retval;
 292
 293        /* OK, This is the point of no return */
 294        set_personality(PER_LINUX);
 295        set_personality_ia32(false);
 296
 297        setup_new_exec(bprm);
 298
 299        regs->cs = __USER32_CS;
 300        regs->r8 = regs->r9 = regs->r10 = regs->r11 = regs->r12 =
 301                regs->r13 = regs->r14 = regs->r15 = 0;
 302
 303        current->mm->end_code = ex.a_text +
 304                (current->mm->start_code = N_TXTADDR(ex));
 305        current->mm->end_data = ex.a_data +
 306                (current->mm->start_data = N_DATADDR(ex));
 307        current->mm->brk = ex.a_bss +
 308                (current->mm->start_brk = N_BSSADDR(ex));
 309
 310        retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT);
 311        if (retval < 0)
 312                return retval;
 313
 314        install_exec_creds(bprm);
 315
 316        if (N_MAGIC(ex) == OMAGIC) {
 317                unsigned long text_addr, map_size;
 318
 319                text_addr = N_TXTADDR(ex);
 320                map_size = ex.a_text+ex.a_data;
 321
 322                error = vm_brk(text_addr & PAGE_MASK, map_size);
 323
 324                if (error != (text_addr & PAGE_MASK))
 325                        return error;
 326
 327                error = read_code(bprm->file, text_addr, 32,
 328                                  ex.a_text + ex.a_data);
 329                if ((signed long)error < 0)
 330                        return error;
 331        } else {
 332#ifdef WARN_OLD
 333                static unsigned long error_time, error_time2;
 334                if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
 335                    (N_MAGIC(ex) != NMAGIC) &&
 336                                time_after(jiffies, error_time2 + 5*HZ)) {
 337                        printk(KERN_NOTICE "executable not page aligned\n");
 338                        error_time2 = jiffies;
 339                }
 340
 341                if ((fd_offset & ~PAGE_MASK) != 0 &&
 342                            time_after(jiffies, error_time + 5*HZ)) {
 343                        printk(KERN_WARNING
 344                               "fd_offset is not page aligned. Please convert "
 345                               "program: %pD\n",
 346                               bprm->file);
 347                        error_time = jiffies;
 348                }
 349#endif
 350
 351                if (!bprm->file->f_op->mmap || (fd_offset & ~PAGE_MASK) != 0) {
 352                        vm_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
 353                        read_code(bprm->file, N_TXTADDR(ex), fd_offset,
 354                                        ex.a_text+ex.a_data);
 355                        goto beyond_if;
 356                }
 357
 358                error = vm_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
 359                                PROT_READ | PROT_EXEC,
 360                                MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE |
 361                                MAP_EXECUTABLE | MAP_32BIT,
 362                                fd_offset);
 363
 364                if (error != N_TXTADDR(ex))
 365                        return error;
 366
 367                error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
 368                                PROT_READ | PROT_WRITE | PROT_EXEC,
 369                                MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE |
 370                                MAP_EXECUTABLE | MAP_32BIT,
 371                                fd_offset + ex.a_text);
 372                if (error != N_DATADDR(ex))
 373                        return error;
 374        }
 375beyond_if:
 376        set_binfmt(&aout_format);
 377
 378        set_brk(current->mm->start_brk, current->mm->brk);
 379
 380        current->mm->start_stack =
 381                (unsigned long)create_aout_tables((char __user *)bprm->p, bprm);
 382        /* start thread */
 383        loadsegment(fs, 0);
 384        loadsegment(ds, __USER32_DS);
 385        loadsegment(es, __USER32_DS);
 386        load_gs_index(0);
 387        (regs)->ip = ex.a_entry;
 388        (regs)->sp = current->mm->start_stack;
 389        (regs)->flags = 0x200;
 390        (regs)->cs = __USER32_CS;
 391        (regs)->ss = __USER32_DS;
 392        regs->r8 = regs->r9 = regs->r10 = regs->r11 =
 393        regs->r12 = regs->r13 = regs->r14 = regs->r15 = 0;
 394        set_fs(USER_DS);
 395        return 0;
 396}
 397
 398static int load_aout_library(struct file *file)
 399{
 400        unsigned long bss, start_addr, len, error;
 401        int retval;
 402        struct exec ex;
 403
 404
 405        retval = -ENOEXEC;
 406        error = kernel_read(file, 0, (char *) &ex, sizeof(ex));
 407        if (error != sizeof(ex))
 408                goto out;
 409
 410        /* We come in here for the regular a.out style of shared libraries */
 411        if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) ||
 412            N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
 413            i_size_read(file_inode(file)) <
 414            ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
 415                goto out;
 416        }
 417
 418        if (N_FLAGS(ex))
 419                goto out;
 420
 421        /* For  QMAGIC, the starting address is 0x20 into the page.  We mask
 422           this off to get the starting address for the page */
 423
 424        start_addr =  ex.a_entry & 0xfffff000;
 425
 426        if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
 427#ifdef WARN_OLD
 428                static unsigned long error_time;
 429                if (time_after(jiffies, error_time + 5*HZ)) {
 430                        printk(KERN_WARNING
 431                               "N_TXTOFF is not page aligned. Please convert "
 432                               "library: %pD\n",
 433                               file);
 434                        error_time = jiffies;
 435                }
 436#endif
 437                vm_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
 438
 439                read_code(file, start_addr, N_TXTOFF(ex),
 440                          ex.a_text + ex.a_data);
 441                retval = 0;
 442                goto out;
 443        }
 444        /* Now use mmap to map the library into memory. */
 445        error = vm_mmap(file, start_addr, ex.a_text + ex.a_data,
 446                        PROT_READ | PROT_WRITE | PROT_EXEC,
 447                        MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_32BIT,
 448                        N_TXTOFF(ex));
 449        retval = error;
 450        if (error != start_addr)
 451                goto out;
 452
 453        len = PAGE_ALIGN(ex.a_text + ex.a_data);
 454        bss = ex.a_text + ex.a_data + ex.a_bss;
 455        if (bss > len) {
 456                error = vm_brk(start_addr + len, bss - len);
 457                retval = error;
 458                if (error != start_addr + len)
 459                        goto out;
 460        }
 461        retval = 0;
 462out:
 463        return retval;
 464}
 465
 466static int __init init_aout_binfmt(void)
 467{
 468        register_binfmt(&aout_format);
 469        return 0;
 470}
 471
 472static void __exit exit_aout_binfmt(void)
 473{
 474        unregister_binfmt(&aout_format);
 475}
 476
 477module_init(init_aout_binfmt);
 478module_exit(exit_aout_binfmt);
 479MODULE_LICENSE("GPL");
 480