root/fs/binfmt_aout.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. set_brk
  2. do_aout_core_dump
  3. aout_core_dump
  4. create_aout_tables
  5. do_load_aout_binary
  6. load_aout_binary
  7. do_load_aout_library
  8. load_aout_library
  9. init_aout_binfmt
  10. init_module
  11. cleanup_module

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

/* [previous][next][first][last][top][bottom][index][help] */