static int xout_amen(struct file *fp, struct xseg *sp, int pageable, u_long *addrp, struct xexec *xexec, struct pt_regs *regs, int impure) { u_long bss_size, bss_base, ce; int err = 0; ce = cap_mmap(0); cap_mmap(1); bss_size = sp->xs_vsize - sp->xs_psize; bss_base = sp->xs_rbase + sp->xs_psize; /* * If it is a text segment update the code boundary * markers. If it is a data segment update the data * boundary markers. */ if (sp->xs_type == XS_TTEXT || sp->xs_type == XS_TDATA) { if ((sp->xs_rbase + sp->xs_psize) > current->mm->end_code) current->mm->end_code = (sp->xs_rbase + sp->xs_psize); } if ((sp->xs_rbase + sp->xs_vsize) > current->mm->brk) { current->mm->start_brk = current->mm->brk = PAGE_ALIGN(sp->xs_rbase + sp->xs_vsize); } if (!pageable) { dprintk(KERN_DEBUG "xout: Null map 0x%08lx, length 0x%08lx\n", sp->xs_rbase, sp->xs_vsize); down_write(¤t->mm->mmap_sem); err = do_mmap(NULL, sp->xs_rbase, sp->xs_vsize, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE|MAP_32BIT, 0); up_write(¤t->mm->mmap_sem); goto out; } dprintk(KERN_DEBUG "xout: mmap to 0x%08lx from 0x%08lx, length 0x%08lx\n", sp->xs_rbase, sp->xs_filpos, sp->xs_psize); if (sp->xs_attr & XS_APURE) { down_write(¤t->mm->mmap_sem); err = do_mmap(fp, sp->xs_rbase, sp->xs_psize, PROT_READ|PROT_EXEC, MAP_FIXED|MAP_SHARED|MAP_32BIT, sp->xs_filpos); up_write(¤t->mm->mmap_sem); } else { down_write(¤t->mm->mmap_sem); err = do_mmap(fp, sp->xs_rbase, sp->xs_psize, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE | MAP_32BIT, sp->xs_filpos); up_write(¤t->mm->mmap_sem); } if (err < 0) goto out; /* * Map uninitialised data. */ if (bss_size) { if (bss_base & PAGE_MASK) { clear_memory(bss_base, PAGE_ALIGN(bss_base)-bss_base); bss_size -= (PAGE_ALIGN(bss_base) - bss_base); bss_base = PAGE_ALIGN(bss_base); } dprintk(KERN_DEBUG "xout: Null map 0x%08lx, length 0x%08lx\n", bss_base, bss_size); down_write(¤t->mm->mmap_sem); err = do_mmap(NULL, bss_base, bss_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_32BIT, 0); up_write(¤t->mm->mmap_sem); } out: if (!ce) cap_mmap(2); return (err); }
/* * Helper function to process the load operation. */ static int coff_load_object(struct linux_binprm *bprm, struct pt_regs *regs, int binary) { COFF_FILHDR *coff_hdr = NULL; COFF_SCNHDR *text_sect = NULL, *data_sect = NULL, *bss_sect = NULL, *sect_bufr = NULL, *sect_ptr = NULL; int text_count = 0, data_count = 0, bss_count = 0, lib_count = 0; coff_section text, data, bss; u_long start_addr = 0, p = bprm->p, m_addr, lPers; short flags, aout_size = 0; int pageable = 1, sections = 0, status = 0, i, ce; int coff_exec_fileno; mm_segment_t old_fs; lPers = abi_personality((char *)_BX(regs)); ce = cap_mmap(0); coff_hdr = (COFF_FILHDR *)bprm->buf; /* * Validate the magic value for the object file. */ if (COFF_I386BADMAG(*coff_hdr)) return -ENOEXEC; flags = COFF_SHORT(coff_hdr->f_flags); /* * The object file should have 32 BIT little endian format. Do not allow * it to have the 16 bit object file flag set as Linux is not able to run * on the 80286/80186/8086. */ if ((flags & (COFF_F_AR32WR | COFF_F_AR16WR)) != COFF_F_AR32WR) return -ENOEXEC; /* * If the file is not executable then reject the execution. This means * that there must not be external references. */ if ((flags & COFF_F_EXEC) == 0) return -ENOEXEC; /* * Extract the header information which we need. */ sections = COFF_SHORT(coff_hdr->f_nscns); /* Number of sections */ aout_size = COFF_SHORT(coff_hdr->f_opthdr); /* Size of opt. headr */ /* * There must be at least one section. */ if (!sections) return -ENOEXEC; if (!bprm->file->f_op->mmap) pageable = 0; if (!(sect_bufr = kmalloc(sections * COFF_SCNHSZ, GFP_KERNEL))) { printk(KERN_WARNING "coff: kmalloc failed\n"); return -ENOMEM; } status = kernel_read(bprm->file, aout_size + COFF_FILHSZ, (char *)sect_bufr, sections * COFF_SCNHSZ); if (status < 0) { printk(KERN_WARNING "coff: unable to read\n"); goto out_free_buf; } status = get_unused_fd(); if (status < 0) { printk(KERN_WARNING "coff: unable to get free fs\n"); goto out_free_buf; } get_file(bprm->file); fd_install(coff_exec_fileno = status, bprm->file); /* * Loop through the sections and find the various types */ sect_ptr = sect_bufr; for (i = 0; i < sections; i++) { long int sect_flags = COFF_LONG(sect_ptr->s_flags); switch (sect_flags) { case COFF_STYP_TEXT: status |= coff_isaligned(sect_ptr); text_sect = sect_ptr; text_count++; break; case COFF_STYP_DATA: status |= coff_isaligned(sect_ptr); data_sect = sect_ptr; data_count++; break; case COFF_STYP_BSS: bss_sect = sect_ptr; bss_count++; break; case COFF_STYP_LIB: lib_count++; break; default: break; } sect_ptr = (COFF_SCNHDR *) & ((char *) sect_ptr)[COFF_SCNHSZ]; } /* * If any of the sections weren't properly aligned we aren't * going to be able to demand page this executable. Note that * at this stage the *only* excuse for having status <= 0 is if * the alignment test failed. */ if (status < 0) pageable = 0; /* * Ensure that there are the required sections. There must be one * text sections and one each of the data and bss sections for an * executable. A library may or may not have a data / bss section. */ if (text_count != 1) { status = -ENOEXEC; goto out_free_file; } if (binary && (data_count != 1 || bss_count != 1)) { status = -ENOEXEC; goto out_free_file; } /* * If there is no additional header then assume the file starts * at the first byte of the text section. This may not be the * proper place, so the best solution is to include the optional * header. A shared library __MUST__ have an optional header to * indicate that it is a shared library. */ if (aout_size == 0) { if (!binary) { status = -ENOEXEC; goto out_free_file; } start_addr = COFF_LONG(text_sect->s_vaddr); } else if (aout_size < (short) COFF_AOUTSZ) { status = -ENOEXEC; goto out_free_file; } else { COFF_AOUTHDR *aout_hdr; short aout_magic; aout_hdr = (COFF_AOUTHDR *) &((char *)coff_hdr)[COFF_FILHSZ]; aout_magic = COFF_SHORT(aout_hdr->magic); /* * Validate the magic number in the a.out header. If it is valid then * update the starting symbol location. Do not accept these file formats * when loading a shared library. */ switch (aout_magic) { case COFF_OMAGIC: case COFF_ZMAGIC: case COFF_STMAGIC: if (!binary) { status = -ENOEXEC; goto out_free_file; } start_addr = (u_int)COFF_LONG(aout_hdr->entry); break; /* * Magic value for a shared library. This is valid only when * loading a shared library. * * (There is no need for a start_addr. It won't be used.) */ case COFF_SHMAGIC: if (!binary) break; /* FALLTHROUGH */ default: status = -ENOEXEC; goto out_free_file; } } /* * Generate the proper values for the text fields * * THIS IS THE POINT OF NO RETURN. THE NEW PROCESS WILL TRAP OUT SHOULD * SOMETHING FAIL IN THE LOAD SEQUENCE FROM THIS POINT ONWARD. */ text.scnptr = COFF_LONG(text_sect->s_scnptr); text.size = COFF_LONG(text_sect->s_size); text.vaddr = COFF_LONG(text_sect->s_vaddr); /* * Generate the proper values for the data fields */ if (data_sect != NULL) { data.scnptr = COFF_LONG(data_sect->s_scnptr); data.size = COFF_LONG(data_sect->s_size); data.vaddr = COFF_LONG(data_sect->s_vaddr); } else { data.scnptr = 0; data.size = 0; data.vaddr = 0; } /* * Generate the proper values for the bss fields */ if (bss_sect != NULL) { bss.size = COFF_LONG(bss_sect->s_size); bss.vaddr = COFF_LONG(bss_sect->s_vaddr); } else { bss.size = 0; bss.vaddr = 0; } /* * Flush the executable from memory. At this point the executable is * committed to being defined or a segmentation violation will occur. */ if (binary) { COFF_SCNHDR *sect_ptr2 = sect_bufr; u_long personality = PER_SVR3; int i; if ((status = flush_old_exec(bprm))) goto out_free_file; /* * Look for clues as to the system this binary was compiled * on in the comments section(s). * * Only look at the main binary, not the shared libraries * (or would it be better to prefer shared libraries over * binaries? Or could they be different???) */ for (i = 0; i < sections; i++) { long sect_flags = COFF_LONG(sect_ptr2->s_flags); if (sect_flags == COFF_STYP_INFO && (status = coff_parse_comments(bprm->file, sect_ptr2, &personality)) > 0) goto found; sect_ptr2 = (COFF_SCNHDR *) &((char *)sect_ptr2)[COFF_SCNHSZ]; } /* * If no .comments section was found there is no way to * figure out the personality. Odds on it is SCO though... */ personality = PER_SCOSVR3; found: if (lPers) personality = lPers; if ( (personality & 0xFF) == (current->personality & 0xFF) ) set_personality(0); set_personality(personality); #if defined(CONFIG_ABI_TRACE) abi_trace(ABI_TRACE_UNIMPL,"Personality %08lX assigned\n",personality); #endif #ifdef CONFIG_64BIT set_thread_flag(TIF_IA32); clear_thread_flag(TIF_ABI_PENDING); #endif current->mm->start_data = 0; current->mm->end_data = 0; current->mm->end_code = 0; current->mm->mmap = NULL; current->flags &= ~PF_FORKNOEXEC; #ifdef set_mm_counter #if _KSL > 14 set_mm_counter(current->mm, file_rss, 0); #else set_mm_counter(current->mm, rss, 0); #endif #else current->mm->rss = 0; #endif /* * Construct the parameter and environment * string table entries. */ #if _KSL > 10 if ((status = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT)) < 0) #else if ((status = setup_arg_pages(bprm, EXSTACK_DEFAULT)) < 0) #endif goto sigsegv; p = (u_long)coff_mktables((char *)bprm->p, bprm->argc, bprm->envc); current->mm->end_code = text.size + (current->mm->start_code = text.vaddr); current->mm->end_data = data.size + (current->mm->start_data = data.vaddr); current->mm->brk = bss.size + (current->mm->start_brk = bss.vaddr); current->mm->start_stack = p; #if _KSL > 28 install_exec_creds(bprm); #else compute_creds(bprm); #endif #if _KSL < 15 #ifdef CONFIG_64BIT __asm__ volatile ( "movl %0,%%fs; movl %0,%%es; movl %0,%%ds" : :"r" (0)); __asm__ volatile ( "pushf; cli; swapgs; movl %0,%%gs; mfence; swapgs; popf" : :"r" (0)); write_pda(oldrsp,p); _FLG(regs) = 0x200; #else __asm__ volatile ( "movl %0,%%fs ; movl %0,%%gs" : :"r" (0)); _DS(regs) = _ES(regs) = __USER_DS; #endif _SS(regs) = __USER_DS; _SP(regs) = p; _CS(regs) = __USER_CS; _IP(regs) = start_addr; set_fs(USER_DS); #else start_thread(regs, start_addr, p); #endif #ifdef CONFIG_64BIT __asm__ volatile("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS)); _SS(regs) = __USER32_DS; _CS(regs) = __USER32_CS; #endif } old_fs = get_fs(); set_fs(get_ds()); if (!pageable) { /* * Read the file from disk... * * XXX: untested. */ loff_t pos = data.scnptr; status = do_brk(text.vaddr, text.size); bprm->file->f_op->read(bprm->file, (char *)data.vaddr, data.scnptr, &pos); status = do_brk(data.vaddr, data.size); bprm->file->f_op->read(bprm->file, (char *)text.vaddr, text.scnptr, &pos); status = 0; } else { /* map the text pages...*/ cap_mmap(1); m_addr = map_coff(bprm->file, &text, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, text.scnptr & PAGE_MASK); if(!ce) cap_mmap(2); if (m_addr != (text.vaddr & PAGE_MASK)) { status = -ENOEXEC; set_fs(old_fs); goto out_free_file; } /* map the data pages */ if (data.size != 0) { cap_mmap(1); m_addr = map_coff(bprm->file, &data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, data.scnptr & PAGE_MASK); if(!ce) cap_mmap(2); if (m_addr != (data.vaddr & PAGE_MASK)) { status = -ENOEXEC; set_fs(old_fs); goto out_free_file; } } status = 0; } /* * Construct the bss data for the process. The bss ranges from the * end of the data (which may not be on a page boundary) to the end * of the bss section. Allocate any necessary pages for the data. */ if (bss.size != 0) { cap_mmap(1); down_write(¤t->mm->mmap_sem); do_mmap(NULL, PAGE_ALIGN(bss.vaddr), bss.size + bss.vaddr - PAGE_ALIGN(bss.vaddr), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_32BIT, 0); up_write(¤t->mm->mmap_sem); if(!ce) cap_mmap(2); if ((status = coff_clear_memory(bss.vaddr, bss.size)) < 0) { set_fs(old_fs); goto out_free_file; } } set_fs(old_fs); if (!binary) goto out_free_file; /* * Load any shared library for the executable. */ if (lib_count) status = coff_preload_shlibs(bprm, sect_bufr, sections); set_binfmt(&coff_format); /* * Generate any needed trap for this process. If an error occured then * generate a segmentation violation. If the process is being debugged * then generate the load trap. (Note: If this is a library load then * do not generate the trap here. Pass the error to the caller who * will do it for the process in the outer lay of this procedure call.) */ if (status < 0) { sigsegv: printk(KERN_WARNING "coff: trapping process with SEGV\n"); send_sig(SIGSEGV, current, 0); /* Generate the error trap */ } #ifdef CONFIG_PTRACE /* --- Red Hat specific handling --- */ #else else if (current->ptrace & PT_PTRACED) send_sig(SIGTRAP, current, 0); #endif /* We are committed. It can't fail */ status = 0; out_free_file: SYS(close,coff_exec_fileno); out_free_buf: kfree(sect_bufr); return (status); }