diff options
Diffstat (limited to 'arch/mips/kernel/irixelf.c')
| -rw-r--r-- | arch/mips/kernel/irixelf.c | 236 |
1 files changed, 127 insertions, 109 deletions
diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c index 4af20cd91f9f..99262fe64560 100644 --- a/arch/mips/kernel/irixelf.c +++ b/arch/mips/kernel/irixelf.c | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | * | 8 | * |
| 9 | * Copyright (C) 1993 - 1994 Eric Youngdale <ericy@cais.com> | 9 | * Copyright (C) 1993 - 1994 Eric Youngdale <ericy@cais.com> |
| 10 | * Copyright (C) 1996 - 2004 David S. Miller <dm@engr.sgi.com> | 10 | * Copyright (C) 1996 - 2004 David S. Miller <dm@engr.sgi.com> |
| 11 | * Copyright (C) 2004 Steven J. Hill <sjhill@realitydiluted.com> | 11 | * Copyright (C) 2004 - 2005 Steven J. Hill <sjhill@realitydiluted.com> |
| 12 | */ | 12 | */ |
| 13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 14 | #include <linux/fs.h> | 14 | #include <linux/fs.h> |
| @@ -31,15 +31,16 @@ | |||
| 31 | #include <linux/elfcore.h> | 31 | #include <linux/elfcore.h> |
| 32 | #include <linux/smp_lock.h> | 32 | #include <linux/smp_lock.h> |
| 33 | 33 | ||
| 34 | #include <asm/uaccess.h> | ||
| 35 | #include <asm/mipsregs.h> | 34 | #include <asm/mipsregs.h> |
| 35 | #include <asm/namei.h> | ||
| 36 | #include <asm/prctl.h> | 36 | #include <asm/prctl.h> |
| 37 | #include <asm/uaccess.h> | ||
| 37 | 38 | ||
| 38 | #define DLINFO_ITEMS 12 | 39 | #define DLINFO_ITEMS 12 |
| 39 | 40 | ||
| 40 | #include <linux/elf.h> | 41 | #include <linux/elf.h> |
| 41 | 42 | ||
| 42 | #undef DEBUG_ELF | 43 | #undef DEBUG |
| 43 | 44 | ||
| 44 | static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs); | 45 | static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs); |
| 45 | static int load_irix_library(struct file *); | 46 | static int load_irix_library(struct file *); |
| @@ -55,7 +56,7 @@ static struct linux_binfmt irix_format = { | |||
| 55 | #define elf_addr_t unsigned long | 56 | #define elf_addr_t unsigned long |
| 56 | #endif | 57 | #endif |
| 57 | 58 | ||
| 58 | #ifdef DEBUG_ELF | 59 | #ifdef DEBUG |
| 59 | /* Debugging routines. */ | 60 | /* Debugging routines. */ |
| 60 | static char *get_elf_p_type(Elf32_Word p_type) | 61 | static char *get_elf_p_type(Elf32_Word p_type) |
| 61 | { | 62 | { |
| @@ -120,7 +121,7 @@ static void dump_phdrs(struct elf_phdr *ep, int pnum) | |||
| 120 | print_phdr(i, ep); | 121 | print_phdr(i, ep); |
| 121 | } | 122 | } |
| 122 | } | 123 | } |
| 123 | #endif /* (DEBUG_ELF) */ | 124 | #endif /* DEBUG */ |
| 124 | 125 | ||
| 125 | static void set_brk(unsigned long start, unsigned long end) | 126 | static void set_brk(unsigned long start, unsigned long end) |
| 126 | { | 127 | { |
| @@ -146,20 +147,20 @@ static void padzero(unsigned long elf_bss) | |||
| 146 | nbyte = elf_bss & (PAGE_SIZE-1); | 147 | nbyte = elf_bss & (PAGE_SIZE-1); |
| 147 | if (nbyte) { | 148 | if (nbyte) { |
| 148 | nbyte = PAGE_SIZE - nbyte; | 149 | nbyte = PAGE_SIZE - nbyte; |
| 149 | clear_user((void *) elf_bss, nbyte); | 150 | clear_user((void __user *) elf_bss, nbyte); |
| 150 | } | 151 | } |
| 151 | } | 152 | } |
| 152 | 153 | ||
| 153 | unsigned long * create_irix_tables(char * p, int argc, int envc, | 154 | static unsigned long * create_irix_tables(char * p, int argc, int envc, |
| 154 | struct elfhdr * exec, unsigned int load_addr, | 155 | struct elfhdr * exec, unsigned int load_addr, |
| 155 | unsigned int interp_load_addr, | 156 | unsigned int interp_load_addr, struct pt_regs *regs, |
| 156 | struct pt_regs *regs, struct elf_phdr *ephdr) | 157 | struct elf_phdr *ephdr) |
| 157 | { | 158 | { |
| 158 | elf_addr_t *argv; | 159 | elf_addr_t *argv; |
| 159 | elf_addr_t *envp; | 160 | elf_addr_t *envp; |
| 160 | elf_addr_t *sp, *csp; | 161 | elf_addr_t *sp, *csp; |
| 161 | 162 | ||
| 162 | #ifdef DEBUG_ELF | 163 | #ifdef DEBUG |
| 163 | printk("create_irix_tables: p[%p] argc[%d] envc[%d] " | 164 | printk("create_irix_tables: p[%p] argc[%d] envc[%d] " |
| 164 | "load_addr[%08x] interp_load_addr[%08x]\n", | 165 | "load_addr[%08x] interp_load_addr[%08x]\n", |
| 165 | p, argc, envc, load_addr, interp_load_addr); | 166 | p, argc, envc, load_addr, interp_load_addr); |
| @@ -248,14 +249,13 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, | |||
| 248 | last_bss = 0; | 249 | last_bss = 0; |
| 249 | error = load_addr = 0; | 250 | error = load_addr = 0; |
| 250 | 251 | ||
| 251 | #ifdef DEBUG_ELF | 252 | #ifdef DEBUG |
| 252 | print_elfhdr(interp_elf_ex); | 253 | print_elfhdr(interp_elf_ex); |
| 253 | #endif | 254 | #endif |
| 254 | 255 | ||
| 255 | /* First of all, some simple consistency checks */ | 256 | /* First of all, some simple consistency checks */ |
| 256 | if ((interp_elf_ex->e_type != ET_EXEC && | 257 | if ((interp_elf_ex->e_type != ET_EXEC && |
| 257 | interp_elf_ex->e_type != ET_DYN) || | 258 | interp_elf_ex->e_type != ET_DYN) || |
| 258 | !irix_elf_check_arch(interp_elf_ex) || | ||
| 259 | !interpreter->f_op->mmap) { | 259 | !interpreter->f_op->mmap) { |
| 260 | printk("IRIX interp has bad e_type %d\n", interp_elf_ex->e_type); | 260 | printk("IRIX interp has bad e_type %d\n", interp_elf_ex->e_type); |
| 261 | return 0xffffffff; | 261 | return 0xffffffff; |
| @@ -290,7 +290,7 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, | |||
| 290 | (char *) elf_phdata, | 290 | (char *) elf_phdata, |
| 291 | sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); | 291 | sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); |
| 292 | 292 | ||
| 293 | #ifdef DEBUG_ELF | 293 | #ifdef DEBUG |
| 294 | dump_phdrs(elf_phdata, interp_elf_ex->e_phnum); | 294 | dump_phdrs(elf_phdata, interp_elf_ex->e_phnum); |
| 295 | #endif | 295 | #endif |
| 296 | 296 | ||
| @@ -306,13 +306,11 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, | |||
| 306 | elf_type |= MAP_FIXED; | 306 | elf_type |= MAP_FIXED; |
| 307 | vaddr = eppnt->p_vaddr; | 307 | vaddr = eppnt->p_vaddr; |
| 308 | 308 | ||
| 309 | #ifdef DEBUG_ELF | 309 | pr_debug("INTERP do_mmap(%p, %08lx, %08lx, %08lx, %08lx, %08lx) ", |
| 310 | printk("INTERP do_mmap(%p, %08lx, %08lx, %08lx, %08lx, %08lx) ", | ||
| 311 | interpreter, vaddr, | 310 | interpreter, vaddr, |
| 312 | (unsigned long) (eppnt->p_filesz + (eppnt->p_vaddr & 0xfff)), | 311 | (unsigned long) (eppnt->p_filesz + (eppnt->p_vaddr & 0xfff)), |
| 313 | (unsigned long) elf_prot, (unsigned long) elf_type, | 312 | (unsigned long) elf_prot, (unsigned long) elf_type, |
| 314 | (unsigned long) (eppnt->p_offset & 0xfffff000)); | 313 | (unsigned long) (eppnt->p_offset & 0xfffff000)); |
| 315 | #endif | ||
| 316 | down_write(¤t->mm->mmap_sem); | 314 | down_write(¤t->mm->mmap_sem); |
| 317 | error = do_mmap(interpreter, vaddr, | 315 | error = do_mmap(interpreter, vaddr, |
| 318 | eppnt->p_filesz + (eppnt->p_vaddr & 0xfff), | 316 | eppnt->p_filesz + (eppnt->p_vaddr & 0xfff), |
| @@ -324,14 +322,10 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, | |||
| 324 | printk("Aieee IRIX interp mmap error=%d\n", error); | 322 | printk("Aieee IRIX interp mmap error=%d\n", error); |
| 325 | break; /* Real error */ | 323 | break; /* Real error */ |
| 326 | } | 324 | } |
| 327 | #ifdef DEBUG_ELF | 325 | pr_debug("error=%08lx ", (unsigned long) error); |
| 328 | printk("error=%08lx ", (unsigned long) error); | ||
| 329 | #endif | ||
| 330 | if(!load_addr && interp_elf_ex->e_type == ET_DYN) { | 326 | if(!load_addr && interp_elf_ex->e_type == ET_DYN) { |
| 331 | load_addr = error; | 327 | load_addr = error; |
| 332 | #ifdef DEBUG_ELF | 328 | pr_debug("load_addr = error "); |
| 333 | printk("load_addr = error "); | ||
| 334 | #endif | ||
| 335 | } | 329 | } |
| 336 | 330 | ||
| 337 | /* Find the end of the file mapping for this phdr, and keep | 331 | /* Find the end of the file mapping for this phdr, and keep |
| @@ -345,17 +339,13 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, | |||
| 345 | */ | 339 | */ |
| 346 | k = eppnt->p_memsz + eppnt->p_vaddr; | 340 | k = eppnt->p_memsz + eppnt->p_vaddr; |
| 347 | if(k > last_bss) last_bss = k; | 341 | if(k > last_bss) last_bss = k; |
| 348 | #ifdef DEBUG_ELF | 342 | pr_debug("\n"); |
| 349 | printk("\n"); | ||
| 350 | #endif | ||
| 351 | } | 343 | } |
| 352 | } | 344 | } |
| 353 | 345 | ||
| 354 | /* Now use mmap to map the library into memory. */ | 346 | /* Now use mmap to map the library into memory. */ |
| 355 | if(error < 0 && error > -1024) { | 347 | if(error < 0 && error > -1024) { |
| 356 | #ifdef DEBUG_ELF | 348 | pr_debug("got error %d\n", error); |
| 357 | printk("got error %d\n", error); | ||
| 358 | #endif | ||
| 359 | kfree(elf_phdata); | 349 | kfree(elf_phdata); |
| 360 | return 0xffffffff; | 350 | return 0xffffffff; |
| 361 | } | 351 | } |
| @@ -365,16 +355,12 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, | |||
| 365 | * that there are zero-mapped pages up to and including the | 355 | * that there are zero-mapped pages up to and including the |
| 366 | * last bss page. | 356 | * last bss page. |
| 367 | */ | 357 | */ |
| 368 | #ifdef DEBUG_ELF | 358 | pr_debug("padzero(%08lx) ", (unsigned long) (elf_bss)); |
| 369 | printk("padzero(%08lx) ", (unsigned long) (elf_bss)); | ||
| 370 | #endif | ||
| 371 | padzero(elf_bss); | 359 | padzero(elf_bss); |
| 372 | len = (elf_bss + 0xfff) & 0xfffff000; /* What we have mapped so far */ | 360 | len = (elf_bss + 0xfff) & 0xfffff000; /* What we have mapped so far */ |
| 373 | 361 | ||
| 374 | #ifdef DEBUG_ELF | 362 | pr_debug("last_bss[%08lx] len[%08lx]\n", (unsigned long) last_bss, |
| 375 | printk("last_bss[%08lx] len[%08lx]\n", (unsigned long) last_bss, | 363 | (unsigned long) len); |
| 376 | (unsigned long) len); | ||
| 377 | #endif | ||
| 378 | 364 | ||
| 379 | /* Map the last of the bss segment */ | 365 | /* Map the last of the bss segment */ |
| 380 | if (last_bss > len) { | 366 | if (last_bss > len) { |
| @@ -396,12 +382,7 @@ static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm) | |||
| 396 | 382 | ||
| 397 | /* First of all, some simple consistency checks */ | 383 | /* First of all, some simple consistency checks */ |
| 398 | if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) || | 384 | if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) || |
| 399 | !irix_elf_check_arch(ehp) || !bprm->file->f_op->mmap) { | 385 | !bprm->file->f_op->mmap) { |
| 400 | return -ENOEXEC; | ||
| 401 | } | ||
| 402 | |||
| 403 | /* Only support MIPS ARCH2 or greater IRIX binaries for now. */ | ||
| 404 | if(!(ehp->e_flags & EF_MIPS_ARCH) && !(ehp->e_flags & 0x04)) { | ||
| 405 | return -ENOEXEC; | 386 | return -ENOEXEC; |
| 406 | } | 387 | } |
| 407 | 388 | ||
| @@ -411,16 +392,17 @@ static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm) | |||
| 411 | * XXX all registers as 64bits on cpu's capable of this at | 392 | * XXX all registers as 64bits on cpu's capable of this at |
| 412 | * XXX exception time plus frob the XTLB exception vector. | 393 | * XXX exception time plus frob the XTLB exception vector. |
| 413 | */ | 394 | */ |
| 414 | if((ehp->e_flags & 0x20)) { | 395 | if((ehp->e_flags & EF_MIPS_ABI2)) |
| 415 | return -ENOEXEC; | 396 | return -ENOEXEC; |
| 416 | } | ||
| 417 | 397 | ||
| 418 | return 0; /* It's ok. */ | 398 | return 0; |
| 419 | } | 399 | } |
| 420 | 400 | ||
| 421 | #define IRIX_INTERP_PREFIX "/usr/gnemul/irix" | 401 | /* |
| 422 | 402 | * This is where the detailed check is performed. Irix binaries | |
| 423 | /* Look for an IRIX ELF interpreter. */ | 403 | * use interpreters with 'libc.so' in the name, so this function |
| 404 | * can differentiate between Linux and Irix binaries. | ||
| 405 | */ | ||
| 424 | static inline int look_for_irix_interpreter(char **name, | 406 | static inline int look_for_irix_interpreter(char **name, |
| 425 | struct file **interpreter, | 407 | struct file **interpreter, |
| 426 | struct elfhdr *interp_elf_ex, | 408 | struct elfhdr *interp_elf_ex, |
| @@ -440,12 +422,11 @@ static inline int look_for_irix_interpreter(char **name, | |||
| 440 | if (*name != NULL) | 422 | if (*name != NULL) |
| 441 | goto out; | 423 | goto out; |
| 442 | 424 | ||
| 443 | *name = kmalloc((epp->p_filesz + strlen(IRIX_INTERP_PREFIX)), | 425 | *name = kmalloc(epp->p_filesz + strlen(IRIX_EMUL), GFP_KERNEL); |
| 444 | GFP_KERNEL); | ||
| 445 | if (!*name) | 426 | if (!*name) |
| 446 | return -ENOMEM; | 427 | return -ENOMEM; |
| 447 | 428 | ||
| 448 | strcpy(*name, IRIX_INTERP_PREFIX); | 429 | strcpy(*name, IRIX_EMUL); |
| 449 | retval = kernel_read(bprm->file, epp->p_offset, (*name + 16), | 430 | retval = kernel_read(bprm->file, epp->p_offset, (*name + 16), |
| 450 | epp->p_filesz); | 431 | epp->p_filesz); |
| 451 | if (retval < 0) | 432 | if (retval < 0) |
| @@ -562,7 +543,7 @@ static inline int map_interpreter(struct elf_phdr *epp, struct elfhdr *ihp, | |||
| 562 | * process and the system, here we map the page and fill the | 543 | * process and the system, here we map the page and fill the |
| 563 | * structure | 544 | * structure |
| 564 | */ | 545 | */ |
| 565 | void irix_map_prda_page (void) | 546 | static void irix_map_prda_page(void) |
| 566 | { | 547 | { |
| 567 | unsigned long v; | 548 | unsigned long v; |
| 568 | struct prda *pp; | 549 | struct prda *pp; |
| @@ -601,14 +582,33 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) | |||
| 601 | 582 | ||
| 602 | load_addr = 0; | 583 | load_addr = 0; |
| 603 | has_interp = has_ephdr = 0; | 584 | has_interp = has_ephdr = 0; |
| 604 | elf_ihdr = elf_ephdr = 0; | 585 | elf_ihdr = elf_ephdr = NULL; |
| 605 | elf_ex = *((struct elfhdr *) bprm->buf); | 586 | elf_ex = *((struct elfhdr *) bprm->buf); |
| 606 | retval = -ENOEXEC; | 587 | retval = -ENOEXEC; |
| 607 | 588 | ||
| 608 | if (verify_binary(&elf_ex, bprm)) | 589 | if (verify_binary(&elf_ex, bprm)) |
| 609 | goto out; | 590 | goto out; |
| 610 | 591 | ||
| 611 | #ifdef DEBUG_ELF | 592 | /* |
| 593 | * Telling -o32 static binaries from Linux and Irix apart from each | ||
| 594 | * other is difficult. There are 2 differences to be noted for static | ||
| 595 | * binaries from the 2 operating systems: | ||
| 596 | * | ||
| 597 | * 1) Irix binaries have their .text section before their .init | ||
| 598 | * section. Linux binaries are just the opposite. | ||
| 599 | * | ||
| 600 | * 2) Irix binaries usually have <= 12 sections and Linux | ||
| 601 | * binaries have > 20. | ||
| 602 | * | ||
| 603 | * We will use Method #2 since Method #1 would require us to read in | ||
| 604 | * the section headers which is way too much overhead. This appears | ||
| 605 | * to work for everything we have ran into so far. If anyone has a | ||
| 606 | * better method to tell the binaries apart, I'm listening. | ||
| 607 | */ | ||
| 608 | if (elf_ex.e_shnum > 20) | ||
| 609 | goto out; | ||
| 610 | |||
| 611 | #ifdef DEBUG | ||
| 612 | print_elfhdr(&elf_ex); | 612 | print_elfhdr(&elf_ex); |
| 613 | #endif | 613 | #endif |
| 614 | 614 | ||
| @@ -623,11 +623,10 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) | |||
| 623 | } | 623 | } |
| 624 | 624 | ||
| 625 | retval = kernel_read(bprm->file, elf_ex.e_phoff, (char *)elf_phdata, size); | 625 | retval = kernel_read(bprm->file, elf_ex.e_phoff, (char *)elf_phdata, size); |
| 626 | |||
| 627 | if (retval < 0) | 626 | if (retval < 0) |
| 628 | goto out_free_ph; | 627 | goto out_free_ph; |
| 629 | 628 | ||
| 630 | #ifdef DEBUG_ELF | 629 | #ifdef DEBUG |
| 631 | dump_phdrs(elf_phdata, elf_ex.e_phnum); | 630 | dump_phdrs(elf_phdata, elf_ex.e_phnum); |
| 632 | #endif | 631 | #endif |
| 633 | 632 | ||
| @@ -644,9 +643,8 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) | |||
| 644 | break; | 643 | break; |
| 645 | }; | 644 | }; |
| 646 | } | 645 | } |
| 647 | #ifdef DEBUG_ELF | 646 | |
| 648 | printk("\n"); | 647 | pr_debug("\n"); |
| 649 | #endif | ||
| 650 | 648 | ||
| 651 | elf_bss = 0; | 649 | elf_bss = 0; |
| 652 | elf_brk = 0; | 650 | elf_brk = 0; |
| @@ -657,12 +655,19 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) | |||
| 657 | end_code = 0; | 655 | end_code = 0; |
| 658 | end_data = 0; | 656 | end_data = 0; |
| 659 | 657 | ||
| 660 | retval = look_for_irix_interpreter(&elf_interpreter, | 658 | /* |
| 661 | &interpreter, | 659 | * If we get a return value, we change the value to be ENOEXEC |
| 660 | * so that we can exit gracefully and the main binary format | ||
| 661 | * search loop in 'fs/exec.c' will move onto the next handler | ||
| 662 | * which should be the normal ELF binary handler. | ||
| 663 | */ | ||
| 664 | retval = look_for_irix_interpreter(&elf_interpreter, &interpreter, | ||
| 662 | &interp_elf_ex, elf_phdata, bprm, | 665 | &interp_elf_ex, elf_phdata, bprm, |
| 663 | elf_ex.e_phnum); | 666 | elf_ex.e_phnum); |
| 664 | if (retval) | 667 | if (retval) { |
| 668 | retval = -ENOEXEC; | ||
| 665 | goto out_free_file; | 669 | goto out_free_file; |
| 670 | } | ||
| 666 | 671 | ||
| 667 | if (elf_interpreter) { | 672 | if (elf_interpreter) { |
| 668 | retval = verify_irix_interpreter(&interp_elf_ex); | 673 | retval = verify_irix_interpreter(&interp_elf_ex); |
| @@ -746,18 +751,16 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) | |||
| 746 | * IRIX maps a page at 0x200000 which holds some system | 751 | * IRIX maps a page at 0x200000 which holds some system |
| 747 | * information. Programs depend on this. | 752 | * information. Programs depend on this. |
| 748 | */ | 753 | */ |
| 749 | irix_map_prda_page (); | 754 | irix_map_prda_page(); |
| 750 | 755 | ||
| 751 | padzero(elf_bss); | 756 | padzero(elf_bss); |
| 752 | 757 | ||
| 753 | #ifdef DEBUG_ELF | 758 | pr_debug("(start_brk) %lx\n" , (long) current->mm->start_brk); |
| 754 | printk("(start_brk) %lx\n" , (long) current->mm->start_brk); | 759 | pr_debug("(end_code) %lx\n" , (long) current->mm->end_code); |
| 755 | printk("(end_code) %lx\n" , (long) current->mm->end_code); | 760 | pr_debug("(start_code) %lx\n" , (long) current->mm->start_code); |
| 756 | printk("(start_code) %lx\n" , (long) current->mm->start_code); | 761 | pr_debug("(end_data) %lx\n" , (long) current->mm->end_data); |
| 757 | printk("(end_data) %lx\n" , (long) current->mm->end_data); | 762 | pr_debug("(start_stack) %lx\n" , (long) current->mm->start_stack); |
| 758 | printk("(start_stack) %lx\n" , (long) current->mm->start_stack); | 763 | pr_debug("(brk) %lx\n" , (long) current->mm->brk); |
| 759 | printk("(brk) %lx\n" , (long) current->mm->brk); | ||
| 760 | #endif | ||
| 761 | 764 | ||
| 762 | #if 0 /* XXX No fucking way dude... */ | 765 | #if 0 /* XXX No fucking way dude... */ |
| 763 | /* Why this, you ask??? Well SVr4 maps page 0 as read-only, | 766 | /* Why this, you ask??? Well SVr4 maps page 0 as read-only, |
| @@ -782,8 +785,7 @@ out_free_dentry: | |||
| 782 | allow_write_access(interpreter); | 785 | allow_write_access(interpreter); |
| 783 | fput(interpreter); | 786 | fput(interpreter); |
| 784 | out_free_interp: | 787 | out_free_interp: |
| 785 | if (elf_interpreter) | 788 | kfree(elf_interpreter); |
| 786 | kfree(elf_interpreter); | ||
| 787 | out_free_file: | 789 | out_free_file: |
| 788 | out_free_ph: | 790 | out_free_ph: |
| 789 | kfree (elf_phdata); | 791 | kfree (elf_phdata); |
| @@ -813,7 +815,7 @@ static int load_irix_library(struct file *file) | |||
| 813 | 815 | ||
| 814 | /* First of all, some simple consistency checks. */ | 816 | /* First of all, some simple consistency checks. */ |
| 815 | if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || | 817 | if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || |
| 816 | !irix_elf_check_arch(&elf_ex) || !file->f_op->mmap) | 818 | !file->f_op->mmap) |
| 817 | return -ENOEXEC; | 819 | return -ENOEXEC; |
| 818 | 820 | ||
| 819 | /* Now read in all of the header information. */ | 821 | /* Now read in all of the header information. */ |
| @@ -874,35 +876,36 @@ static int load_irix_library(struct file *file) | |||
| 874 | * phdrs there are in the USER_PHDRP array. We return the vaddr the | 876 | * phdrs there are in the USER_PHDRP array. We return the vaddr the |
| 875 | * first phdr was successfully mapped to. | 877 | * first phdr was successfully mapped to. |
| 876 | */ | 878 | */ |
| 877 | unsigned long irix_mapelf(int fd, struct elf_phdr *user_phdrp, int cnt) | 879 | unsigned long irix_mapelf(int fd, struct elf_phdr __user *user_phdrp, int cnt) |
| 878 | { | 880 | { |
| 879 | struct elf_phdr *hp; | 881 | unsigned long type, vaddr, filesz, offset, flags; |
| 882 | struct elf_phdr __user *hp; | ||
| 880 | struct file *filp; | 883 | struct file *filp; |
| 881 | int i, retval; | 884 | int i, retval; |
| 882 | 885 | ||
| 883 | #ifdef DEBUG_ELF | 886 | pr_debug("irix_mapelf: fd[%d] user_phdrp[%p] cnt[%d]\n", |
| 884 | printk("irix_mapelf: fd[%d] user_phdrp[%p] cnt[%d]\n", | 887 | fd, user_phdrp, cnt); |
| 885 | fd, user_phdrp, cnt); | ||
| 886 | #endif | ||
| 887 | 888 | ||
| 888 | /* First get the verification out of the way. */ | 889 | /* First get the verification out of the way. */ |
| 889 | hp = user_phdrp; | 890 | hp = user_phdrp; |
| 890 | if (!access_ok(VERIFY_READ, hp, (sizeof(struct elf_phdr) * cnt))) { | 891 | if (!access_ok(VERIFY_READ, hp, (sizeof(struct elf_phdr) * cnt))) { |
| 891 | #ifdef DEBUG_ELF | 892 | pr_debug("irix_mapelf: bad pointer to ELF PHDR!\n"); |
| 892 | printk("irix_mapelf: access_ok fails!\n"); | 893 | |
| 893 | #endif | ||
| 894 | return -EFAULT; | 894 | return -EFAULT; |
| 895 | } | 895 | } |
| 896 | 896 | ||
| 897 | #ifdef DEBUG_ELF | 897 | #ifdef DEBUG |
| 898 | dump_phdrs(user_phdrp, cnt); | 898 | dump_phdrs(user_phdrp, cnt); |
| 899 | #endif | 899 | #endif |
| 900 | 900 | ||
| 901 | for(i = 0; i < cnt; i++, hp++) | 901 | for (i = 0; i < cnt; i++, hp++) { |
| 902 | if(hp->p_type != PT_LOAD) { | 902 | if (__get_user(type, &hp->p_type)) |
| 903 | return -EFAULT; | ||
| 904 | if (type != PT_LOAD) { | ||
| 903 | printk("irix_mapelf: One section is not PT_LOAD!\n"); | 905 | printk("irix_mapelf: One section is not PT_LOAD!\n"); |
| 904 | return -ENOEXEC; | 906 | return -ENOEXEC; |
| 905 | } | 907 | } |
| 908 | } | ||
| 906 | 909 | ||
| 907 | filp = fget(fd); | 910 | filp = fget(fd); |
| 908 | if (!filp) | 911 | if (!filp) |
| @@ -917,29 +920,40 @@ unsigned long irix_mapelf(int fd, struct elf_phdr *user_phdrp, int cnt) | |||
| 917 | for(i = 0; i < cnt; i++, hp++) { | 920 | for(i = 0; i < cnt; i++, hp++) { |
| 918 | int prot; | 921 | int prot; |
| 919 | 922 | ||
| 920 | prot = (hp->p_flags & PF_R) ? PROT_READ : 0; | 923 | retval = __get_user(vaddr, &hp->p_vaddr); |
| 921 | prot |= (hp->p_flags & PF_W) ? PROT_WRITE : 0; | 924 | retval |= __get_user(filesz, &hp->p_filesz); |
| 922 | prot |= (hp->p_flags & PF_X) ? PROT_EXEC : 0; | 925 | retval |= __get_user(offset, &hp->p_offset); |
| 926 | retval |= __get_user(flags, &hp->p_flags); | ||
| 927 | if (retval) | ||
| 928 | return retval; | ||
| 929 | |||
| 930 | prot = (flags & PF_R) ? PROT_READ : 0; | ||
| 931 | prot |= (flags & PF_W) ? PROT_WRITE : 0; | ||
| 932 | prot |= (flags & PF_X) ? PROT_EXEC : 0; | ||
| 933 | |||
| 923 | down_write(¤t->mm->mmap_sem); | 934 | down_write(¤t->mm->mmap_sem); |
| 924 | retval = do_mmap(filp, (hp->p_vaddr & 0xfffff000), | 935 | retval = do_mmap(filp, (vaddr & 0xfffff000), |
| 925 | (hp->p_filesz + (hp->p_vaddr & 0xfff)), | 936 | (filesz + (vaddr & 0xfff)), |
| 926 | prot, (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), | 937 | prot, (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), |
| 927 | (hp->p_offset & 0xfffff000)); | 938 | (offset & 0xfffff000)); |
| 928 | up_write(¤t->mm->mmap_sem); | 939 | up_write(¤t->mm->mmap_sem); |
| 929 | 940 | ||
| 930 | if(retval != (hp->p_vaddr & 0xfffff000)) { | 941 | if (retval != (vaddr & 0xfffff000)) { |
| 931 | printk("irix_mapelf: do_mmap fails with %d!\n", retval); | 942 | printk("irix_mapelf: do_mmap fails with %d!\n", retval); |
| 932 | fput(filp); | 943 | fput(filp); |
| 933 | return retval; | 944 | return retval; |
| 934 | } | 945 | } |
| 935 | } | 946 | } |
| 936 | 947 | ||
| 937 | #ifdef DEBUG_ELF | 948 | pr_debug("irix_mapelf: Success, returning %08lx\n", |
| 938 | printk("irix_mapelf: Success, returning %08lx\n", | 949 | (unsigned long) user_phdrp->p_vaddr); |
| 939 | (unsigned long) user_phdrp->p_vaddr); | 950 | |
| 940 | #endif | ||
| 941 | fput(filp); | 951 | fput(filp); |
| 942 | return user_phdrp->p_vaddr; | 952 | |
| 953 | if (__get_user(vaddr, &user_phdrp->p_vaddr)) | ||
| 954 | return -EFAULT; | ||
| 955 | |||
| 956 | return vaddr; | ||
| 943 | } | 957 | } |
| 944 | 958 | ||
| 945 | /* | 959 | /* |
| @@ -952,9 +966,9 @@ unsigned long irix_mapelf(int fd, struct elf_phdr *user_phdrp, int cnt) | |||
| 952 | /* These are the only things you should do on a core-file: use only these | 966 | /* These are the only things you should do on a core-file: use only these |
| 953 | * functions to write out all the necessary info. | 967 | * functions to write out all the necessary info. |
| 954 | */ | 968 | */ |
| 955 | static int dump_write(struct file *file, const void *addr, int nr) | 969 | static int dump_write(struct file *file, const void __user *addr, int nr) |
| 956 | { | 970 | { |
| 957 | return file->f_op->write(file, addr, nr, &file->f_pos) == nr; | 971 | return file->f_op->write(file, (const char __user *) addr, nr, &file->f_pos) == nr; |
| 958 | } | 972 | } |
| 959 | 973 | ||
| 960 | static int dump_seek(struct file *file, off_t off) | 974 | static int dump_seek(struct file *file, off_t off) |
| @@ -1073,7 +1087,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) | |||
| 1073 | /* Count what's needed to dump, up to the limit of coredump size. */ | 1087 | /* Count what's needed to dump, up to the limit of coredump size. */ |
| 1074 | segs = 0; | 1088 | segs = 0; |
| 1075 | size = 0; | 1089 | size = 0; |
| 1076 | for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { | 1090 | for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { |
| 1077 | if (maydump(vma)) | 1091 | if (maydump(vma)) |
| 1078 | { | 1092 | { |
| 1079 | int sz = vma->vm_end-vma->vm_start; | 1093 | int sz = vma->vm_end-vma->vm_start; |
| @@ -1187,9 +1201,9 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) | |||
| 1187 | 1201 | ||
| 1188 | len = current->mm->arg_end - current->mm->arg_start; | 1202 | len = current->mm->arg_end - current->mm->arg_start; |
| 1189 | len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len; | 1203 | len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len; |
| 1190 | copy_from_user(&psinfo.pr_psargs, | 1204 | (void *) copy_from_user(&psinfo.pr_psargs, |
| 1191 | (const char *)current->mm->arg_start, len); | 1205 | (const char __user *)current->mm->arg_start, len); |
| 1192 | for(i = 0; i < len; i++) | 1206 | for (i = 0; i < len; i++) |
| 1193 | if (psinfo.pr_psargs[i] == 0) | 1207 | if (psinfo.pr_psargs[i] == 0) |
| 1194 | psinfo.pr_psargs[i] = ' '; | 1208 | psinfo.pr_psargs[i] = ' '; |
| 1195 | psinfo.pr_psargs[len] = 0; | 1209 | psinfo.pr_psargs[len] = 0; |
| @@ -1256,8 +1270,10 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) | |||
| 1256 | phdr.p_memsz = sz; | 1270 | phdr.p_memsz = sz; |
| 1257 | offset += phdr.p_filesz; | 1271 | offset += phdr.p_filesz; |
| 1258 | phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; | 1272 | phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; |
| 1259 | if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W; | 1273 | if (vma->vm_flags & VM_WRITE) |
| 1260 | if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X; | 1274 | phdr.p_flags |= PF_W; |
| 1275 | if (vma->vm_flags & VM_EXEC) | ||
| 1276 | phdr.p_flags |= PF_X; | ||
| 1261 | phdr.p_align = PAGE_SIZE; | 1277 | phdr.p_align = PAGE_SIZE; |
| 1262 | 1278 | ||
| 1263 | DUMP_WRITE(&phdr, sizeof(phdr)); | 1279 | DUMP_WRITE(&phdr, sizeof(phdr)); |
| @@ -1283,7 +1299,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) | |||
| 1283 | #ifdef DEBUG | 1299 | #ifdef DEBUG |
| 1284 | printk("elf_core_dump: writing %08lx %lx\n", addr, len); | 1300 | printk("elf_core_dump: writing %08lx %lx\n", addr, len); |
| 1285 | #endif | 1301 | #endif |
| 1286 | DUMP_WRITE((void *)addr, len); | 1302 | DUMP_WRITE((void __user *)addr, len); |
| 1287 | } | 1303 | } |
| 1288 | 1304 | ||
| 1289 | if ((off_t) file->f_pos != offset) { | 1305 | if ((off_t) file->f_pos != offset) { |
| @@ -1299,7 +1315,7 @@ end_coredump: | |||
| 1299 | 1315 | ||
| 1300 | static int __init init_irix_binfmt(void) | 1316 | static int __init init_irix_binfmt(void) |
| 1301 | { | 1317 | { |
| 1302 | int init_inventory(void); | 1318 | extern int init_inventory(void); |
| 1303 | extern asmlinkage unsigned long sys_call_table; | 1319 | extern asmlinkage unsigned long sys_call_table; |
| 1304 | extern asmlinkage unsigned long sys_call_table_irix5; | 1320 | extern asmlinkage unsigned long sys_call_table_irix5; |
| 1305 | 1321 | ||
| @@ -1318,7 +1334,9 @@ static int __init init_irix_binfmt(void) | |||
| 1318 | 1334 | ||
| 1319 | static void __exit exit_irix_binfmt(void) | 1335 | static void __exit exit_irix_binfmt(void) |
| 1320 | { | 1336 | { |
| 1321 | /* Remove the IRIX ELF loaders. */ | 1337 | /* |
| 1338 | * Remove the Irix ELF loader. | ||
| 1339 | */ | ||
| 1322 | unregister_binfmt(&irix_format); | 1340 | unregister_binfmt(&irix_format); |
| 1323 | } | 1341 | } |
| 1324 | 1342 | ||
