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. do_load_aout_binary
  5. load_aout_binary
  6. do_load_aout_library
  7. load_aout_library
  8. init_aout_binfmt
  9. init_module
  10. 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         strncpy(dump.u_comm, current->comm, sizeof(current->comm));
 133         dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump)));
 134         dump.signal = signr;
 135         dump_thread(regs, &dump);
 136 
 137 /* If the size of the dump file exceeds the rlimit, then see what would happen
 138    if we wrote the stack, but not the data area.  */
 139         if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE >
 140             current->rlim[RLIMIT_CORE].rlim_cur)
 141                 dump.u_dsize = 0;
 142 
 143 /* Make sure we have enough room to write the stack and data areas. */
 144         if ((dump.u_ssize+1) * PAGE_SIZE >
 145             current->rlim[RLIMIT_CORE].rlim_cur)
 146                 dump.u_ssize = 0;
 147 
 148 /* make sure we actually have a data and stack area to dump */
 149         set_fs(USER_DS);
 150         if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize << PAGE_SHIFT))
 151                 dump.u_dsize = 0;
 152         if (verify_area(VERIFY_READ, (void *) dump.start_stack, dump.u_ssize << PAGE_SHIFT))
 153                 dump.u_ssize = 0;
 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         DUMP_SEEK(PAGE_SIZE);
 160 /* now we start writing out the user space info */
 161         set_fs(USER_DS);
 162 /* Dump the data area */
 163         if (dump.u_dsize != 0) {
 164                 dump_start = START_DATA(dump);
 165                 dump_size = dump.u_dsize << PAGE_SHIFT;
 166                 DUMP_WRITE(dump_start,dump_size);
 167         }
 168 /* Now prepare to dump the stack area */
 169         if (dump.u_ssize != 0) {
 170                 dump_start = dump.start_stack;
 171                 dump_size = dump.u_ssize << PAGE_SHIFT;
 172                 DUMP_WRITE(dump_start,dump_size);
 173         }
 174 /* Finally dump the task struct.  Not be used by gdb, but could be useful */
 175         set_fs(KERNEL_DS);
 176         DUMP_WRITE(current,sizeof(*current));
 177 close_coredump:
 178         if (file.f_op->release)
 179                 file.f_op->release(inode,&file);
 180 done_coredump:
 181         put_write_access(inode);
 182 end_coredump:
 183         set_fs(fs);
 184         iput(inode);
 185         return has_dumped;
 186 }
 187 
 188 static int
 189 aout_core_dump(long signr, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 190 {
 191         int retval;
 192 
 193         MOD_INC_USE_COUNT;
 194         retval = do_aout_core_dump(signr, regs);
 195         MOD_DEC_USE_COUNT;
 196         return retval;
 197 }
 198 
 199 /*
 200  * These are the functions used to load a.out style executables and shared
 201  * libraries.  There is no binary dependent code anywhere else.
 202  */
 203 
 204 static inline int
 205 do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 206 {
 207         struct exec ex;
 208         struct file * file;
 209         int fd;
 210         unsigned long error;
 211         unsigned long p = bprm->p;
 212         unsigned long fd_offset;
 213         unsigned long rlim;
 214 
 215         ex = *((struct exec *) bprm->buf);              /* exec-header */
 216         if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && 
 217              N_MAGIC(ex) != QMAGIC) ||
 218             N_TRSIZE(ex) || N_DRSIZE(ex) ||
 219             bprm->inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
 220                 return -ENOEXEC;
 221         }
 222 
 223         current->personality = PER_LINUX;
 224         fd_offset = N_TXTOFF(ex);
 225 
 226 #ifdef __i386__
 227         if (N_MAGIC(ex) == ZMAGIC && fd_offset != BLOCK_SIZE) {
 228                 printk(KERN_NOTICE "N_TXTOFF != BLOCK_SIZE. See a.out.h.\n");
 229                 return -ENOEXEC;
 230         }
 231 
 232         if (N_MAGIC(ex) == ZMAGIC && ex.a_text &&
 233             (fd_offset < bprm->inode->i_sb->s_blocksize)) {
 234                 printk(KERN_NOTICE "N_TXTOFF < BLOCK_SIZE. Please convert binary.\n");
 235                 return -ENOEXEC;
 236         }
 237 #endif
 238 
 239         /* Check initial limits. This avoids letting people circumvent
 240          * size limits imposed on them by creating programs with large
 241          * arrays in the data or bss.
 242          */
 243         rlim = current->rlim[RLIMIT_DATA].rlim_cur;
 244         if (rlim >= RLIM_INFINITY)
 245                 rlim = ~0;
 246         if (ex.a_data + ex.a_bss > rlim)
 247                 return -ENOMEM;
 248 
 249         /* OK, This is the point of no return */
 250         flush_old_exec(bprm);
 251 
 252         current->mm->end_code = ex.a_text +
 253                 (current->mm->start_code = N_TXTADDR(ex));
 254         current->mm->end_data = ex.a_data +
 255                 (current->mm->start_data = N_DATADDR(ex));
 256         current->mm->brk = ex.a_bss +
 257                 (current->mm->start_brk = N_BSSADDR(ex));
 258 
 259         current->mm->rss = 0;
 260         current->mm->mmap = NULL;
 261         current->suid = current->euid = current->fsuid = bprm->e_uid;
 262         current->sgid = current->egid = current->fsgid = bprm->e_gid;
 263         if (N_MAGIC(ex) == OMAGIC) {
 264 #ifdef __alpha__
 265                 do_mmap(NULL, N_TXTADDR(ex) & PAGE_MASK,
 266                         ex.a_text+ex.a_data + PAGE_SIZE - 1,
 267                         PROT_READ|PROT_WRITE|PROT_EXEC,
 268                         MAP_FIXED|MAP_PRIVATE, 0);
 269                 read_exec(bprm->inode, fd_offset, (char *) N_TXTADDR(ex),
 270                           ex.a_text+ex.a_data, 0);
 271 #else
 272                 do_mmap(NULL, 0, ex.a_text+ex.a_data,
 273                         PROT_READ|PROT_WRITE|PROT_EXEC,
 274                         MAP_FIXED|MAP_PRIVATE, 0);
 275                 read_exec(bprm->inode, 32, (char *) 0, ex.a_text+ex.a_data, 0);
 276 #endif
 277         } else {
 278                 if (ex.a_text & 0xfff || ex.a_data & 0xfff)
 279                         printk(KERN_NOTICE "executable not page aligned\n");
 280                 
 281                 fd = open_inode(bprm->inode, O_RDONLY);
 282                 
 283                 if (fd < 0)
 284                         return fd;
 285                 file = current->files->fd[fd];
 286                 if (!file->f_op || !file->f_op->mmap) {
 287                         sys_close(fd);
 288                         do_mmap(NULL, 0, ex.a_text+ex.a_data,
 289                                 PROT_READ|PROT_WRITE|PROT_EXEC,
 290                                 MAP_FIXED|MAP_PRIVATE, 0);
 291                         read_exec(bprm->inode, fd_offset,
 292                                   (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0);
 293                         goto beyond_if;
 294                 }
 295 
 296                 error = do_mmap(file, N_TXTADDR(ex), ex.a_text,
 297                         PROT_READ | PROT_EXEC,
 298                         MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
 299                         fd_offset);
 300 
 301                 if (error != N_TXTADDR(ex)) {
 302                         sys_close(fd);
 303                         send_sig(SIGKILL, current, 0);
 304                         return error;
 305                 }
 306                 
 307                 error = do_mmap(file, N_DATADDR(ex), ex.a_data,
 308                                 PROT_READ | PROT_WRITE | PROT_EXEC,
 309                                 MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
 310                                 fd_offset + ex.a_text);
 311                 sys_close(fd);
 312                 if (error != N_DATADDR(ex)) {
 313                         send_sig(SIGKILL, current, 0);
 314                         return error;
 315                 }
 316         }
 317 beyond_if:
 318         if (current->exec_domain && current->exec_domain->use_count)
 319                 (*current->exec_domain->use_count)--;
 320         if (current->binfmt && current->binfmt->use_count)
 321                 (*current->binfmt->use_count)--;
 322         current->exec_domain = lookup_exec_domain(current->personality);
 323         current->binfmt = &aout_format;
 324         if (current->exec_domain && current->exec_domain->use_count)
 325                 (*current->exec_domain->use_count)++;
 326         if (current->binfmt && current->binfmt->use_count)
 327                 (*current->binfmt->use_count)++;
 328 
 329         set_brk(current->mm->start_brk, current->mm->brk);
 330 
 331         fd_offset = setup_arg_pages(ex.a_text,bprm->page) - MAX_ARG_PAGES*PAGE_SIZE;
 332         p += fd_offset;
 333         if (bprm->loader)
 334                 bprm->loader += fd_offset;
 335         bprm->exec += fd_offset;
 336         
 337         p = (unsigned long)create_tables((char *)p, bprm,
 338                                         current->personality != PER_LINUX);
 339         current->mm->start_stack = p;
 340 #ifdef __alpha__
 341         regs->gp = ex.a_gpvalue;
 342 #endif
 343         start_thread(regs, ex.a_entry, p);
 344         if (current->flags & PF_PTRACED)
 345                 send_sig(SIGTRAP, current, 0);
 346         return 0;
 347 }
 348 
 349 static int
 350 load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 351 {
 352         int retval;
 353 
 354         MOD_INC_USE_COUNT;
 355         retval = do_load_aout_binary(bprm, regs);
 356         MOD_DEC_USE_COUNT;
 357         return retval;
 358 }
 359 
 360 static inline int
 361 do_load_aout_library(int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 362 {
 363         struct file * file;
 364         struct exec ex;
 365         struct  inode * inode;
 366         unsigned int len;
 367         unsigned int bss;
 368         unsigned int start_addr;
 369         unsigned long error;
 370         
 371         file = current->files->fd[fd];
 372         inode = file->f_inode;
 373         
 374         if (!file || !file->f_op)
 375                 return -EACCES;
 376 
 377         /* Seek into the file */
 378         if (file->f_op->lseek) {
 379                 if ((error = file->f_op->lseek(inode, file, 0, 0)) != 0)
 380                         return -ENOEXEC;
 381         } else
 382                 file->f_pos = 0;
 383 
 384         set_fs(KERNEL_DS);
 385         error = file->f_op->read(inode, file, (char *) &ex, sizeof(ex));
 386         set_fs(USER_DS);
 387         if (error != sizeof(ex))
 388                 return -ENOEXEC;
 389 
 390         /* We come in here for the regular a.out style of shared libraries */
 391         if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) ||
 392             N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
 393             inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
 394                 return -ENOEXEC;
 395         }
 396         if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) && 
 397             (N_TXTOFF(ex) < inode->i_sb->s_blocksize)) {
 398                 printk("N_TXTOFF < BLOCK_SIZE. Please convert library\n");
 399                 return -ENOEXEC;
 400         }
 401         
 402         if (N_FLAGS(ex)) return -ENOEXEC;
 403 
 404         /* For  QMAGIC, the starting address is 0x20 into the page.  We mask
 405            this off to get the starting address for the page */
 406 
 407         start_addr =  ex.a_entry & 0xfffff000;
 408 
 409         /* Now use mmap to map the library into memory. */
 410         error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
 411                         PROT_READ | PROT_WRITE | PROT_EXEC,
 412                         MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
 413                         N_TXTOFF(ex));
 414         if (error != start_addr)
 415                 return error;
 416         len = PAGE_ALIGN(ex.a_text + ex.a_data);
 417         bss = ex.a_text + ex.a_data + ex.a_bss;
 418         if (bss > len) {
 419                 error = do_mmap(NULL, start_addr + len, bss-len,
 420                                 PROT_READ|PROT_WRITE|PROT_EXEC,
 421                                 MAP_PRIVATE|MAP_FIXED, 0);
 422                 if (error != start_addr + len)
 423                         return error;
 424         }
 425         return 0;
 426 }
 427 
 428 static int
 429 load_aout_library(int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 430 {
 431         int retval;
 432 
 433         MOD_INC_USE_COUNT;
 434         retval = do_load_aout_library(fd);
 435         MOD_DEC_USE_COUNT;
 436         return retval;
 437 }
 438 
 439 
 440 int init_aout_binfmt(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 441         return register_binfmt(&aout_format);
 442 }
 443 
 444 #ifdef MODULE
 445 int init_module(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 446         return init_aout_binfmt();
 447 }
 448 
 449 void cleanup_module( void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 450         unregister_binfmt(&aout_format);
 451 }
 452 #endif
 453 

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