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                /* Someone check-me: is this error path enough? */
 313                send_sig(SIGKILL, current, 0);
 314                return retval;
 315        }
 316
 317        install_exec_creds(bprm);
 318
 319        if (N_MAGIC(ex) == OMAGIC) {
 320                unsigned long text_addr, map_size;
 321
 322                text_addr = N_TXTADDR(ex);
 323                map_size = ex.a_text+ex.a_data;
 324
 325                error = vm_brk(text_addr & PAGE_MASK, map_size);
 326
 327                if (error != (text_addr & PAGE_MASK)) {
 328                        send_sig(SIGKILL, current, 0);
 329                        return error;
 330                }
 331
 332                error = read_code(bprm->file, text_addr, 32,
 333                                  ex.a_text + ex.a_data);
 334                if ((signed long)error < 0) {
 335                        send_sig(SIGKILL, current, 0);
 336                        return error;
 337                }
 338        } else {
 339#ifdef WARN_OLD
 340                static unsigned long error_time, error_time2;
 341                if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
 342                    (N_MAGIC(ex) != NMAGIC) &&
 343                                time_after(jiffies, error_time2 + 5*HZ)) {
 344                        printk(KERN_NOTICE "executable not page aligned\n");
 345                        error_time2 = jiffies;
 346                }
 347
 348                if ((fd_offset & ~PAGE_MASK) != 0 &&
 349                            time_after(jiffies, error_time + 5*HZ)) {
 350                        printk(KERN_WARNING
 351                               "fd_offset is not page aligned. Please convert "
 352                               "program: %s\n",
 353                               bprm->file->f_path.dentry->d_name.name);
 354                        error_time = jiffies;
 355                }
 356#endif
 357
 358                if (!bprm->file->f_op->mmap || (fd_offset & ~PAGE_MASK) != 0) {
 359                        vm_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
 360                        read_code(bprm->file, N_TXTADDR(ex), fd_offset,
 361                                        ex.a_text+ex.a_data);
 362                        goto beyond_if;
 363                }
 364
 365                error = vm_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
 366                                PROT_READ | PROT_EXEC,
 367                                MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE |
 368                                MAP_EXECUTABLE | MAP_32BIT,
 369                                fd_offset);
 370
 371                if (error != N_TXTADDR(ex)) {
 372                        send_sig(SIGKILL, current, 0);
 373                        return error;
 374                }
 375
 376                error = vm_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
 377                                PROT_READ | PROT_WRITE | PROT_EXEC,
 378                                MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE |
 379                                MAP_EXECUTABLE | MAP_32BIT,
 380                                fd_offset + ex.a_text);
 381                if (error != N_DATADDR(ex)) {
 382                        send_sig(SIGKILL, current, 0);
 383                        return error;
 384                }
 385        }
 386beyond_if:
 387        set_binfmt(&aout_format);
 388
 389        set_brk(current->mm->start_brk, current->mm->brk);
 390
 391        current->mm->start_stack =
 392                (unsigned long)create_aout_tables((char __user *)bprm->p, bprm);
 393        /* start thread */
 394        loadsegment(fs, 0);
 395        loadsegment(ds, __USER32_DS);
 396        loadsegment(es, __USER32_DS);
 397        load_gs_index(0);
 398        (regs)->ip = ex.a_entry;
 399        (regs)->sp = current->mm->start_stack;
 400        (regs)->flags = 0x200;
 401        (regs)->cs = __USER32_CS;
 402        (regs)->ss = __USER32_DS;
 403        regs->r8 = regs->r9 = regs->r10 = regs->r11 =
 404        regs->r12 = regs->r13 = regs->r14 = regs->r15 = 0;
 405        set_fs(USER_DS);
 406        return 0;
 407}
 408
 409static int load_aout_library(struct file *file)
 410{
 411        unsigned long bss, start_addr, len, error;
 412        int retval;
 413        struct exec ex;
 414
 415
 416        retval = -ENOEXEC;
 417        error = kernel_read(file, 0, (char *) &ex, sizeof(ex));
 418        if (error != sizeof(ex))
 419                goto out;
 420
 421        /* We come in here for the regular a.out style of shared libraries */
 422        if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) ||
 423            N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
 424            i_size_read(file_inode(file)) <
 425            ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
 426                goto out;
 427        }
 428
 429        if (N_FLAGS(ex))
 430                goto out;
 431
 432        /* For  QMAGIC, the starting address is 0x20 into the page.  We mask
 433           this off to get the starting address for the page */
 434
 435        start_addr =  ex.a_entry & 0xfffff000;
 436
 437        if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
 438#ifdef WARN_OLD
 439                static unsigned long error_time;
 440                if (time_after(jiffies, error_time + 5*HZ)) {
 441                        printk(KERN_WARNING
 442                               "N_TXTOFF is not page aligned. Please convert "
 443                               "library: %s\n",
 444                               file->f_path.dentry->d_name.name);
 445                        error_time = jiffies;
 446                }
 447#endif
 448                vm_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
 449
 450                read_code(file, start_addr, N_TXTOFF(ex),
 451                          ex.a_text + ex.a_data);
 452                retval = 0;
 453                goto out;
 454        }
 455        /* Now use mmap to map the library into memory. */
 456        error = vm_mmap(file, start_addr, ex.a_text + ex.a_data,
 457                        PROT_READ | PROT_WRITE | PROT_EXEC,
 458                        MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_32BIT,
 459                        N_TXTOFF(ex));
 460        retval = error;
 461        if (error != start_addr)
 462                goto out;
 463
 464        len = PAGE_ALIGN(ex.a_text + ex.a_data);
 465        bss = ex.a_text + ex.a_data + ex.a_bss;
 466        if (bss > len) {
 467                error = vm_brk(start_addr + len, bss - len);
 468                retval = error;
 469                if (error != start_addr + len)
 470                        goto out;
 471        }
 472        retval = 0;
 473out:
 474        return retval;
 475}
 476
 477static int __init init_aout_binfmt(void)
 478{
 479        register_binfmt(&aout_format);
 480        return 0;
 481}
 482
 483static void __exit exit_aout_binfmt(void)
 484{
 485        unregister_binfmt(&aout_format);
 486}
 487
 488module_init(init_aout_binfmt);
 489module_exit(exit_aout_binfmt);
 490MODULE_LICENSE("GPL");
 491