linux-bk/fs/binfmt_aout.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/binfmt_aout.c
   3 *
   4 *  Copyright (C) 1991, 1992, 1996  Linus Torvalds
   5 */
   6
   7#include <linux/module.h>
   8
   9#include <linux/time.h>
  10#include <linux/kernel.h>
  11#include <linux/mm.h>
  12#include <linux/mman.h>
  13#include <linux/a.out.h>
  14#include <linux/errno.h>
  15#include <linux/signal.h>
  16#include <linux/string.h>
  17#include <linux/fs.h>
  18#include <linux/file.h>
  19#include <linux/stat.h>
  20#include <linux/fcntl.h>
  21#include <linux/ptrace.h>
  22#include <linux/user.h>
  23#include <linux/slab.h>
  24#include <linux/binfmts.h>
  25#include <linux/personality.h>
  26#include <linux/init.h>
  27
  28#include <asm/system.h>
  29#include <asm/uaccess.h>
  30#include <asm/pgalloc.h>
  31#include <asm/cacheflush.h>
  32
  33static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
  34static int load_aout_library(struct file*);
  35static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file);
  36
  37extern void dump_thread(struct pt_regs *, struct user *);
  38
  39static struct linux_binfmt aout_format = {
  40        .module         = THIS_MODULE,
  41        .load_binary    = load_aout_binary,
  42        .load_shlib     = load_aout_library,
  43        .core_dump      = aout_core_dump,
  44        .min_coredump   = PAGE_SIZE
  45};
  46
  47static void set_brk(unsigned long start, unsigned long end)
  48{
  49        start = PAGE_ALIGN(start);
  50        end = PAGE_ALIGN(end);
  51        if (end <= start)
  52                return;
  53        do_brk(start, end - start);
  54}
  55
  56/*
  57 * These are the only things you should do on a core-file: use only these
  58 * macros to write out all the necessary info.
  59 */
  60
  61static int dump_write(struct file *file, const void *addr, int nr)
  62{
  63        return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
  64}
  65
  66#define DUMP_WRITE(addr, nr)    \
  67        if (!dump_write(file, (void *)(addr), (nr))) \
  68                goto end_coredump;
  69
  70#define DUMP_SEEK(offset) \
  71if (file->f_op->llseek) { \
  72        if (file->f_op->llseek(file,(offset),0) != (offset)) \
  73                goto end_coredump; \
  74} else file->f_pos = (offset)
  75
  76/*
  77 * Routine writes a core dump image in the current directory.
  78 * Currently only a stub-function.
  79 *
  80 * Note that setuid/setgid files won't make a core-dump if the uid/gid
  81 * changed due to the set[u|g]id. It's enforced by the "current->mm->dumpable"
  82 * field, which also makes sure the core-dumps won't be recursive if the
  83 * dumping of the process results in another error..
  84 */
  85
  86static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file)
  87{
  88        mm_segment_t fs;
  89        int has_dumped = 0;
  90        unsigned long dump_start, dump_size;
  91        struct user dump;
  92#if defined(__alpha__)
  93#       define START_DATA(u)    (u.start_data)
  94#elif defined(__arm__)
  95#       define START_DATA(u)    ((u.u_tsize << PAGE_SHIFT) + u.start_code)
  96#elif defined(__sparc__)
  97#       define START_DATA(u)    (u.u_tsize)
  98#elif defined(__i386__) || defined(__mc68000__) || defined(__arch_um__)
  99#       define START_DATA(u)    (u.u_tsize << PAGE_SHIFT)
 100#endif
 101#ifdef __sparc__
 102#       define START_STACK(u)   ((regs->u_regs[UREG_FP]) & ~(PAGE_SIZE - 1))
 103#else
 104#       define START_STACK(u)   (u.start_stack)
 105#endif
 106
 107        fs = get_fs();
 108        set_fs(KERNEL_DS);
 109        has_dumped = 1;
 110        current->flags |= PF_DUMPCORE;
 111        strncpy(dump.u_comm, current->comm, sizeof(current->comm));
 112#ifndef __sparc__
 113        dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump)));
 114#endif
 115        dump.signal = signr;
 116        dump_thread(regs, &dump);
 117
 118/* If the size of the dump file exceeds the rlimit, then see what would happen
 119   if we wrote the stack, but not the data area.  */
 120#ifdef __sparc__
 121        if ((dump.u_dsize+dump.u_ssize) >
 122            current->rlim[RLIMIT_CORE].rlim_cur)
 123                dump.u_dsize = 0;
 124#else
 125        if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE >
 126            current->rlim[RLIMIT_CORE].rlim_cur)
 127                dump.u_dsize = 0;
 128#endif
 129
 130/* Make sure we have enough room to write the stack and data areas. */
 131#ifdef __sparc__
 132        if ((dump.u_ssize) >
 133            current->rlim[RLIMIT_CORE].rlim_cur)
 134                dump.u_ssize = 0;
 135#else
 136        if ((dump.u_ssize+1) * PAGE_SIZE >
 137            current->rlim[RLIMIT_CORE].rlim_cur)
 138                dump.u_ssize = 0;
 139#endif
 140
 141/* make sure we actually have a data and stack area to dump */
 142        set_fs(USER_DS);
 143#ifdef __sparc__
 144        if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize))
 145                dump.u_dsize = 0;
 146        if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize))
 147                dump.u_ssize = 0;
 148#else
 149        if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize << PAGE_SHIFT))
 150                dump.u_dsize = 0;
 151        if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize << PAGE_SHIFT))
 152                dump.u_ssize = 0;
 153#endif
 154
 155        set_fs(KERNEL_DS);
 156/* struct user */
 157        DUMP_WRITE(&dump,sizeof(dump));
 158/* Now dump all of the user data.  Include malloced stuff as well */
 159#ifndef __sparc__
 160        DUMP_SEEK(PAGE_SIZE);
 161#endif
 162/* now we start writing out the user space info */
 163        set_fs(USER_DS);
 164/* Dump the data area */
 165        if (dump.u_dsize != 0) {
 166                dump_start = START_DATA(dump);
 167#ifdef __sparc__
 168                dump_size = dump.u_dsize;
 169#else
 170                dump_size = dump.u_dsize << PAGE_SHIFT;
 171#endif
 172                DUMP_WRITE(dump_start,dump_size);
 173        }
 174/* Now prepare to dump the stack area */
 175        if (dump.u_ssize != 0) {
 176                dump_start = START_STACK(dump);
 177#ifdef __sparc__
 178                dump_size = dump.u_ssize;
 179#else
 180                dump_size = dump.u_ssize << PAGE_SHIFT;
 181#endif
 182                DUMP_WRITE(dump_start,dump_size);
 183        }
 184/* Finally dump the task struct.  Not be used by gdb, but could be useful */
 185        set_fs(KERNEL_DS);
 186        DUMP_WRITE(current,sizeof(*current));
 187end_coredump:
 188        set_fs(fs);
 189        return has_dumped;
 190}
 191
 192/*
 193 * create_aout_tables() parses the env- and arg-strings in new user
 194 * memory and creates the pointer tables from them, and puts their
 195 * addresses on the "stack", returning the new stack pointer value.
 196 */
 197static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm)
 198{
 199        char **argv, **envp;
 200        unsigned long * sp;
 201        int argc = bprm->argc;
 202        int envc = bprm->envc;
 203
 204        sp = (unsigned long *) ((-(unsigned long)sizeof(char *)) & (unsigned long) p);
 205#ifdef __sparc__
 206        /* This imposes the proper stack alignment for a new process. */
 207        sp = (unsigned long *) (((unsigned long) sp) & ~7);
 208        if ((envc+argc+3)&1) --sp;
 209#endif
 210#ifdef __alpha__
 211/* whee.. test-programs are so much fun. */
 212        put_user(0, --sp);
 213        put_user(0, --sp);
 214        if (bprm->loader) {
 215                put_user(0, --sp);
 216                put_user(0x3eb, --sp);
 217                put_user(bprm->loader, --sp);
 218                put_user(0x3ea, --sp);
 219        }
 220        put_user(bprm->exec, --sp);
 221        put_user(0x3e9, --sp);
 222#endif
 223        sp -= envc+1;
 224        envp = (char **) sp;
 225        sp -= argc+1;
 226        argv = (char **) sp;
 227#if defined(__i386__) || defined(__mc68000__) || defined(__arm__) || defined(__arch_um__)
 228        put_user((unsigned long) envp,--sp);
 229        put_user((unsigned long) argv,--sp);
 230#endif
 231        put_user(argc,--sp);
 232        current->mm->arg_start = (unsigned long) p;
 233        while (argc-->0) {
 234                char c;
 235                put_user(p,argv++);
 236                do {
 237                        get_user(c,p++);
 238                } while (c);
 239        }
 240        put_user(NULL,argv);
 241        current->mm->arg_end = current->mm->env_start = (unsigned long) p;
 242        while (envc-->0) {
 243                char c;
 244                put_user(p,envp++);
 245                do {
 246                        get_user(c,p++);
 247                } while (c);
 248        }
 249        put_user(NULL,envp);
 250        current->mm->env_end = (unsigned long) p;
 251        return sp;
 252}
 253
 254/*
 255 * These are the functions used to load a.out style executables and shared
 256 * libraries.  There is no binary dependent code anywhere else.
 257 */
 258
 259static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
 260{
 261        struct exec ex;
 262        unsigned long error;
 263        unsigned long fd_offset;
 264        unsigned long rlim;
 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            bprm->file->f_dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
 272                return -ENOEXEC;
 273        }
 274
 275        fd_offset = N_TXTOFF(ex);
 276
 277        /* Check initial limits. This avoids letting people circumvent
 278         * size limits imposed on them by creating programs with large
 279         * arrays in the data or bss.
 280         */
 281        rlim = current->rlim[RLIMIT_DATA].rlim_cur;
 282        if (rlim >= RLIM_INFINITY)
 283                rlim = ~0;
 284        if (ex.a_data + ex.a_bss > rlim)
 285                return -ENOMEM;
 286
 287        /* Flush all traces of the currently running executable */
 288        retval = flush_old_exec(bprm);
 289        if (retval)
 290                return retval;
 291
 292        /* OK, This is the point of no return */
 293#if defined(__alpha__)
 294        SET_AOUT_PERSONALITY(bprm, ex);
 295#elif defined(__sparc__)
 296        set_personality(PER_SUNOS);
 297#if !defined(__sparc_v9__)
 298        memcpy(&current->thread.core_exec, &ex, sizeof(struct exec));
 299#endif
 300#else
 301        set_personality(PER_LINUX);
 302#endif
 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        current->mm->rss = 0;
 312        current->mm->mmap = NULL;
 313        compute_creds(bprm);
 314        current->flags &= ~PF_FORKNOEXEC;
 315#ifdef __sparc__
 316        if (N_MAGIC(ex) == NMAGIC) {
 317                loff_t pos = fd_offset;
 318                /* Fuck me plenty... */
 319                /* <AOL></AOL> */
 320                error = do_brk(N_TXTADDR(ex), ex.a_text);
 321                bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
 322                          ex.a_text, &pos);
 323                error = do_brk(N_DATADDR(ex), ex.a_data);
 324                bprm->file->f_op->read(bprm->file, (char *) N_DATADDR(ex),
 325                          ex.a_data, &pos);
 326                goto beyond_if;
 327        }
 328#endif
 329
 330        if (N_MAGIC(ex) == OMAGIC) {
 331                unsigned long text_addr, map_size;
 332                loff_t pos;
 333
 334                text_addr = N_TXTADDR(ex);
 335
 336#if defined(__alpha__) || defined(__sparc__)
 337                pos = fd_offset;
 338                map_size = ex.a_text+ex.a_data + PAGE_SIZE - 1;
 339#else
 340                pos = 32;
 341                map_size = ex.a_text+ex.a_data;
 342#endif
 343
 344                error = do_brk(text_addr & PAGE_MASK, map_size);
 345                if (error != (text_addr & PAGE_MASK)) {
 346                        send_sig(SIGKILL, current, 0);
 347                        return error;
 348                }
 349
 350                error = bprm->file->f_op->read(bprm->file, (char *)text_addr,
 351                          ex.a_text+ex.a_data, &pos);
 352                if ((signed long)error < 0) {
 353                        send_sig(SIGKILL, current, 0);
 354                        return error;
 355                }
 356                         
 357                flush_icache_range(text_addr, text_addr+ex.a_text+ex.a_data);
 358        } else {
 359                static unsigned long error_time, error_time2;
 360                if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
 361                    (N_MAGIC(ex) != NMAGIC) && (jiffies-error_time2) > 5*HZ)
 362                {
 363                        printk(KERN_NOTICE "executable not page aligned\n");
 364                        error_time2 = jiffies;
 365                }
 366
 367                if ((fd_offset & ~PAGE_MASK) != 0 &&
 368                    (jiffies-error_time) > 5*HZ)
 369                {
 370                        printk(KERN_WARNING 
 371                               "fd_offset is not page aligned. Please convert program: %s\n",
 372                               bprm->file->f_dentry->d_name.name);
 373                        error_time = jiffies;
 374                }
 375
 376                if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
 377                        loff_t pos = fd_offset;
 378                        do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
 379                        bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
 380                                        ex.a_text+ex.a_data, &pos);
 381                        flush_icache_range((unsigned long) N_TXTADDR(ex),
 382                                           (unsigned long) N_TXTADDR(ex) +
 383                                           ex.a_text+ex.a_data);
 384                        goto beyond_if;
 385                }
 386
 387                down_write(&current->mm->mmap_sem);
 388                error = do_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
 389                        PROT_READ | PROT_EXEC,
 390                        MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
 391                        fd_offset);
 392                up_write(&current->mm->mmap_sem);
 393
 394                if (error != N_TXTADDR(ex)) {
 395                        send_sig(SIGKILL, current, 0);
 396                        return error;
 397                }
 398
 399                down_write(&current->mm->mmap_sem);
 400                error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
 401                                PROT_READ | PROT_WRITE | PROT_EXEC,
 402                                MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
 403                                fd_offset + ex.a_text);
 404                up_write(&current->mm->mmap_sem);
 405                if (error != N_DATADDR(ex)) {
 406                        send_sig(SIGKILL, current, 0);
 407                        return error;
 408                }
 409        }
 410beyond_if:
 411        set_binfmt(&aout_format);
 412
 413        set_brk(current->mm->start_brk, current->mm->brk);
 414
 415        retval = setup_arg_pages(bprm); 
 416        if (retval < 0) { 
 417                /* Someone check-me: is this error path enough? */ 
 418                send_sig(SIGKILL, current, 0); 
 419                return retval;
 420        }
 421
 422        current->mm->start_stack =
 423                (unsigned long) create_aout_tables((char *) bprm->p, bprm);
 424#ifdef __alpha__
 425        regs->gp = ex.a_gpvalue;
 426#endif
 427        start_thread(regs, ex.a_entry, current->mm->start_stack);
 428        if (current->ptrace & PT_PTRACED)
 429                send_sig(SIGTRAP, current, 0);
 430        return 0;
 431}
 432
 433static int load_aout_library(struct file *file)
 434{
 435        struct inode * inode;
 436        unsigned long bss, start_addr, len;
 437        unsigned long error;
 438        int retval;
 439        struct exec ex;
 440
 441        inode = file->f_dentry->d_inode;
 442
 443        retval = -ENOEXEC;
 444        error = kernel_read(file, 0, (char *) &ex, sizeof(ex));
 445        if (error != sizeof(ex))
 446                goto out;
 447
 448        /* We come in here for the regular a.out style of shared libraries */
 449        if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) ||
 450            N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
 451            inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
 452                goto out;
 453        }
 454
 455        if (N_FLAGS(ex))
 456                goto out;
 457
 458        /* For  QMAGIC, the starting address is 0x20 into the page.  We mask
 459           this off to get the starting address for the page */
 460
 461        start_addr =  ex.a_entry & 0xfffff000;
 462
 463        if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
 464                static unsigned long error_time;
 465                loff_t pos = N_TXTOFF(ex);
 466
 467                if ((jiffies-error_time) > 5*HZ)
 468                {
 469                        printk(KERN_WARNING 
 470                               "N_TXTOFF is not page aligned. Please convert library: %s\n",
 471                               file->f_dentry->d_name.name);
 472                        error_time = jiffies;
 473                }
 474
 475                do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
 476                
 477                file->f_op->read(file, (char *)start_addr,
 478                        ex.a_text + ex.a_data, &pos);
 479                flush_icache_range((unsigned long) start_addr,
 480                                   (unsigned long) start_addr + ex.a_text + ex.a_data);
 481
 482                retval = 0;
 483                goto out;
 484        }
 485        /* Now use mmap to map the library into memory. */
 486        down_write(&current->mm->mmap_sem);
 487        error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
 488                        PROT_READ | PROT_WRITE | PROT_EXEC,
 489                        MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
 490                        N_TXTOFF(ex));
 491        up_write(&current->mm->mmap_sem);
 492        retval = error;
 493        if (error != start_addr)
 494                goto out;
 495
 496        len = PAGE_ALIGN(ex.a_text + ex.a_data);
 497        bss = ex.a_text + ex.a_data + ex.a_bss;
 498        if (bss > len) {
 499                error = do_brk(start_addr + len, bss - len);
 500                retval = error;
 501                if (error != start_addr + len)
 502                        goto out;
 503        }
 504        retval = 0;
 505out:
 506        return retval;
 507}
 508
 509static int __init init_aout_binfmt(void)
 510{
 511        return register_binfmt(&aout_format);
 512}
 513
 514static void __exit exit_aout_binfmt(void)
 515{
 516        unregister_binfmt(&aout_format);
 517}
 518
 519module_init(init_aout_binfmt);
 520module_exit(exit_aout_binfmt);
 521MODULE_LICENSE("GPL");
 522
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.