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