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