diff options
Diffstat (limited to 'arch/mips/kernel/irixelf.c')
-rw-r--r-- | arch/mips/kernel/irixelf.c | 254 |
1 files changed, 133 insertions, 121 deletions
diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c index 4af20cd91f9f..10d3644e3608 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); |
@@ -692,7 +697,6 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) | |||
692 | /* Do this so that we can load the interpreter, if need be. We will | 697 | /* Do this so that we can load the interpreter, if need be. We will |
693 | * change some of these later. | 698 | * change some of these later. |
694 | */ | 699 | */ |
695 | set_mm_counter(current->mm, rss, 0); | ||
696 | setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT); | 700 | setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT); |
697 | current->mm->start_stack = bprm->p; | 701 | current->mm->start_stack = bprm->p; |
698 | 702 | ||
@@ -746,18 +750,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 | 750 | * IRIX maps a page at 0x200000 which holds some system |
747 | * information. Programs depend on this. | 751 | * information. Programs depend on this. |
748 | */ | 752 | */ |
749 | irix_map_prda_page (); | 753 | irix_map_prda_page(); |
750 | 754 | ||
751 | padzero(elf_bss); | 755 | padzero(elf_bss); |
752 | 756 | ||
753 | #ifdef DEBUG_ELF | 757 | pr_debug("(start_brk) %lx\n" , (long) current->mm->start_brk); |
754 | printk("(start_brk) %lx\n" , (long) current->mm->start_brk); | 758 | pr_debug("(end_code) %lx\n" , (long) current->mm->end_code); |
755 | printk("(end_code) %lx\n" , (long) current->mm->end_code); | 759 | pr_debug("(start_code) %lx\n" , (long) current->mm->start_code); |
756 | printk("(start_code) %lx\n" , (long) current->mm->start_code); | 760 | pr_debug("(end_data) %lx\n" , (long) current->mm->end_data); |
757 | printk("(end_data) %lx\n" , (long) current->mm->end_data); | 761 | pr_debug("(start_stack) %lx\n" , (long) current->mm->start_stack); |
758 | printk("(start_stack) %lx\n" , (long) current->mm->start_stack); | 762 | pr_debug("(brk) %lx\n" , (long) current->mm->brk); |
759 | printk("(brk) %lx\n" , (long) current->mm->brk); | ||
760 | #endif | ||
761 | 763 | ||
762 | #if 0 /* XXX No fucking way dude... */ | 764 | #if 0 /* XXX No fucking way dude... */ |
763 | /* Why this, you ask??? Well SVr4 maps page 0 as read-only, | 765 | /* Why this, you ask??? Well SVr4 maps page 0 as read-only, |
@@ -782,8 +784,7 @@ out_free_dentry: | |||
782 | allow_write_access(interpreter); | 784 | allow_write_access(interpreter); |
783 | fput(interpreter); | 785 | fput(interpreter); |
784 | out_free_interp: | 786 | out_free_interp: |
785 | if (elf_interpreter) | 787 | kfree(elf_interpreter); |
786 | kfree(elf_interpreter); | ||
787 | out_free_file: | 788 | out_free_file: |
788 | out_free_ph: | 789 | out_free_ph: |
789 | kfree (elf_phdata); | 790 | kfree (elf_phdata); |
@@ -813,7 +814,7 @@ static int load_irix_library(struct file *file) | |||
813 | 814 | ||
814 | /* First of all, some simple consistency checks. */ | 815 | /* First of all, some simple consistency checks. */ |
815 | if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || | 816 | if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || |
816 | !irix_elf_check_arch(&elf_ex) || !file->f_op->mmap) | 817 | !file->f_op->mmap) |
817 | return -ENOEXEC; | 818 | return -ENOEXEC; |
818 | 819 | ||
819 | /* Now read in all of the header information. */ | 820 | /* Now read in all of the header information. */ |
@@ -874,35 +875,36 @@ static int load_irix_library(struct file *file) | |||
874 | * phdrs there are in the USER_PHDRP array. We return the vaddr the | 875 | * phdrs there are in the USER_PHDRP array. We return the vaddr the |
875 | * first phdr was successfully mapped to. | 876 | * first phdr was successfully mapped to. |
876 | */ | 877 | */ |
877 | unsigned long irix_mapelf(int fd, struct elf_phdr *user_phdrp, int cnt) | 878 | unsigned long irix_mapelf(int fd, struct elf_phdr __user *user_phdrp, int cnt) |
878 | { | 879 | { |
879 | struct elf_phdr *hp; | 880 | unsigned long type, vaddr, filesz, offset, flags; |
881 | struct elf_phdr __user *hp; | ||
880 | struct file *filp; | 882 | struct file *filp; |
881 | int i, retval; | 883 | int i, retval; |
882 | 884 | ||
883 | #ifdef DEBUG_ELF | 885 | pr_debug("irix_mapelf: fd[%d] user_phdrp[%p] cnt[%d]\n", |
884 | printk("irix_mapelf: fd[%d] user_phdrp[%p] cnt[%d]\n", | 886 | fd, user_phdrp, cnt); |
885 | fd, user_phdrp, cnt); | ||
886 | #endif | ||
887 | 887 | ||
888 | /* First get the verification out of the way. */ | 888 | /* First get the verification out of the way. */ |
889 | hp = user_phdrp; | 889 | hp = user_phdrp; |
890 | if (!access_ok(VERIFY_READ, hp, (sizeof(struct elf_phdr) * cnt))) { | 890 | if (!access_ok(VERIFY_READ, hp, (sizeof(struct elf_phdr) * cnt))) { |
891 | #ifdef DEBUG_ELF | 891 | pr_debug("irix_mapelf: bad pointer to ELF PHDR!\n"); |
892 | printk("irix_mapelf: access_ok fails!\n"); | 892 | |
893 | #endif | ||
894 | return -EFAULT; | 893 | return -EFAULT; |
895 | } | 894 | } |
896 | 895 | ||
897 | #ifdef DEBUG_ELF | 896 | #ifdef DEBUG |
898 | dump_phdrs(user_phdrp, cnt); | 897 | dump_phdrs(user_phdrp, cnt); |
899 | #endif | 898 | #endif |
900 | 899 | ||
901 | for(i = 0; i < cnt; i++, hp++) | 900 | for (i = 0; i < cnt; i++, hp++) { |
902 | if(hp->p_type != PT_LOAD) { | 901 | if (__get_user(type, &hp->p_type)) |
902 | return -EFAULT; | ||
903 | if (type != PT_LOAD) { | ||
903 | printk("irix_mapelf: One section is not PT_LOAD!\n"); | 904 | printk("irix_mapelf: One section is not PT_LOAD!\n"); |
904 | return -ENOEXEC; | 905 | return -ENOEXEC; |
905 | } | 906 | } |
907 | } | ||
906 | 908 | ||
907 | filp = fget(fd); | 909 | filp = fget(fd); |
908 | if (!filp) | 910 | if (!filp) |
@@ -917,29 +919,40 @@ unsigned long irix_mapelf(int fd, struct elf_phdr *user_phdrp, int cnt) | |||
917 | for(i = 0; i < cnt; i++, hp++) { | 919 | for(i = 0; i < cnt; i++, hp++) { |
918 | int prot; | 920 | int prot; |
919 | 921 | ||
920 | prot = (hp->p_flags & PF_R) ? PROT_READ : 0; | 922 | retval = __get_user(vaddr, &hp->p_vaddr); |
921 | prot |= (hp->p_flags & PF_W) ? PROT_WRITE : 0; | 923 | retval |= __get_user(filesz, &hp->p_filesz); |
922 | prot |= (hp->p_flags & PF_X) ? PROT_EXEC : 0; | 924 | retval |= __get_user(offset, &hp->p_offset); |
925 | retval |= __get_user(flags, &hp->p_flags); | ||
926 | if (retval) | ||
927 | return retval; | ||
928 | |||
929 | prot = (flags & PF_R) ? PROT_READ : 0; | ||
930 | prot |= (flags & PF_W) ? PROT_WRITE : 0; | ||
931 | prot |= (flags & PF_X) ? PROT_EXEC : 0; | ||
932 | |||
923 | down_write(¤t->mm->mmap_sem); | 933 | down_write(¤t->mm->mmap_sem); |
924 | retval = do_mmap(filp, (hp->p_vaddr & 0xfffff000), | 934 | retval = do_mmap(filp, (vaddr & 0xfffff000), |
925 | (hp->p_filesz + (hp->p_vaddr & 0xfff)), | 935 | (filesz + (vaddr & 0xfff)), |
926 | prot, (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), | 936 | prot, (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), |
927 | (hp->p_offset & 0xfffff000)); | 937 | (offset & 0xfffff000)); |
928 | up_write(¤t->mm->mmap_sem); | 938 | up_write(¤t->mm->mmap_sem); |
929 | 939 | ||
930 | if(retval != (hp->p_vaddr & 0xfffff000)) { | 940 | if (retval != (vaddr & 0xfffff000)) { |
931 | printk("irix_mapelf: do_mmap fails with %d!\n", retval); | 941 | printk("irix_mapelf: do_mmap fails with %d!\n", retval); |
932 | fput(filp); | 942 | fput(filp); |
933 | return retval; | 943 | return retval; |
934 | } | 944 | } |
935 | } | 945 | } |
936 | 946 | ||
937 | #ifdef DEBUG_ELF | 947 | pr_debug("irix_mapelf: Success, returning %08lx\n", |
938 | printk("irix_mapelf: Success, returning %08lx\n", | 948 | (unsigned long) user_phdrp->p_vaddr); |
939 | (unsigned long) user_phdrp->p_vaddr); | 949 | |
940 | #endif | ||
941 | fput(filp); | 950 | fput(filp); |
942 | return user_phdrp->p_vaddr; | 951 | |
952 | if (__get_user(vaddr, &user_phdrp->p_vaddr)) | ||
953 | return -EFAULT; | ||
954 | |||
955 | return vaddr; | ||
943 | } | 956 | } |
944 | 957 | ||
945 | /* | 958 | /* |
@@ -952,9 +965,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 | 965 | /* These are the only things you should do on a core-file: use only these |
953 | * functions to write out all the necessary info. | 966 | * functions to write out all the necessary info. |
954 | */ | 967 | */ |
955 | static int dump_write(struct file *file, const void *addr, int nr) | 968 | static int dump_write(struct file *file, const void __user *addr, int nr) |
956 | { | 969 | { |
957 | return file->f_op->write(file, addr, nr, &file->f_pos) == nr; | 970 | return file->f_op->write(file, (const char __user *) addr, nr, &file->f_pos) == nr; |
958 | } | 971 | } |
959 | 972 | ||
960 | static int dump_seek(struct file *file, off_t off) | 973 | static int dump_seek(struct file *file, off_t off) |
@@ -1064,8 +1077,8 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) | |||
1064 | struct elfhdr elf; | 1077 | struct elfhdr elf; |
1065 | off_t offset = 0, dataoff; | 1078 | off_t offset = 0, dataoff; |
1066 | int limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; | 1079 | int limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; |
1067 | int numnote = 4; | 1080 | int numnote = 3; |
1068 | struct memelfnote notes[4]; | 1081 | struct memelfnote notes[3]; |
1069 | struct elf_prstatus prstatus; /* NT_PRSTATUS */ | 1082 | struct elf_prstatus prstatus; /* NT_PRSTATUS */ |
1070 | elf_fpregset_t fpu; /* NT_PRFPREG */ | 1083 | elf_fpregset_t fpu; /* NT_PRFPREG */ |
1071 | struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ | 1084 | struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ |
@@ -1073,7 +1086,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. */ | 1086 | /* Count what's needed to dump, up to the limit of coredump size. */ |
1074 | segs = 0; | 1087 | segs = 0; |
1075 | size = 0; | 1088 | size = 0; |
1076 | for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { | 1089 | for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { |
1077 | if (maydump(vma)) | 1090 | if (maydump(vma)) |
1078 | { | 1091 | { |
1079 | int sz = vma->vm_end-vma->vm_start; | 1092 | int sz = vma->vm_end-vma->vm_start; |
@@ -1187,9 +1200,9 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) | |||
1187 | 1200 | ||
1188 | len = current->mm->arg_end - current->mm->arg_start; | 1201 | len = current->mm->arg_end - current->mm->arg_start; |
1189 | len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len; | 1202 | len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len; |
1190 | copy_from_user(&psinfo.pr_psargs, | 1203 | (void *) copy_from_user(&psinfo.pr_psargs, |
1191 | (const char *)current->mm->arg_start, len); | 1204 | (const char __user *)current->mm->arg_start, len); |
1192 | for(i = 0; i < len; i++) | 1205 | for (i = 0; i < len; i++) |
1193 | if (psinfo.pr_psargs[i] == 0) | 1206 | if (psinfo.pr_psargs[i] == 0) |
1194 | psinfo.pr_psargs[i] = ' '; | 1207 | psinfo.pr_psargs[i] = ' '; |
1195 | psinfo.pr_psargs[len] = 0; | 1208 | psinfo.pr_psargs[len] = 0; |
@@ -1198,20 +1211,15 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) | |||
1198 | } | 1211 | } |
1199 | strlcpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname)); | 1212 | strlcpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname)); |
1200 | 1213 | ||
1201 | notes[2].name = "CORE"; | ||
1202 | notes[2].type = NT_TASKSTRUCT; | ||
1203 | notes[2].datasz = sizeof(*current); | ||
1204 | notes[2].data = current; | ||
1205 | |||
1206 | /* Try to dump the FPU. */ | 1214 | /* Try to dump the FPU. */ |
1207 | prstatus.pr_fpvalid = dump_fpu (regs, &fpu); | 1215 | prstatus.pr_fpvalid = dump_fpu (regs, &fpu); |
1208 | if (!prstatus.pr_fpvalid) { | 1216 | if (!prstatus.pr_fpvalid) { |
1209 | numnote--; | 1217 | numnote--; |
1210 | } else { | 1218 | } else { |
1211 | notes[3].name = "CORE"; | 1219 | notes[2].name = "CORE"; |
1212 | notes[3].type = NT_PRFPREG; | 1220 | notes[2].type = NT_PRFPREG; |
1213 | notes[3].datasz = sizeof(fpu); | 1221 | notes[2].datasz = sizeof(fpu); |
1214 | notes[3].data = &fpu; | 1222 | notes[2].data = &fpu; |
1215 | } | 1223 | } |
1216 | 1224 | ||
1217 | /* Write notes phdr entry. */ | 1225 | /* Write notes phdr entry. */ |
@@ -1256,8 +1264,10 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) | |||
1256 | phdr.p_memsz = sz; | 1264 | phdr.p_memsz = sz; |
1257 | offset += phdr.p_filesz; | 1265 | offset += phdr.p_filesz; |
1258 | phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; | 1266 | phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; |
1259 | if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W; | 1267 | if (vma->vm_flags & VM_WRITE) |
1260 | if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X; | 1268 | phdr.p_flags |= PF_W; |
1269 | if (vma->vm_flags & VM_EXEC) | ||
1270 | phdr.p_flags |= PF_X; | ||
1261 | phdr.p_align = PAGE_SIZE; | 1271 | phdr.p_align = PAGE_SIZE; |
1262 | 1272 | ||
1263 | DUMP_WRITE(&phdr, sizeof(phdr)); | 1273 | DUMP_WRITE(&phdr, sizeof(phdr)); |
@@ -1283,7 +1293,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) | |||
1283 | #ifdef DEBUG | 1293 | #ifdef DEBUG |
1284 | printk("elf_core_dump: writing %08lx %lx\n", addr, len); | 1294 | printk("elf_core_dump: writing %08lx %lx\n", addr, len); |
1285 | #endif | 1295 | #endif |
1286 | DUMP_WRITE((void *)addr, len); | 1296 | DUMP_WRITE((void __user *)addr, len); |
1287 | } | 1297 | } |
1288 | 1298 | ||
1289 | if ((off_t) file->f_pos != offset) { | 1299 | if ((off_t) file->f_pos != offset) { |
@@ -1299,7 +1309,7 @@ end_coredump: | |||
1299 | 1309 | ||
1300 | static int __init init_irix_binfmt(void) | 1310 | static int __init init_irix_binfmt(void) |
1301 | { | 1311 | { |
1302 | int init_inventory(void); | 1312 | extern int init_inventory(void); |
1303 | extern asmlinkage unsigned long sys_call_table; | 1313 | extern asmlinkage unsigned long sys_call_table; |
1304 | extern asmlinkage unsigned long sys_call_table_irix5; | 1314 | extern asmlinkage unsigned long sys_call_table_irix5; |
1305 | 1315 | ||
@@ -1318,7 +1328,9 @@ static int __init init_irix_binfmt(void) | |||
1318 | 1328 | ||
1319 | static void __exit exit_irix_binfmt(void) | 1329 | static void __exit exit_irix_binfmt(void) |
1320 | { | 1330 | { |
1321 | /* Remove the IRIX ELF loaders. */ | 1331 | /* |
1332 | * Remove the Irix ELF loader. | ||
1333 | */ | ||
1322 | unregister_binfmt(&irix_format); | 1334 | unregister_binfmt(&irix_format); |
1323 | } | 1335 | } |
1324 | 1336 | ||