//-------------------------------------------------------------------------- int get_aout_file_format_index(linput_t *li) { exec ex; register int i = 0; if(qlread(li, &ex, sizeof(ex)) != sizeof(ex)) return false; if(N_BADMAG(ex)) { ex.a_info = swap32(ex.a_info); switch(N_MACHTYPE(ex)) { case M_386_NETBSD: case M_68K_NETBSD: case M_68K4K_NETBSD: case M_532_NETBSD: case M_SPARC_NETBSD: case M_PMAX_NETBSD: case M_VAX_NETBSD: case M_ALPHA_NETBSD: case M_ARM6_NETBSD: break; default: return false; } } switch(N_MAGIC(ex)) { case NMAGIC: ++i; case CMAGIC: ++i; case ZMAGIC: ++i; case OMAGIC: ++i; case QMAGIC: // msg("text=%d data=%d symsize=%d txtoff=%d sum=%d\n", ex.a_text, ex.a_data, // N_SYMSIZE(ex), N_TXTOFF(ex), ex.a_text + ex.a_data + N_SYMSIZE(ex) + N_TXTOFF(ex)); if ( qlsize(li) >= ex.a_text + ex.a_data + N_SYMSIZE(ex) + N_TXTOFF(ex) ) break; if ( N_MAGIC(ex) == ZMAGIC && qlsize(li) >= ex.a_text + ex.a_data + N_SYMSIZE(ex) ) { i = 5; // OpenBSD demand-paged break; } default: return false; } return i+1; }
// Печать заголовков файла, заданного именем void aout_info(char *Name) { char name83[11]; Exec exec; Make83Name(Name, name83); DirEntry Entry; if (FindEntry(0, name83, &Entry) == (uint)-1) { printf("Cannot open file '%s'!\n", Name); return; } LoadPart(&Entry, &exec, 0, sizeof(Exec)); printf("midmag\t= 0x%x\n", exec.a_midmag); printf("text\t= %d\n", exec.a_text); printf("data\t= %d\n", exec.a_data); printf("bss\t= %d\n", exec.a_bss); printf("syms\t= %d\n", exec.a_syms); printf("entry\t= 0x%x\n", exec.a_entry); printf("trsize\t= %d\n", exec.a_trsize); printf("drsize\t= %d\n", exec.a_drsize); printf("\nflags\t= 0x%x\n", N_FLAG(exec)); printf("machine\t= "); switch (N_MID(exec)) { case M_OLDSUN2: printf("OldSun2"); break; case M_68010: printf("m68010"); break; case M_68020: printf("m68020"); break; case M_SPARC: printf("sparc"); break; case M_386: printf("386"); break; case M_MIPS1: printf("mips1"); break; case M_MIPS2: printf("mips2"); break; default: printf("unknown?"); return; } printf("\n"); if (N_MID(exec) != M_386) { printf("Only 386's binaries are supported\n"); return; } printf("magic\t= "); switch (N_MAGIC(exec)) { case OMAGIC: printf("omagic"); break; case NMAGIC: printf("nmagic"); break; case ZMAGIC: printf("zmagic"); break; case QMAGIC: printf("qmagic"); break; case CMAGIC: printf("cmagic"); break; default: printf("bad magic"); return; } // Relocation_Info rels[100]; // FIXME: добавить вывод relocation records }
static unsigned long load_aout_interp(struct exec * interp_ex, int interpreter_fd) { unsigned long text_data, offset, elf_entry = ~0UL; char * addr; int retval; printf("WARNING: load_aout_interp() has not been tested at all!\n"); current->end_code = interp_ex->a_text; text_data = interp_ex->a_text + interp_ex->a_data; current->end_data = text_data; current->brk = interp_ex->a_bss + text_data; switch (N_MAGIC(*interp_ex)) { case OMAGIC: offset = 32; addr = (char *) 0; break; case ZMAGIC: case QMAGIC: offset = N_TXTOFF(*interp_ex); addr = (char *) N_TXTADDR(*interp_ex); break; default: goto out; } if ((unsigned long)addr + text_data < text_data) goto out; do_mmap(-1, 0, text_data, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, 0); retval = read_exec(interpreter_fd, offset, addr, text_data, 0); if (retval < 0) goto out; #if 0 flush_icache_range((unsigned long)addr, (unsigned long)addr + text_data); #endif do_mmap(-1, ELF_PAGESTART(text_data + ELF_EXEC_PAGESIZE - 1), interp_ex->a_bss, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, 0); elf_entry = interp_ex->a_entry; out: return elf_entry; }
static unsigned int load_aout_interp(struct exec * interp_ex, struct inode * interpreter_inode) { int retval; unsigned int elf_entry; current->mm->brk = interp_ex->a_bss + (current->mm->end_data = interp_ex->a_data + (current->mm->end_code = interp_ex->a_text)); elf_entry = interp_ex->a_entry; if (N_MAGIC(*interp_ex) == OMAGIC) { do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); retval = read_exec(interpreter_inode, 32, (char *) 0, interp_ex->a_text+interp_ex->a_data); } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) { do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); retval = read_exec(interpreter_inode, N_TXTOFF(*interp_ex) , (char *) N_TXTADDR(*interp_ex), interp_ex->a_text+interp_ex->a_data); } else retval = -1; if(retval >= 0) do_mmap(NULL, (interp_ex->a_text + interp_ex->a_data + 0xfff) & 0xfffff000, interp_ex->a_bss, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); if(retval < 0) return 0xffffffff; return elf_entry; }
int load_aout(const char *filename, target_phys_addr_t addr, int max_sz) { int fd, size, ret; struct exec e; uint32_t magic; fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) return -1; size = read(fd, &e, sizeof(e)); if (size < 0) goto fail; bswap_ahdr(&e); magic = N_MAGIC(e); switch (magic) { case ZMAGIC: case QMAGIC: case OMAGIC: if (e.a_text + e.a_data > max_sz) goto fail; lseek(fd, N_TXTOFF(e), SEEK_SET); size = read_targphys(fd, addr, e.a_text + e.a_data); if (size < 0) goto fail; break; case NMAGIC: if (N_DATADDR(e) + e.a_data > max_sz) goto fail; lseek(fd, N_TXTOFF(e), SEEK_SET); size = read_targphys(fd, addr, e.a_text); if (size < 0) goto fail; ret = read_targphys(fd, addr + N_DATADDR(e), e.a_data); if (ret < 0) goto fail; size += ret; break; default: goto fail; } close(fd); return size; fail: close(fd); return -1; }
static unsigned long load_aout_interp(struct exec * interp_ex, struct file * interpreter) { unsigned long text_data, elf_entry = ~0UL; char * addr; loff_t offset; current->mm->end_code = interp_ex->a_text; text_data = interp_ex->a_text + interp_ex->a_data; current->mm->end_data = text_data; current->mm->brk = interp_ex->a_bss + text_data; switch (N_MAGIC(*interp_ex)) { case OMAGIC: offset = 32; addr = (char *) 0; break; case ZMAGIC: case QMAGIC: offset = N_TXTOFF(*interp_ex); addr = (char *) N_TXTADDR(*interp_ex); break; default: goto out; } down_write(¤t->mm->mmap_sem); do_brk(0, text_data); up_write(¤t->mm->mmap_sem); if (!interpreter->f_op || !interpreter->f_op->read) goto out; if (interpreter->f_op->read(interpreter, addr, text_data, &offset) < 0) goto out; flush_icache_range((unsigned long)addr, (unsigned long)addr + text_data); down_write(¤t->mm->mmap_sem); do_brk(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1), interp_ex->a_bss); up_write(¤t->mm->mmap_sem); elf_entry = interp_ex->a_entry; out: return elf_entry; }
static unsigned long load_aout_interp(struct exec * interp_ex, struct dentry * interpreter_dentry) { unsigned long text_data, offset, elf_entry = ~0UL; char * addr; int retval; current->mm->end_code = interp_ex->a_text; text_data = interp_ex->a_text + interp_ex->a_data; current->mm->end_data = text_data; current->mm->brk = interp_ex->a_bss + text_data; switch (N_MAGIC(*interp_ex)) { case OMAGIC: offset = 32; addr = (char *) 0; break; case ZMAGIC: case QMAGIC: offset = N_TXTOFF(*interp_ex); addr = (char *) N_TXTADDR(*interp_ex); break; default: goto out; } do_mmap(NULL, 0, text_data, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); retval = read_exec(interpreter_dentry, offset, addr, text_data, 0); if (retval < 0) goto out; flush_icache_range((unsigned long)addr, (unsigned long)addr + text_data); do_mmap(NULL, ELF_PAGESTART(text_data + ELF_EXEC_PAGESIZE - 1), interp_ex->a_bss, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); elf_entry = interp_ex->a_entry; out: return elf_entry; }
static int load_elf_binary(struct linux_binprm *bprm) { struct pt_regs regs; int interpreter_fd = -1; unsigned long load_addr = 0, load_bias; int load_addr_set = 0; char * elf_interpreter = NULL; unsigned int interpreter_type = INTERPRETER_NONE; unsigned long error; struct elf_phdr * elf_ppnt, *elf_phdata; unsigned long elf_bss, k, elf_brk; int elf_exec_fileno; int retval, size, i; unsigned long elf_entry, interp_load_addr = 0; unsigned long start_code, end_code, end_data; struct elfhdr elf_ex; struct elfhdr interp_elf_ex; struct exec interp_ex; char passed_fileno[6]; /* Get the exec-header */ elf_ex = *((struct elfhdr *) bprm->buf); my_print("[debug]here to run elf\n"); retval = -ENOEXEC; /* First of all, some simple consistency checks */ if (elf_ex.e_ident[0] != 0x7f || strncmp(&elf_ex.e_ident[1], "ELF", 3) != 0) goto out; //my_print("[ender]1\n"); if (elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) goto out; if (!elf_check_arch(elf_ex.e_machine)) goto out; //my_print("[ender]2\n"); /* Now read in all of the header information */ if (elf_ex.e_phentsize != sizeof(struct elf_phdr) || elf_ex.e_phnum < 1 || elf_ex.e_phnum > 65536 / sizeof(struct elf_phdr)) goto out; // my_print("[ender]3\n"); retval = -ENOMEM; size = elf_ex.e_phentsize * elf_ex.e_phnum; elf_phdata = (struct elf_phdr *) malloc(size); if (!elf_phdata) goto out; retval = read_exec(bprm->fd, elf_ex.e_phoff, (char *) elf_phdata, size, 1); if (retval < 0) goto out_free_ph; //my_print("[ender]4\n"); elf_exec_fileno = dup(bprm->fd); lseek(elf_exec_fileno, 0, SEEK_SET); elf_ppnt = elf_phdata; elf_bss = 0; elf_brk = 0; start_code = ~0UL; end_code = 0; end_data = 0; /* look for interpreter */ for (i = 0; i < elf_ex.e_phnum; i++) { if (elf_ppnt->p_type == PT_INTERP) { retval = -ENOEXEC; if (elf_interpreter || elf_ppnt->p_filesz < 2 || elf_ppnt->p_filesz > PAGE_SIZE) goto out_free_dentry; /* This is the program interpreter used for * shared libraries - for now assume that this * is an a.out format binary */ retval = -ENOMEM; elf_interpreter = (char *)malloc(elf_ppnt->p_filesz); if (!elf_interpreter) goto out_free_file; retval = read_exec(bprm->fd, elf_ppnt->p_offset, elf_interpreter, elf_ppnt->p_filesz, 1); if (retval < 0) goto out_free_interp; elf_interpreter[elf_ppnt->p_filesz - 1] = 0; #if 0 /* If the program interpreter is one of these two, * then assume an iBCS2 image. Otherwise assume * a native linux image. */ if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) ibcs2_interpreter = 1; #endif log_debug(LOG_LINEXEC_EXEC, "Using ELF interpreter: %s", elf_interpreter); if( elf_interpreter[0] == '/'){ char tmp [MAX_PATH]; change_path_to_relative(tmp, elf_interpreter); free(elf_interpreter); //elf_interpreter = (char *)malloc(elf_ppnt->p_filesz); elf_interpreter = (char *)malloc(strlen(tmp)+1); if (!elf_interpreter) goto out_free_file; strcpy(elf_interpreter, tmp); } interpreter_fd = open(elf_interpreter, O_RDONLY); my_print("[debug]open elf_interpreter %s\n", elf_interpreter); if (interpreter_fd < 0) { retval = -errno; goto out_free_interp; } #if 0 retval = permission(interpreter_dentry->d_inode, MAY_EXEC); if (retval < 0) goto out_free_dentry; #endif retval = read_exec(interpreter_fd, 0, bprm->buf, 128, 1); if (retval < 0) goto out_free_dentry; /* Get the exec headers */ interp_ex = *((struct exec *) bprm->buf); interp_elf_ex = *((struct elfhdr *) bprm->buf); } elf_ppnt++; //my_print("[ender]6\n"); } /* Some simple consistency checks for the interpreter */ if (elf_interpreter) { interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; /* Now figure out which format our binary is */ if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && (N_MAGIC(interp_ex) != QMAGIC)) interpreter_type = INTERPRETER_ELF; if (interp_elf_ex.e_ident[0] != 0x7f || strncmp(&interp_elf_ex.e_ident[1], "ELF", 3) != 0) interpreter_type &= ~INTERPRETER_ELF; retval = -ELIBBAD; if (!interpreter_type) goto out_free_dentry; /* Make sure only one type was selected */ if ((interpreter_type & INTERPRETER_ELF) && interpreter_type != INTERPRETER_ELF) { printf("ELF: Ambiguous type, using ELF\n"); interpreter_type = INTERPRETER_ELF; } } //my_print("[ender]7\n"); /* OK, we are done with that, now set up the arg stuff, and then start this sucker up */ if (!bprm->sh_bang) { char * passed_p; if (interpreter_type == INTERPRETER_AOUT) { sprintf(passed_fileno, "%d", elf_exec_fileno); passed_p = passed_fileno; if (elf_interpreter) { bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p); bprm->argc++; } } retval = -E2BIG; if (!bprm->p) goto out_free_dentry; } #if 0 /* Flush all traces of the currently running executable */ retval = flush_old_exec(bprm); if (retval) goto out_free_dentry; #endif /* OK, This is the point of no return */ current->end_data = 0; current->end_code = 0; #if 0 current->mm->mmap = NULL; current->flags &= ~PF_FORKNOEXEC; #endif elf_entry = (unsigned long) elf_ex.e_entry; //printf("[ender]8\n"); #if 0 /* Do this immediately, since STACK_TOP as used in setup_arg_pages may depend on the personality. */ SET_PERSONALITY(elf_ex, ibcs2_interpreter); #endif /* Do this so that we can load the interpreter, if need be. We will change some of these later */ // current->mm->rss = 0; bprm->p = setup_arg_pages(bprm->p, bprm); current->start_stack = bprm->p; /* Try and get dynamic programs out of the way of the default mmap base, as well as whatever program they might try to exec. This is because the brk will follow the loader, and is not movable. */ load_bias = ELF_PAGESTART(elf_ex.e_type==ET_DYN ? ELF_ET_DYN_BASE : 0); #ifdef __VERBOSE__ printf("load_bias: %08lX\n", load_bias); #endif /* Now we do a little grungy work by mmaping the ELF image into the correct location in memory. At this point, we assume that the image should be loaded at fixed address, not at a variable address. */ for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { int elf_prot = 0, elf_flags; unsigned long vaddr; if (elf_ppnt->p_type != PT_LOAD) continue; if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; elf_flags = MAP_PRIVATE; // |MAP_DENYWRITE|MAP_EXECUTABLE; vaddr = elf_ppnt->p_vaddr; if (elf_ex.e_type == ET_EXEC || load_addr_set) { elf_flags |= MAP_FIXED; } //my_print("[ender]9\n"); #ifdef __VERBOSE__ printf("mapping: %08lX\n", ELF_PAGESTART(load_bias + vaddr)); #endif error = do_mmap(bprm->fd, ELF_PAGESTART(load_bias + vaddr), (elf_ppnt->p_filesz + ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), elf_prot, elf_flags, (elf_ppnt->p_offset - ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); #ifdef __VERBOSE__ printf("error: %08lX\n", error); #endif if (!load_addr_set) { load_addr_set = 1; load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset); #ifdef __VERBOSE__ printf("load_addr: %08lX, vaddr: %08lX\n", load_addr, vaddr); #endif if (elf_ex.e_type == ET_DYN) { load_bias += error - ELF_PAGESTART(load_bias + vaddr); load_addr += error; #ifdef __VERBOSE__ printf("new\nload_bias: %08lX, load_addr: %08lX\n", load_bias, load_addr); #endif } } k = elf_ppnt->p_vaddr; if (k < start_code) start_code = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; if (k > elf_bss) elf_bss = k; if ((elf_ppnt->p_flags & PF_X) && end_code < k) end_code = k; if (end_data < k) end_data = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; if (k > elf_brk) elf_brk = k; } close(bprm->fd); elf_entry += load_bias; elf_bss += load_bias; elf_brk += load_bias; start_code += load_bias; end_code += load_bias; end_data += load_bias; if (elf_interpreter) { if (interpreter_type == INTERPRETER_AOUT) { elf_entry = load_aout_interp(&interp_ex, interpreter_fd); } else { elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, &interp_load_addr); } close(interpreter_fd); if (elf_entry == ~0UL) { printf("Unable to load interpreter %.128s\n", elf_interpreter); free(elf_interpreter); free(elf_phdata); //send_sig(SIGSEGV, current, 0); exit(1); return 0; } free(elf_interpreter); } free(elf_phdata); if (interpreter_type != INTERPRETER_AOUT) close(elf_exec_fileno); #if 0 #ifndef VM_STACK_FLAGS current->executable = dget(bprm->dentry); #endif #endif bprm->p = (unsigned long)create_elf_tables((char *)bprm->p, bprm->argc, bprm->envc, (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), load_addr, load_bias, interp_load_addr, (interpreter_type == INTERPRETER_AOUT ? 0 : 1)); #if 0 /* N.B. passed_fileno might not be initialized? */ if (interpreter_type == INTERPRETER_AOUT) current->arg_start += strlen(passed_fileno) + 1; #endif current->start_brk = current->brk = elf_brk; current->end_code = end_code; current->start_code = start_code; current->end_data = end_data; current->start_stack = bprm->p; /* Calling set_brk effectively mmaps the pages that we need * for the bss and break sections */ set_brk(elf_bss, elf_brk); padzero(elf_bss); log_debug(LOG_LINEXEC_EXEC,"start_brk: %lx" , current->start_brk); log_debug(LOG_LINEXEC_EXEC,"end_code: %lx" , current->end_code); log_debug(LOG_LINEXEC_EXEC,"start_code: %lx" , current->start_code); log_debug(LOG_LINEXEC_EXEC,"end_data: %lx" , current->end_data); log_debug(LOG_LINEXEC_EXEC,"start_stack: %lx" , current->start_stack); log_debug(LOG_LINEXEC_EXEC,"brk: %lx" , current->brk); /* * The ABI may specify that certain registers be set up in special * ways (on i386 %edx is the address of a DT_FINI function, for * example. This macro performs whatever initialization to * the regs structure is required. */ ELF_PLAT_INIT((®s)); regs.eip = elf_entry; regs.esp = bprm->p; #if 0 if (current->flags & PF_PTRACED) send_sig(SIGTRAP, current, 0); #endif #ifndef __DEBUG__ // dumpMemoryMap(); log_verbose(LOG_LINEXEC_EXEC, "[transfering control to Linux executable]"); //getchar(); //printf("[ender]11\n"); ASM_EXEC_JUMP(regs); printf("You should never see this message!\n"); #else printf("execve() finished, but in debug mode. exiting...\n"); #endif retval = 0; out: return retval; /* error cleanup */ out_free_dentry: close(interpreter_fd); out_free_interp: if (elf_interpreter) { free(elf_interpreter); } out_free_file: close(elf_exec_fileno); out_free_ph: free(elf_phdata); goto out; }
static int load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs) { struct exec ex; unsigned long error; unsigned long fd_offset; unsigned long rlim; unsigned long orig_thr_flags; int retval; ex = *((struct exec *) bprm->buf); /* exec-header */ if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) || N_TRSIZE(ex) || N_DRSIZE(ex) || bprm->file->f_path.dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { return -ENOEXEC; } fd_offset = N_TXTOFF(ex); /* Check initial limits. This avoids letting people circumvent * size limits imposed on them by creating programs with large * arrays in the data or bss. */ rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur; if (rlim >= RLIM_INFINITY) rlim = ~0; if (ex.a_data + ex.a_bss > rlim) return -ENOMEM; /* Flush all traces of the currently running executable */ retval = flush_old_exec(bprm); if (retval) return retval; /* OK, This is the point of no return */ set_personality(PER_SUNOS); current->mm->end_code = ex.a_text + (current->mm->start_code = N_TXTADDR(ex)); current->mm->end_data = ex.a_data + (current->mm->start_data = N_DATADDR(ex)); current->mm->brk = ex.a_bss + (current->mm->start_brk = N_BSSADDR(ex)); current->mm->free_area_cache = current->mm->mmap_base; current->mm->cached_hole_size = 0; current->mm->mmap = NULL; compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; if (N_MAGIC(ex) == NMAGIC) { loff_t pos = fd_offset; /* F**k me plenty... */ down_write(¤t->mm->mmap_sem); error = do_brk(N_TXTADDR(ex), ex.a_text); up_write(¤t->mm->mmap_sem); bprm->file->f_op->read(bprm->file, (char __user *)N_TXTADDR(ex), ex.a_text, &pos); down_write(¤t->mm->mmap_sem); error = do_brk(N_DATADDR(ex), ex.a_data); up_write(¤t->mm->mmap_sem); bprm->file->f_op->read(bprm->file, (char __user *)N_DATADDR(ex), ex.a_data, &pos); goto beyond_if; } if (N_MAGIC(ex) == OMAGIC) { loff_t pos = fd_offset; down_write(¤t->mm->mmap_sem); do_brk(N_TXTADDR(ex) & PAGE_MASK, ex.a_text+ex.a_data + PAGE_SIZE - 1); up_write(¤t->mm->mmap_sem); bprm->file->f_op->read(bprm->file, (char __user *)N_TXTADDR(ex), ex.a_text+ex.a_data, &pos); } else { static unsigned long error_time; if ((ex.a_text & 0xfff || ex.a_data & 0xfff) && (N_MAGIC(ex) != NMAGIC) && (jiffies-error_time) > 5*HZ) { printk(KERN_NOTICE "executable not page aligned\n"); error_time = jiffies; } if (!bprm->file->f_op->mmap) { loff_t pos = fd_offset; down_write(¤t->mm->mmap_sem); do_brk(0, ex.a_text+ex.a_data); up_write(¤t->mm->mmap_sem); bprm->file->f_op->read(bprm->file, (char __user *)N_TXTADDR(ex), ex.a_text+ex.a_data, &pos); goto beyond_if; } down_write(¤t->mm->mmap_sem); error = do_mmap(bprm->file, N_TXTADDR(ex), ex.a_text, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset); up_write(¤t->mm->mmap_sem); if (error != N_TXTADDR(ex)) { send_sig(SIGKILL, current, 0); return error; } down_write(¤t->mm->mmap_sem); error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset + ex.a_text); up_write(¤t->mm->mmap_sem); if (error != N_DATADDR(ex)) { send_sig(SIGKILL, current, 0); return error; } } beyond_if: set_binfmt(&aout32_format); set_brk(current->mm->start_brk, current->mm->brk); /* Make sure STACK_TOP returns the right thing. */ orig_thr_flags = current_thread_info()->flags; current_thread_info()->flags |= _TIF_32BIT; retval = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT); if (retval < 0) { current_thread_info()->flags = orig_thr_flags; /* Someone check-me: is this error path enough? */ send_sig(SIGKILL, current, 0); return retval; } current->mm->start_stack = (unsigned long) create_aout32_tables((char __user *)bprm->p, bprm); tsb_context_switch(current->mm); start_thread32(regs, ex.a_entry, current->mm->start_stack); if (current->ptrace & PT_PTRACED) send_sig(SIGTRAP, current, 0); return 0; }
static int load_aout_library(struct file *file) { struct inode * inode; unsigned long bss, start_addr, len; unsigned long error; int retval; struct exec ex; inode = file->f_dentry->d_inode; retval = -ENOEXEC; error = kernel_read(file, 0, (char *) &ex, sizeof(ex)); if (error != sizeof(ex)) goto out; /* We come in here for the regular a.out style of shared libraries */ if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) || N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) || inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { goto out; } if (N_FLAGS(ex)) goto out; /* For QMAGIC, the starting address is 0x20 into the page. We mask this off to get the starting address for the page */ #ifndef __arm__ start_addr = ex.a_entry & 0xfffff000; #else start_addr = ex.a_entry & 0xffff8000; #endif if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) { static unsigned long error_time; loff_t pos = N_TXTOFF(ex); if ((jiffies-error_time) > 5*HZ) { printk(KERN_WARNING "N_TXTOFF is not page aligned. Please convert library: %s\n", file->f_dentry->d_name.name); error_time = jiffies; } do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss); file->f_op->read(file, (char *)start_addr, ex.a_text + ex.a_data, &pos); flush_icache_range((unsigned long) start_addr, (unsigned long) start_addr + ex.a_text + ex.a_data); retval = 0; goto out; } /* Now use mmap to map the library into memory. */ down_write(¤t->mm->mmap_sem); error = do_mmap(file, start_addr, ex.a_text + ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, N_TXTOFF(ex)); up_write(¤t->mm->mmap_sem); retval = error; if (error != start_addr) goto out; len = PAGE_ALIGN(ex.a_text + ex.a_data); bss = ex.a_text + ex.a_data + ex.a_bss; if (bss > len) { error = do_brk(start_addr + len, bss - len); retval = error; if (error != start_addr + len) goto out; } retval = 0; out: return retval; }
// Запуск файла, заданного именем // (см. комментарии в binfmt.c) void aout_load(char *Name) { char name83[11]; DirEntry Entry; Make83Name(Name, name83); if (FindEntry(0, name83, &Entry) == (uint)-1) { printf("Cannot open file '%s'!\n", Name); return; } // Грузим заголовок Exec exec; LoadPart(&Entry, &exec, 0, sizeof(Exec)); // Проверяем пригодность файла if (N_MID(exec) != M_386) { printf("Only 386's binaries are supported\n"); return; } if (N_MAGIC(exec) != ZMAGIC) { printf("Not-ZMAGIC binaries are not supported yet\n"); return; } // Количество страниц в каждой секции ushort TextPages = (exec.a_text + 0xfff) / PAGE_SIZE; ushort DataPages = (exec.a_data + 0xfff) / PAGE_SIZE; ushort BSSPages = (exec.a_bss + 0xfff) / PAGE_SIZE; // Создаем каталог страниц ulong *pg_dir = (ulong*)alloc_first_page(); // И записываем в него системные таблицы memset(pg_dir, 0, PAGE_SIZE); pg_dir[0x200] = 0x3000 + SYS_PAGE_ATTR; pg_dir[0x201] = 0x4000 + SYS_PAGE_ATTR; // Создаем для процесса TaskStruct TaskStruct *task = (TaskStruct*)alloc_first_page(); // Достаем адрес GDT GDTDescriptor GDT; __asm__("sgdt %0":: "m" (GDT)); ushort desc_count = (GDT.Size + 1) >> 3; // Сюда допишем TSS ushort tssn = desc_count; // Заполняем атрибуты task->pid = CurPID++; task->tsss = tssn << 3; task->BinFormat = BIN_AOUT; // Копируем DirEntry и заголовок A.OUT memcpy(&task->file, &Entry, sizeof(DirEntry)); memcpy(&task->header, &exec, sizeof(Exec)); // Заполняем TSS task->tss.tl = 0; task->tss.esp0 = (ulong)&task->syscall_stack + sizeof(task->syscall_stack); // Стек для системных вызовов task->tss.ss0 = KERNEL_DS; task->tss.cr3 = (ulong)pg_dir; task->tss.eip = exec.a_entry; task->tss.eflags = 0x200; // Только IF task->tss.eax = task->tss.ebx = task->tss.ecx = task->tss.edx = task->tss.esi = task->tss.edi = 0; // Стек следует сразу за остальными секциями task->tss.esp = task->tss.ebp = (TextPages+DataPages+BSSPages + USER_STACK_PAGES) * PAGE_SIZE - 4; // 4 байта на адрес возврата task->tss.cs = USER_CS; task->tss.es = task->tss.ss = task->tss.ds = task->tss.fs = task->tss.gs = USER_DS; task->tss.ldt = 0; task->tss.iomap_trace = 0; // Чтобы процесс имел возможность нормально завершится, мы должны предоставить ему адрес // возврата в стеке. Процесс передаст управление по этому адресу при выходе из main(). // Для этого мы маппируем страницу с функцией user_exit_code (head.S) в АП процесса. // Адрес, по которому мы ее будет маппировать, расположим сразу после стека (FIXME: создаем // сами себе грабли для динамической линковки...) addr_t exit_page = (TextPages+DataPages+BSSPages+USER_STACK_PAGES) * PAGE_SIZE; // FIXME: Я НЕ ТЕСТИРОВАЛ ЗАВЕРШЕНИЕ ПРОЦЕССОВ A.OUT addr_t stack_page = alloc_first_page(); map_page(stack_page, task, PAGE_ADDR(task->tss.esp), PAGE_ATTR); *(ulong*)(stack_page+0xffc) = exit_page; map_page((addr_t)&user_exit_code, task, exit_page, PA_USER | PA_P | PA_NONFREE); // Создаем в GDT дескриптор для TSS // FIXME: Их нужно удалять при завершении процесса! // TSS адресуется через верхнюю память ulong tss_addr = (ulong)&task->tss + 0x80000000; GDT.Addr = (Descriptor*)((ulong)GDT.Addr - 0x80000000); GDT.Addr[tssn].a = (tss_addr<<16)|0x0067; GDT.Addr[tssn].b = (tss_addr&0xff000000)|0x00408b00|((tss_addr>>16)&0xff); GDT.Addr = (Descriptor*)((ulong)GDT.Addr + 0x80000000); GDT.Size += 8; // Один дескриптор добавили __asm__("lgdt %0"::"m"(GDT)); // Ура Task[NTasks] = task; NTasks++; }
static int CVE_2010_0307_linux2_6_23_load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) { struct file *interpreter = NULL; /* to shut gcc up */ unsigned long load_addr = 0, load_bias = 0; int load_addr_set = 0; char * elf_interpreter = NULL; unsigned int interpreter_type = INTERPRETER_NONE; unsigned char ibcs2_interpreter = 0; unsigned long error; struct elf_phdr *elf_ppnt, *elf_phdata; unsigned long elf_bss, elf_brk; int elf_exec_fileno; int retval, i; unsigned int size; unsigned long elf_entry, interp_load_addr = 0; unsigned long start_code, end_code, start_data, end_data; unsigned long reloc_func_desc = 0; char passed_fileno[6]; struct files_struct *files; int executable_stack = EXSTACK_DEFAULT; unsigned long def_flags = 0; struct { struct elfhdr elf_ex; struct elfhdr interp_elf_ex; struct exec interp_ex; } *loc; loc = kmalloc(sizeof(*loc), GFP_KERNEL); if (!loc) { retval = -ENOMEM; goto out_ret; } /* Get the exec-header */ loc->elf_ex = *((struct elfhdr *)bprm->buf); retval = -ENOEXEC; /* First of all, some simple consistency checks */ if (memcmp(loc->elf_ex.e_ident, ELFMAG, SELFMAG) != 0) goto out; if (loc->elf_ex.e_type != ET_EXEC && loc->elf_ex.e_type != ET_DYN) goto out; if (!elf_check_arch(&loc->elf_ex)) goto out; if (!bprm->file->f_op||!bprm->file->f_op->mmap) goto out; /* Now read in all of the header information */ if (loc->elf_ex.e_phentsize != sizeof(struct elf_phdr)) goto out; if (loc->elf_ex.e_phnum < 1 || loc->elf_ex.e_phnum > 65536U / sizeof(struct elf_phdr)) goto out; size = loc->elf_ex.e_phnum * sizeof(struct elf_phdr); retval = -ENOMEM; elf_phdata = kmalloc(size, GFP_KERNEL); if (!elf_phdata) goto out; retval = kernel_read(bprm->file, loc->elf_ex.e_phoff, (char *)elf_phdata, size); if (retval != size) { if (retval >= 0) retval = -EIO; goto out_free_ph; } files = current->files; /* Refcounted so ok */ retval = unshare_files(); if (retval < 0) goto out_free_ph; if (files == current->files) { put_files_struct(files); files = NULL; } /* exec will make our files private anyway, but for the a.out loader stuff we need to do it earlier */ retval = get_unused_fd(); if (retval < 0) goto out_free_fh; get_file(bprm->file); fd_install(elf_exec_fileno = retval, bprm->file); elf_ppnt = elf_phdata; elf_bss = 0; elf_brk = 0; start_code = ~0UL; end_code = 0; start_data = 0; end_data = 0; for (i = 0; i < loc->elf_ex.e_phnum; i++) { if (elf_ppnt->p_type == PT_INTERP) { /* This is the program interpreter used for * shared libraries - for now assume that this * is an a.out format binary */ retval = -ENOEXEC; if (elf_ppnt->p_filesz > PATH_MAX || elf_ppnt->p_filesz < 2) goto out_free_file; retval = -ENOMEM; elf_interpreter = kmalloc(elf_ppnt->p_filesz, GFP_KERNEL); if (!elf_interpreter) goto out_free_file; retval = kernel_read(bprm->file, elf_ppnt->p_offset, elf_interpreter, elf_ppnt->p_filesz); if (retval != elf_ppnt->p_filesz) { if (retval >= 0) retval = -EIO; goto out_free_interp; } /* make sure path is NULL terminated */ retval = -ENOEXEC; if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') goto out_free_interp; /* If the program interpreter is one of these two, * then assume an iBCS2 image. Otherwise assume * a native linux image. */ if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) ibcs2_interpreter = 1; /* * The early SET_PERSONALITY here is so that the lookup * for the interpreter happens in the namespace of the * to-be-execed image. SET_PERSONALITY can select an * alternate root. * * However, SET_PERSONALITY is NOT allowed to switch * this task into the new images's memory mapping * policy - that is, TASK_SIZE must still evaluate to * that which is appropriate to the execing application. * This is because exit_mmap() needs to have TASK_SIZE * evaluate to the size of the old image. * * So if (say) a 64-bit application is execing a 32-bit * application it is the architecture's responsibility * to defer changing the value of TASK_SIZE until the * switch really is going to happen - do this in * flush_thread(). - akpm */ SET_PERSONALITY(loc->elf_ex, ibcs2_interpreter); interpreter = open_exec(elf_interpreter); retval = PTR_ERR(interpreter); if (IS_ERR(interpreter)) goto out_free_interp; /* * If the binary is not readable then enforce * mm->dumpable = 0 regardless of the interpreter's * permissions. */ if (file_permission(interpreter, MAY_READ) < 0) bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; retval = kernel_read(interpreter, 0, bprm->buf, BINPRM_BUF_SIZE); if (retval != BINPRM_BUF_SIZE) { if (retval >= 0) retval = -EIO; goto out_free_dentry; } /* Get the exec headers */ loc->interp_ex = *((struct exec *)bprm->buf); loc->interp_elf_ex = *((struct elfhdr *)bprm->buf); break; } elf_ppnt++; } elf_ppnt = elf_phdata; for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++) if (elf_ppnt->p_type == PT_GNU_STACK) { if (elf_ppnt->p_flags & PF_X) executable_stack = EXSTACK_ENABLE_X; else executable_stack = EXSTACK_DISABLE_X; break; } /* Some simple consistency checks for the interpreter */ if (elf_interpreter) { interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; /* Now figure out which format our binary is */ if ((N_MAGIC(loc->interp_ex) != OMAGIC) && (N_MAGIC(loc->interp_ex) != ZMAGIC) && (N_MAGIC(loc->interp_ex) != QMAGIC)) interpreter_type = INTERPRETER_ELF; if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0) interpreter_type &= ~INTERPRETER_ELF; retval = -ELIBBAD; if (!interpreter_type) goto out_free_dentry; /* Make sure only one type was selected */ if ((interpreter_type & INTERPRETER_ELF) && interpreter_type != INTERPRETER_ELF) { // FIXME - ratelimit this before re-enabling // printk(KERN_WARNING "ELF: Ambiguous type, using ELF\n"); interpreter_type = INTERPRETER_ELF; } /* Verify the interpreter has a valid arch */ if ((interpreter_type == INTERPRETER_ELF) && !elf_check_arch(&loc->interp_elf_ex)) goto out_free_dentry; } else { /* Executables without an interpreter also need a personality */ SET_PERSONALITY(loc->elf_ex, ibcs2_interpreter); } /* OK, we are done with that, now set up the arg stuff, and then start this sucker up */ if ((!bprm->sh_bang) && (interpreter_type == INTERPRETER_AOUT)) { char *passed_p = passed_fileno; sprintf(passed_fileno, "%d", elf_exec_fileno); if (elf_interpreter) { retval = copy_strings_kernel(1, &passed_p, bprm); if (retval) goto out_free_dentry; bprm->argc++; } } /* Flush all traces of the currently running executable */ retval = flush_old_exec(bprm); if (retval) goto out_free_dentry; /* Discard our unneeded old files struct */ if (files) { put_files_struct(files); files = NULL; } /* OK, This is the point of no return */ current->flags &= ~PF_FORKNOEXEC; current->mm->def_flags = def_flags; /* Do this immediately, since STACK_TOP as used in setup_arg_pages may depend on the personality. */ SET_PERSONALITY(loc->elf_ex, ibcs2_interpreter); if (elf_read_implies_exec(loc->elf_ex, executable_stack)) current->personality |= READ_IMPLIES_EXEC; if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) current->flags |= PF_RANDOMIZE; arch_pick_mmap_layout(current->mm); /* Do this so that we can load the interpreter, if need be. We will change some of these later */ current->mm->free_area_cache = current->mm->mmap_base; current->mm->cached_hole_size = 0; retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP), executable_stack); if (retval < 0) { send_sig(SIGKILL, current, 0); goto out_free_dentry; } current->mm->start_stack = bprm->p; /* Now we do a little grungy work by mmaping the ELF image into the correct location in memory. At this point, we assume that the image should be loaded at fixed address, not at a variable address. */ for(i = 0, elf_ppnt = elf_phdata; i < loc->elf_ex.e_phnum; i++, elf_ppnt++) { int elf_prot = 0, elf_flags; unsigned long k, vaddr; if (elf_ppnt->p_type != PT_LOAD) continue; if (unlikely (elf_brk > elf_bss)) { unsigned long nbyte; /* There was a PT_LOAD segment with p_memsz > p_filesz before this one. Map anonymous pages, if needed, and clear the area. */ retval = set_brk (elf_bss + load_bias, elf_brk + load_bias); if (retval) { send_sig(SIGKILL, current, 0); goto out_free_dentry; } nbyte = ELF_PAGEOFFSET(elf_bss); if (nbyte) { nbyte = ELF_MIN_ALIGN - nbyte; if (nbyte > elf_brk - elf_bss) nbyte = elf_brk - elf_bss; if (clear_user((void __user *)elf_bss + load_bias, nbyte)) { /* * This bss-zeroing can fail if the ELF * file specifies odd protections. So * we don't check the return value */ } } } if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE; vaddr = elf_ppnt->p_vaddr; if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) { elf_flags |= MAP_FIXED; } else if (loc->elf_ex.e_type == ET_DYN) { /* Try and get dynamic programs out of the way of the * default mmap base, as well as whatever program they * might try to exec. This is because the brk will * follow the loader, and is not movable. */ load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); } error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags); if (BAD_ADDR(error)) { send_sig(SIGKILL, current, 0); retval = IS_ERR((void *)error) ? PTR_ERR((void*)error) : -EINVAL; goto out_free_dentry; } if (!load_addr_set) { load_addr_set = 1; load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset); if (loc->elf_ex.e_type == ET_DYN) { load_bias += error - ELF_PAGESTART(load_bias + vaddr); load_addr += load_bias; reloc_func_desc = load_bias; } } k = elf_ppnt->p_vaddr; if (k < start_code) start_code = k; if (start_data < k) start_data = k; /* * Check to see if the section's size will overflow the * allowed task size. Note that p_filesz must always be * <= p_memsz so it is only necessary to check p_memsz. */ if (BAD_ADDR(k) || elf_ppnt->p_filesz > elf_ppnt->p_memsz || elf_ppnt->p_memsz > TASK_SIZE || TASK_SIZE - elf_ppnt->p_memsz < k) { /* set_brk can never work. Avoid overflows. */ send_sig(SIGKILL, current, 0); retval = -EINVAL; goto out_free_dentry; } k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; if (k > elf_bss) elf_bss = k; if ((elf_ppnt->p_flags & PF_X) && end_code < k) end_code = k; if (end_data < k) end_data = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; if (k > elf_brk) elf_brk = k; } loc->elf_ex.e_entry += load_bias; elf_bss += load_bias; elf_brk += load_bias; start_code += load_bias; end_code += load_bias; start_data += load_bias; end_data += load_bias; /* Calling set_brk effectively mmaps the pages that we need * for the bss and break sections. We must do this before * mapping in the interpreter, to make sure it doesn't wind * up getting placed where the bss needs to go. */ retval = set_brk(elf_bss, elf_brk); if (retval) { send_sig(SIGKILL, current, 0); goto out_free_dentry; } if (likely(elf_bss != elf_brk) && unlikely(padzero(elf_bss))) { send_sig(SIGSEGV, current, 0); retval = -EFAULT; /* Nobody gets to see this, but.. */ goto out_free_dentry; } if (elf_interpreter) { if (interpreter_type == INTERPRETER_AOUT) elf_entry = load_aout_interp(&loc->interp_ex, interpreter); else elf_entry = load_elf_interp(&loc->interp_elf_ex, interpreter, &interp_load_addr); if (BAD_ADDR(elf_entry)) { force_sig(SIGSEGV, current); retval = IS_ERR((void *)elf_entry) ? (int)elf_entry : -EINVAL; goto out_free_dentry; } reloc_func_desc = interp_load_addr; allow_write_access(interpreter); fput(interpreter); kfree(elf_interpreter); } else { elf_entry = loc->elf_ex.e_entry; if (BAD_ADDR(elf_entry)) { force_sig(SIGSEGV, current); retval = -EINVAL; goto out_free_dentry; } } kfree(elf_phdata); if (interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno); set_binfmt(&elf_format); #ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES retval = arch_setup_additional_pages(bprm, executable_stack); if (retval < 0) { send_sig(SIGKILL, current, 0); goto out; } #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; retval = create_elf_tables(bprm, &loc->elf_ex, (interpreter_type == INTERPRETER_AOUT), load_addr, interp_load_addr); if (retval < 0) { send_sig(SIGKILL, current, 0); goto out; } /* N.B. passed_fileno might not be initialized? */ if (interpreter_type == INTERPRETER_AOUT) current->mm->arg_start += strlen(passed_fileno) + 1; current->mm->end_code = end_code; current->mm->start_code = start_code; current->mm->start_data = start_data; current->mm->end_data = end_data; current->mm->start_stack = bprm->p; if (current->personality & MMAP_PAGE_ZERO) { /* Why this, you ask??? Well SVr4 maps page 0 as read-only, and some applications "depend" upon this behavior. Since we do not have the power to recompile these, we emulate the SVr4 behavior. Sigh. */ down_write(¤t->mm->mmap_sem); error = do_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); up_write(¤t->mm->mmap_sem); } #ifdef ELF_PLAT_INIT /* * The ABI may specify that certain registers be set up in special * ways (on i386 %edx is the address of a DT_FINI function, for * example. In addition, it may also specify (eg, PowerPC64 ELF) * that the e_entry field is the address of the function descriptor * for the startup routine, rather than the address of the startup * routine itself. This macro performs whatever initialization to * the regs structure is required as well as any relocations to the * function descriptor entries when executing dynamically links apps. */ ELF_PLAT_INIT(regs, reloc_func_desc); #endif start_thread(regs, elf_entry, bprm->p); if (unlikely(current->ptrace & PT_PTRACED)) { if (current->ptrace & PT_TRACE_EXEC) ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP); else send_sig(SIGTRAP, current, 0); } retval = 0; out: kfree(loc); out_ret: return retval; /* error cleanup */ out_free_dentry: allow_write_access(interpreter); if (interpreter) fput(interpreter); out_free_interp: kfree(elf_interpreter); out_free_file: sys_close(elf_exec_fileno); out_free_fh: if (files) reset_files_struct(current, files); out_free_ph: kfree(elf_phdata); goto out; }
static inline int do_load_aout_library(int fd) { struct file * file; struct exec ex; struct inode * inode; unsigned int len; unsigned int bss; unsigned int start_addr; unsigned long error; file = current->files->fd[fd]; inode = file->f_inode; if (!file || !file->f_op) return -EACCES; /* Seek into the file */ if (file->f_op->lseek) { if ((error = file->f_op->lseek(inode, file, 0, 0)) != 0) return -ENOEXEC; } else file->f_pos = 0; set_fs(KERNEL_DS); error = file->f_op->read(inode, file, (char *) &ex, sizeof(ex)); set_fs(USER_DS); if (error != sizeof(ex)) return -ENOEXEC; /* We come in here for the regular a.out style of shared libraries */ if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) || N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) || inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { return -ENOEXEC; } if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) && (N_TXTOFF(ex) < inode->i_sb->s_blocksize)) { printk("N_TXTOFF < BLOCK_SIZE. Please convert library\n"); return -ENOEXEC; } if (N_FLAGS(ex)) return -ENOEXEC; /* For QMAGIC, the starting address is 0x20 into the page. We mask this off to get the starting address for the page */ #ifndef CONFIG_ARM start_addr = ex.a_entry & 0xfffff000; /* Now use mmap to map the library into memory. */ error = do_mmap(file, start_addr, ex.a_text + ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, N_TXTOFF(ex)); if (error != start_addr) return error; len = PAGE_ALIGN(ex.a_text + ex.a_data); bss = ex.a_text + ex.a_data + ex.a_bss; #else start_addr = ex.a_entry & 0xffff8000; { unsigned int offset; unsigned int length; switch (N_MAGIC(ex)) { case QMAGIC: offset = 0; length = ex.a_text + ex.a_data; break; case ZMAGIC: /* or QMAGIC */ offset = N_TXTOFF(ex); length = ex.a_text + ex.a_data; break; default: return -ENOEXEC; } /* Now use mmap to map the library into memory. */ error = do_mmap(file, start_addr, length, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, offset); if (error != start_addr) return error; len = PAGE_ALIGN(length); bss = length + ex.a_bss; } #endif if (bss > len) { error = do_mmap(NULL, start_addr + len, bss-len, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 0); if (error != start_addr + len) return error; } return 0; }
static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) { struct exec ex; struct file * file; int fd; unsigned long error; unsigned long p = bprm->p; unsigned long fd_offset; unsigned long rlim; ex = *((struct exec *) bprm->buf); /* exec-header */ if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) || N_DRSIZE(ex) || bprm->inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { return -ENOEXEC; } current->personality = PER_LINUX; fd_offset = N_TXTOFF(ex); #if defined (__i386__) || defined (CONFIG_ARM) if (N_MAGIC(ex) == ZMAGIC && fd_offset != BLOCK_SIZE) { printk(KERN_NOTICE "N_TXTOFF != BLOCK_SIZE. See a.out.h.\n"); return -ENOEXEC; } if (N_MAGIC(ex) == ZMAGIC && ex.a_text && (fd_offset < bprm->inode->i_sb->s_blocksize)) { printk(KERN_NOTICE "N_TXTOFF < BLOCK_SIZE. Please convert binary.\n"); return -ENOEXEC; } #endif #if defined(CONFIG_ARM) if (N_MACHTYPE(ex) != M_ARM) { printk(KERN_NOTICE "Binary != ARM. Please recompile binary.\n"); return -ENOEXEC; } #endif /* Check initial limits. This avoids letting people circumvent * size limits imposed on them by creating programs with large * arrays in the data or bss. */ rlim = current->rlim[RLIMIT_DATA].rlim_cur; if (rlim >= RLIM_INFINITY) rlim = ~0; if (ex.a_data + ex.a_bss > rlim) return -ENOMEM; if (flush_old_exec(bprm)) return -ENOMEM; /* OK, This is the point of no return */ current->mm->end_code = ex.a_text + (current->mm->start_code = N_TXTADDR(ex)); current->mm->end_data = ex.a_data + (current->mm->start_data = N_DATADDR(ex)); current->mm->brk = ex.a_bss + (current->mm->start_brk = N_BSSADDR(ex)); current->mm->rss = 0; current->mm->mmap = NULL; current->suid = current->euid = current->fsuid = bprm->e_uid; current->sgid = current->egid = current->fsgid = bprm->e_gid; current->flags &= ~PF_FORKNOEXEC; if (N_MAGIC(ex) == OMAGIC) { #if defined(__alpha__) || defined(CONFIG_ARM) #ifndef CONFIG_ARM do_mmap(NULL, N_TXTADDR(ex) & PAGE_MASK, ex.a_text+ex.a_data + PAGE_SIZE - 1, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); #else do_mmap(NULL, N_TXTADDR(ex), ex.a_text+ex.a_data, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); #endif read_exec(bprm->inode, fd_offset, (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0); #else do_mmap(NULL, 0, ex.a_text+ex.a_data, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); read_exec(bprm->inode, 32, (char *) 0, ex.a_text+ex.a_data, 0); #endif } else { if (ex.a_text & 0xfff || ex.a_data & 0xfff) printk(KERN_NOTICE "executable not page aligned\n"); fd = open_inode(bprm->inode, O_RDONLY); if (fd < 0) { send_sig(SIGKILL, current, 0); return fd; } file = current->files->fd[fd]; if (!file->f_op || !file->f_op->mmap) { sys_close(fd); do_mmap(NULL, 0, ex.a_text+ex.a_data, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); read_exec(bprm->inode, fd_offset, (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0); goto beyond_if; } error = do_mmap(file, N_TXTADDR(ex), ex.a_text, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset); if (error != N_TXTADDR(ex)) { sys_close(fd); send_sig(SIGKILL, current, 0); return error; } error = do_mmap(file, N_DATADDR(ex), ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset + ex.a_text); sys_close(fd); if (error != N_DATADDR(ex)) { send_sig(SIGKILL, current, 0); return error; } } beyond_if: if (current->exec_domain && current->exec_domain->use_count) (*current->exec_domain->use_count)--; if (current->binfmt && current->binfmt->use_count) (*current->binfmt->use_count)--; current->exec_domain = lookup_exec_domain(current->personality); current->binfmt = &aout_format; if (current->exec_domain && current->exec_domain->use_count) (*current->exec_domain->use_count)++; if (current->binfmt && current->binfmt->use_count) (*current->binfmt->use_count)++; set_brk(current->mm->start_brk, current->mm->brk); p = setup_arg_pages(p, bprm); p = (unsigned long) create_aout_tables((char *)p, bprm); current->mm->start_stack = p; #ifdef __alpha__ regs->gp = ex.a_gpvalue; #endif start_thread(regs, ex.a_entry, p); if (current->flags & PF_PTRACED) send_sig(SIGTRAP, current, 0); #ifndef CONFIG_ARM return 0; #else return regs->ARM_r0; #endif }
static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) { struct elfhdr elf_ex; struct elfhdr interp_elf_ex; struct file * file; struct exec interp_ex; struct inode *interpreter_inode; unsigned int load_addr; unsigned int interpreter_type = INTERPRETER_NONE; int i; int old_fs; int error; struct elf_phdr * elf_ppnt, *elf_phdata; int elf_exec_fileno; unsigned int elf_bss, k, elf_brk; int retval; char * elf_interpreter; unsigned int elf_entry; int status; unsigned int start_code, end_code, end_data; unsigned int elf_stack; char passed_fileno[6]; status = 0; load_addr = 0; elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ if (elf_ex.e_ident[0] != 0x7f || strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) return -ENOEXEC; /* First of all, some simple consistency checks */ if(elf_ex.e_type != ET_EXEC || (elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) || (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops || !bprm->inode->i_op->default_file_ops->mmap)){ return -ENOEXEC; }; /* Now read in all of the header information */ elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize * elf_ex.e_phnum, GFP_KERNEL); old_fs = get_fs(); set_fs(get_ds()); retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata, elf_ex.e_phentsize * elf_ex.e_phnum); set_fs(old_fs); if (retval < 0) { kfree (elf_phdata); return retval; } elf_ppnt = elf_phdata; elf_bss = 0; elf_brk = 0; elf_exec_fileno = open_inode(bprm->inode, O_RDONLY); if (elf_exec_fileno < 0) { kfree (elf_phdata); return elf_exec_fileno; } file = current->files->fd[elf_exec_fileno]; elf_stack = 0xffffffff; elf_interpreter = NULL; start_code = 0; end_code = 0; end_data = 0; old_fs = get_fs(); set_fs(get_ds()); for(i=0;i < elf_ex.e_phnum; i++){ if(elf_ppnt->p_type == PT_INTERP) { /* This is the program interpreter used for shared libraries - for now assume that this is an a.out format binary */ elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz, GFP_KERNEL); retval = read_exec(bprm->inode,elf_ppnt->p_offset,elf_interpreter, elf_ppnt->p_filesz); #if 0 printk("Using ELF interpreter %s\n", elf_interpreter); #endif if(retval >= 0) retval = namei(elf_interpreter, &interpreter_inode); if(retval >= 0) retval = read_exec(interpreter_inode,0,bprm->buf,128); if(retval >= 0){ interp_ex = *((struct exec *) bprm->buf); /* exec-header */ interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ }; if(retval < 0) { kfree (elf_phdata); kfree(elf_interpreter); return retval; }; }; elf_ppnt++; }; set_fs(old_fs); /* Some simple consistency checks for the interpreter */ if(elf_interpreter){ interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; if(retval < 0) { kfree(elf_interpreter); kfree(elf_phdata); return -ELIBACC; }; /* Now figure out which format our binary is */ if((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && (N_MAGIC(interp_ex) != QMAGIC)) interpreter_type = INTERPRETER_ELF; if (interp_elf_ex.e_ident[0] != 0x7f || strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) interpreter_type &= ~INTERPRETER_ELF; if(!interpreter_type) { kfree(elf_interpreter); kfree(elf_phdata); return -ELIBBAD; }; } /* OK, we are done with that, now set up the arg stuff, and then start this sucker up */ if (!bprm->sh_bang) { char * passed_p; if(interpreter_type == INTERPRETER_AOUT) { sprintf(passed_fileno, "%d", elf_exec_fileno); passed_p = passed_fileno; if(elf_interpreter) { bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2); bprm->argc++; }; }; if (!bprm->p) { if(elf_interpreter) { kfree(elf_interpreter); } kfree (elf_phdata); return -E2BIG; } } /* OK, This is the point of no return */ flush_old_exec(bprm); current->mm->end_data = 0; current->mm->end_code = 0; current->mm->start_mmap = ELF_START_MMAP; current->mm->mmap = NULL; elf_entry = (unsigned int) elf_ex.e_entry; /* Do this so that we can load the interpreter, if need be. We will change some of these later */ current->mm->rss = 0; bprm->p += change_ldt(0, bprm->page); current->mm->start_stack = bprm->p; /* Now we do a little grungy work by mmaping the ELF image into the correct location in memory. At this point, we assume that the image should be loaded at fixed address, not at a variable address. */ old_fs = get_fs(); set_fs(get_ds()); elf_ppnt = elf_phdata; for(i=0;i < elf_ex.e_phnum; i++){ if(elf_ppnt->p_type == PT_INTERP) { /* Set these up so that we are able to load the interpreter */ /* Now load the interpreter into user address space */ set_fs(old_fs); if(interpreter_type & 1) elf_entry = load_aout_interp(&interp_ex, interpreter_inode); if(interpreter_type & 2) elf_entry = load_elf_interp(&interp_elf_ex, interpreter_inode); old_fs = get_fs(); set_fs(get_ds()); iput(interpreter_inode); kfree(elf_interpreter); if(elf_entry == 0xffffffff) { printk("Unable to load interpreter\n"); kfree(elf_phdata); send_sig(SIGSEGV, current, 0); return 0; }; }; if(elf_ppnt->p_type == PT_LOAD) { error = do_mmap(file, elf_ppnt->p_vaddr & 0xfffff000, elf_ppnt->p_filesz + (elf_ppnt->p_vaddr & 0xfff), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, elf_ppnt->p_offset & 0xfffff000); #ifdef LOW_ELF_STACK if(elf_ppnt->p_vaddr & 0xfffff000 < elf_stack) elf_stack = elf_ppnt->p_vaddr & 0xfffff000; #endif if(!load_addr) load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; k = elf_ppnt->p_vaddr; if(k > start_code) start_code = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; if(k > elf_bss) elf_bss = k; if((elf_ppnt->p_flags | PROT_WRITE) && end_code < k) end_code = k; if(end_data < k) end_data = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; if(k > elf_brk) elf_brk = k; }; elf_ppnt++; }; set_fs(old_fs); kfree(elf_phdata); if(interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno); /* The following 3 lines need a little bit of work if we are loading an iBCS2 binary. We should initially load it this way, and if we get a lcall7, then we should look to see if the iBCS2 execution profile is present. If it is, then switch to that, otherwise bomb. */ current->personality = PER_LINUX; current->lcall7 = no_lcall7; current->signal_map = current->signal_invmap = ident_map; current->executable = bprm->inode; bprm->inode->i_count++; #ifdef LOW_ELF_STACK current->start_stack = p = elf_stack - 4; #endif bprm->p -= MAX_ARG_PAGES*PAGE_SIZE; bprm->p = (unsigned long) create_elf_tables((char *)bprm->p, bprm->argc, bprm->envc, (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), load_addr, (interpreter_type == INTERPRETER_AOUT ? 0 : 1)); if(interpreter_type == INTERPRETER_AOUT) current->mm->arg_start += strlen(passed_fileno) + 1; current->mm->start_brk = current->mm->brk = elf_brk; current->mm->end_code = end_code; current->mm->start_code = start_code; current->mm->end_data = end_data; current->mm->start_stack = bprm->p; current->suid = current->euid = bprm->e_uid; current->sgid = current->egid = bprm->e_gid; /* Calling sys_brk effectively mmaps the pages that we need for the bss and break sections */ current->mm->brk = (elf_bss + 0xfff) & 0xfffff000; sys_brk((elf_brk + 0xfff) & 0xfffff000); padzero(elf_bss); /* Why this, you ask??? Well SVr4 maps page 0 as read-only, and some applications "depend" upon this behavior. Since we do not have the power to recompile these, we emulate the SVr4 behavior. Sigh. */ error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); regs->eip = elf_entry; /* eip, magic happens :-) */ regs->esp = bprm->p; /* stack pointer */ if (current->flags & PF_PTRACED) send_sig(SIGTRAP, current, 0); return 0; }
static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) { struct exec ex; unsigned long error; unsigned long fd_offset; unsigned long rlim; int retval; ex = *((struct exec *) bprm->buf); /* exec-header */ if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) || N_TRSIZE(ex) || N_DRSIZE(ex) || bprm->file->f_dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { return -ENOEXEC; } fd_offset = N_TXTOFF(ex); /* Check initial limits. This avoids letting people circumvent * size limits imposed on them by creating programs with large * arrays in the data or bss. */ rlim = current->rlim[RLIMIT_DATA].rlim_cur; if (rlim >= RLIM_INFINITY) rlim = ~0; if (ex.a_data + ex.a_bss > rlim) return -ENOMEM; /* Flush all traces of the currently running executable */ retval = flush_old_exec(bprm); if (retval) return retval; /* OK, This is the point of no return */ #if defined(__alpha__) SET_AOUT_PERSONALITY(bprm, ex); #elif defined(__sparc__) set_personality(PER_SUNOS); #if !defined(__sparc_v9__) memcpy(¤t->thread.core_exec, &ex, sizeof(struct exec)); #endif #else set_personality(PER_LINUX); #endif current->mm->end_code = ex.a_text + (current->mm->start_code = N_TXTADDR(ex)); current->mm->end_data = ex.a_data + (current->mm->start_data = N_DATADDR(ex)); current->mm->brk = ex.a_bss + (current->mm->start_brk = N_BSSADDR(ex)); current->mm->rss = 0; current->mm->mmap = NULL; #ifdef CONFIG_ARM_FASS arch_new_mm(current, current->mm); #endif compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; #ifdef __sparc__ if (N_MAGIC(ex) == NMAGIC) { loff_t pos = fd_offset; /* F**k me plenty... */ /* <AOL></AOL> */ error = do_brk(N_TXTADDR(ex), ex.a_text); bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex), ex.a_text, &pos); error = do_brk(N_DATADDR(ex), ex.a_data); bprm->file->f_op->read(bprm->file, (char *) N_DATADDR(ex), ex.a_data, &pos); goto beyond_if; } #endif if (N_MAGIC(ex) == OMAGIC) { unsigned long text_addr, map_size; loff_t pos; text_addr = N_TXTADDR(ex); #if defined(__alpha__) || defined(__sparc__) pos = fd_offset; map_size = ex.a_text+ex.a_data + PAGE_SIZE - 1; #else pos = 32; map_size = ex.a_text+ex.a_data; #endif error = do_brk(text_addr & PAGE_MASK, map_size); if (error != (text_addr & PAGE_MASK)) { send_sig(SIGKILL, current, 0); return error; } error = bprm->file->f_op->read(bprm->file, (char *)text_addr, ex.a_text+ex.a_data, &pos); if ((signed long)error < 0) { send_sig(SIGKILL, current, 0); return error; } flush_icache_range(text_addr, text_addr+ex.a_text+ex.a_data); } else { static unsigned long error_time, error_time2; if ((ex.a_text & 0xfff || ex.a_data & 0xfff) && (N_MAGIC(ex) != NMAGIC) && (jiffies-error_time2) > 5*HZ) { printk(KERN_NOTICE "executable not page aligned\n"); error_time2 = jiffies; } if ((fd_offset & ~PAGE_MASK) != 0 && (jiffies-error_time) > 5*HZ) { printk(KERN_WARNING "fd_offset is not page aligned. Please convert program: %s\n", bprm->file->f_dentry->d_name.name); error_time = jiffies; } if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) { loff_t pos = fd_offset; do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data); bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex), ex.a_text+ex.a_data, &pos); flush_icache_range((unsigned long) N_TXTADDR(ex), (unsigned long) N_TXTADDR(ex) + ex.a_text+ex.a_data); goto beyond_if; } down_write(¤t->mm->mmap_sem); error = do_mmap(bprm->file, N_TXTADDR(ex), ex.a_text, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset); up_write(¤t->mm->mmap_sem); if (error != N_TXTADDR(ex)) { send_sig(SIGKILL, current, 0); return error; } down_write(¤t->mm->mmap_sem); error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset + ex.a_text); up_write(¤t->mm->mmap_sem); if (error != N_DATADDR(ex)) { send_sig(SIGKILL, current, 0); return error; } } beyond_if: set_binfmt(&aout_format); set_brk(current->mm->start_brk, current->mm->brk); retval = setup_arg_pages(bprm); if (retval < 0) { /* Someone check-me: is this error path enough? */ send_sig(SIGKILL, current, 0); return retval; } current->mm->start_stack = (unsigned long) create_aout_tables((char *) bprm->p, bprm); #ifdef __alpha__ regs->gp = ex.a_gpvalue; #endif start_thread(regs, ex.a_entry, current->mm->start_stack); if (current->ptrace & PT_PTRACED) send_sig(SIGTRAP, current, 0); #ifndef __arm__ return 0; #else return regs->ARM_r0; #endif }
static inline int do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) { struct file * file; struct dentry *interpreter_dentry = NULL; /* to shut gcc up */ unsigned long load_addr = 0, load_bias; int load_addr_set = 0; char * elf_interpreter = NULL; unsigned int interpreter_type = INTERPRETER_NONE; unsigned char ibcs2_interpreter = 0; mm_segment_t old_fs; unsigned long error; struct elf_phdr * elf_ppnt, *elf_phdata; unsigned long elf_bss, k, elf_brk; int elf_exec_fileno; int retval, size, i; unsigned long elf_entry, interp_load_addr = 0; unsigned long start_code, end_code, end_data; struct elfhdr elf_ex; struct elfhdr interp_elf_ex; struct exec interp_ex; char passed_fileno[6]; /* Get the exec-header */ elf_ex = *((struct elfhdr *) bprm->buf); retval = -ENOEXEC; /* First of all, some simple consistency checks */ if (elf_ex.e_ident[0] != 0x7f || strncmp(&elf_ex.e_ident[1], "ELF", 3) != 0) goto out; if (elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) goto out; if (!elf_check_arch(elf_ex.e_machine)) goto out; #ifdef __mips__ /* allow only mips1 if exec is MIPSEB elf, because IRIX binaries handled elsewhere. */ /* borrowed from binutils/include/elf/common.h*/ #define EI_DATA 5 /* Data encoding */ #define ELFDATA2MSB 2 /* 2's complement, big endian */ if ((elf_ex.e_ident[EI_DATA] == ELFDATA2MSB ) && (elf_ex.e_flags & EF_MIPS_ARCH) ) { retval = -ENOEXEC; goto out; } #endif if (!bprm->dentry->d_inode->i_op || !bprm->dentry->d_inode->i_op->default_file_ops || !bprm->dentry->d_inode->i_op->default_file_ops->mmap) goto out; /* Now read in all of the header information */ retval = -ENOMEM; size = elf_ex.e_phentsize * elf_ex.e_phnum; elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL); if (!elf_phdata) goto out; retval = read_exec(bprm->dentry, elf_ex.e_phoff, (char *) elf_phdata, size, 1); if (retval < 0) goto out_free_ph; retval = open_dentry(bprm->dentry, O_RDONLY); if (retval < 0) goto out_free_ph; elf_exec_fileno = retval; file = fget(elf_exec_fileno); elf_ppnt = elf_phdata; elf_bss = 0; elf_brk = 0; start_code = ~0UL; end_code = 0; end_data = 0; for (i = 0; i < elf_ex.e_phnum; i++) { if (elf_ppnt->p_type == PT_INTERP) { retval = -EINVAL; if (elf_interpreter) goto out_free_interp; /* This is the program interpreter used for * shared libraries - for now assume that this * is an a.out format binary */ retval = -ENOMEM; elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz, GFP_KERNEL); if (!elf_interpreter) goto out_free_file; retval = read_exec(bprm->dentry, elf_ppnt->p_offset, elf_interpreter, elf_ppnt->p_filesz, 1); if (retval < 0) goto out_free_interp; /* If the program interpreter is one of these two, * then assume an iBCS2 image. Otherwise assume * a native linux image. */ if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) ibcs2_interpreter = 1; #if 0 printk("Using ELF interpreter %s\n", elf_interpreter); #endif old_fs = get_fs(); /* This could probably be optimized */ set_fs(get_ds()); #ifdef __sparc__ if (ibcs2_interpreter) { unsigned long old_pers = current->personality; current->personality = PER_SVR4; interpreter_dentry = open_namei(elf_interpreter, 0, 0); current->personality = old_pers; } else #endif interpreter_dentry = open_namei(elf_interpreter, 0, 0); set_fs(old_fs); retval = PTR_ERR(interpreter_dentry); if (IS_ERR(interpreter_dentry)) goto out_free_interp; retval = permission(interpreter_dentry->d_inode, MAY_EXEC); if (retval < 0) goto out_free_dentry; retval = read_exec(interpreter_dentry, 0, bprm->buf, 128, 1); if (retval < 0) goto out_free_dentry; /* Get the exec headers */ interp_ex = *((struct exec *) bprm->buf); interp_elf_ex = *((struct elfhdr *) bprm->buf); } elf_ppnt++; } /* Some simple consistency checks for the interpreter */ if (elf_interpreter) { interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; /* Now figure out which format our binary is */ if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && (N_MAGIC(interp_ex) != QMAGIC)) interpreter_type = INTERPRETER_ELF; if (interp_elf_ex.e_ident[0] != 0x7f || strncmp(&interp_elf_ex.e_ident[1], "ELF", 3) != 0) interpreter_type &= ~INTERPRETER_ELF; retval = -ELIBBAD; if (!interpreter_type) goto out_free_dentry; /* Make sure only one type was selected */ if ((interpreter_type & INTERPRETER_ELF) && interpreter_type != INTERPRETER_ELF) { printk(KERN_WARNING "ELF: Ambiguous type, using ELF\n"); interpreter_type = INTERPRETER_ELF; } } /* OK, we are done with that, now set up the arg stuff, and then start this sucker up */ if (!bprm->sh_bang) { char * passed_p; if (interpreter_type == INTERPRETER_AOUT) { sprintf(passed_fileno, "%d", elf_exec_fileno); passed_p = passed_fileno; if (elf_interpreter) { bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2); bprm->argc++; } } retval = -E2BIG; if (!bprm->p) goto out_free_dentry; } /* Flush all traces of the currently running executable */ retval = flush_old_exec(bprm); if (retval) goto out_free_dentry; /* OK, This is the point of no return */ current->mm->end_data = 0; current->mm->end_code = 0; current->mm->mmap = NULL; current->flags &= ~PF_FORKNOEXEC; elf_entry = (unsigned long) elf_ex.e_entry; /* Do this immediately, since STACK_TOP as used in setup_arg_pages may depend on the personality. */ SET_PERSONALITY(elf_ex, ibcs2_interpreter); /* Do this so that we can load the interpreter, if need be. We will change some of these later */ current->mm->rss = 0; bprm->p = setup_arg_pages(bprm->p, bprm); current->mm->start_stack = bprm->p; /* Try and get dynamic programs out of the way of the default mmap base, as well as whatever program they might try to exec. This is because the brk will follow the loader, and is not movable. */ load_bias = ELF_PAGESTART(elf_ex.e_type==ET_DYN ? ELF_ET_DYN_BASE : 0); /* Now we do a little grungy work by mmaping the ELF image into the correct location in memory. At this point, we assume that the image should be loaded at fixed address, not at a variable address. */ old_fs = get_fs(); set_fs(get_ds()); for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { int elf_prot = 0, elf_flags; unsigned long vaddr; if (elf_ppnt->p_type != PT_LOAD) continue; if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE; vaddr = elf_ppnt->p_vaddr; if (elf_ex.e_type == ET_EXEC || load_addr_set) { elf_flags |= MAP_FIXED; } error = do_mmap(file, ELF_PAGESTART(load_bias + vaddr), (elf_ppnt->p_filesz + ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), elf_prot, elf_flags, (elf_ppnt->p_offset - ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); if (!load_addr_set) { load_addr_set = 1; load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset); if (elf_ex.e_type == ET_DYN) { load_bias += error - ELF_PAGESTART(load_bias + vaddr); load_addr += error; } } k = elf_ppnt->p_vaddr; if (k < start_code) start_code = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; if (k > elf_bss) elf_bss = k; if ((elf_ppnt->p_flags & PF_X) && end_code < k) end_code = k; if (end_data < k) end_data = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; if (k > elf_brk) elf_brk = k; } set_fs(old_fs); fput(file); /* all done with the file */ elf_entry += load_bias; elf_bss += load_bias; elf_brk += load_bias; start_code += load_bias; end_code += load_bias; end_data += load_bias; if (elf_interpreter) { if (interpreter_type == INTERPRETER_AOUT) elf_entry = load_aout_interp(&interp_ex, interpreter_dentry); else elf_entry = load_elf_interp(&interp_elf_ex, interpreter_dentry, &interp_load_addr); dput(interpreter_dentry); kfree(elf_interpreter); if (elf_entry == ~0UL) { printk(KERN_ERR "Unable to load interpreter\n"); kfree(elf_phdata); send_sig(SIGSEGV, current, 0); return 0; } } kfree(elf_phdata); if (interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno); if (current->exec_domain && current->exec_domain->module) __MOD_DEC_USE_COUNT(current->exec_domain->module); if (current->binfmt && current->binfmt->module) __MOD_DEC_USE_COUNT(current->binfmt->module); current->exec_domain = lookup_exec_domain(current->personality); current->binfmt = &elf_format; if (current->exec_domain && current->exec_domain->module) __MOD_INC_USE_COUNT(current->exec_domain->module); if (current->binfmt && current->binfmt->module) __MOD_INC_USE_COUNT(current->binfmt->module); #ifndef VM_STACK_FLAGS current->executable = dget(bprm->dentry); #endif compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; bprm->p = (unsigned long) create_elf_tables((char *)bprm->p, bprm->argc, bprm->envc, (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), load_addr, load_bias, interp_load_addr, (interpreter_type == INTERPRETER_AOUT ? 0 : 1)); /* N.B. passed_fileno might not be initialized? */ if (interpreter_type == INTERPRETER_AOUT) current->mm->arg_start += strlen(passed_fileno) + 1; current->mm->start_brk = current->mm->brk = elf_brk; current->mm->end_code = end_code; current->mm->start_code = start_code; current->mm->end_data = end_data; current->mm->start_stack = bprm->p; /* Calling set_brk effectively mmaps the pages that we need * for the bss and break sections */ set_brk(elf_bss, elf_brk); padzero(elf_bss); #if 0 printk("(start_brk) %x\n" , current->mm->start_brk); printk("(end_code) %x\n" , current->mm->end_code); printk("(start_code) %x\n" , current->mm->start_code); printk("(end_data) %x\n" , current->mm->end_data); printk("(start_stack) %x\n" , current->mm->start_stack); printk("(brk) %x\n" , current->mm->brk); #endif if ( current->personality == PER_SVR4 ) { /* Why this, you ask??? Well SVr4 maps page 0 as read-only, and some applications "depend" upon this behavior. Since we do not have the power to recompile these, we emulate the SVr4 behavior. Sigh. */ /* N.B. Shouldn't the size here be PAGE_SIZE?? */ error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); } #ifdef ELF_PLAT_INIT /* * The ABI may specify that certain registers be set up in special * ways (on i386 %edx is the address of a DT_FINI function, for * example. This macro performs whatever initialization to * the regs structure is required. */ ELF_PLAT_INIT(regs); #endif start_thread(regs, elf_entry, bprm->p); if (current->flags & PF_PTRACED) send_sig(SIGTRAP, current, 0); retval = 0; out: return retval; /* error cleanup */ out_free_dentry: dput(interpreter_dentry); out_free_interp: if (elf_interpreter) kfree(elf_interpreter); out_free_file: fput(file); sys_close(elf_exec_fileno); out_free_ph: kfree(elf_phdata); goto out; }
int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, struct image_info * info) { struct elfhdr elf_ex; struct elfhdr interp_elf_ex; struct exec interp_ex; int interpreter_fd = -1; /* avoid warning */ abi_ulong load_addr, load_bias; int load_addr_set = 0; unsigned int interpreter_type = INTERPRETER_NONE; unsigned char ibcs2_interpreter; int i; abi_ulong mapped_addr; struct elf_phdr * elf_ppnt; struct elf_phdr *elf_phdata; abi_ulong elf_bss, k, elf_brk; int retval; char * elf_interpreter; abi_ulong elf_entry, interp_load_addr = 0; int status; abi_ulong start_code, end_code, start_data, end_data; abi_ulong reloc_func_desc = 0; abi_ulong elf_stack; char passed_fileno[6]; ibcs2_interpreter = 0; status = 0; load_addr = 0; load_bias = 0; elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ #ifdef BSWAP_NEEDED bswap_ehdr(&elf_ex); #endif /* First of all, some simple consistency checks */ if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || (! elf_check_arch(elf_ex.e_machine))) { return -ENOEXEC; } bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p); bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p); bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p); if (!bprm->p) { retval = -E2BIG; } /* Now read in all of the header information */ elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum); if (elf_phdata == NULL) { return -ENOMEM; } retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); if(retval > 0) { retval = read(bprm->fd, (char *) elf_phdata, elf_ex.e_phentsize * elf_ex.e_phnum); } if (retval < 0) { perror("load_elf_binary"); exit(-1); free (elf_phdata); return -errno; } #ifdef BSWAP_NEEDED elf_ppnt = elf_phdata; for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) { bswap_phdr(elf_ppnt); } #endif elf_ppnt = elf_phdata; elf_bss = 0; elf_brk = 0; elf_stack = ~((abi_ulong)0UL); elf_interpreter = NULL; start_code = ~((abi_ulong)0UL); end_code = 0; start_data = 0; end_data = 0; interp_ex.a_info = 0; for(i=0;i < elf_ex.e_phnum; i++) { if (elf_ppnt->p_type == PT_INTERP) { if ( elf_interpreter != NULL ) { free (elf_phdata); free(elf_interpreter); close(bprm->fd); return -EINVAL; } /* This is the program interpreter used for * shared libraries - for now assume that this * is an a.out format binary */ elf_interpreter = (char *)malloc(elf_ppnt->p_filesz); if (elf_interpreter == NULL) { free (elf_phdata); close(bprm->fd); return -ENOMEM; } retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); if(retval >= 0) { retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz); } if(retval < 0) { perror("load_elf_binary2"); exit(-1); } /* If the program interpreter is one of these two, then assume an iBCS2 image. Otherwise assume a native linux image. */ /* JRP - Need to add X86 lib dir stuff here... */ if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) { ibcs2_interpreter = 1; } #if 0 printf("Using ELF interpreter %s\n", elf_interpreter); #endif if (retval >= 0) { retval = open(path(elf_interpreter), O_RDONLY); if(retval >= 0) { interpreter_fd = retval; } else { perror(elf_interpreter); exit(-1); /* retval = -errno; */ } } if (retval >= 0) { retval = lseek(interpreter_fd, 0, SEEK_SET); if(retval >= 0) { retval = read(interpreter_fd,bprm->buf,128); } } if (retval >= 0) { interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */ interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */ } if (retval < 0) { perror("load_elf_binary3"); exit(-1); free (elf_phdata); free(elf_interpreter); close(bprm->fd); return retval; } } elf_ppnt++; } /* Some simple consistency checks for the interpreter */ if (elf_interpreter){ interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; /* Now figure out which format our binary is */ if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && (N_MAGIC(interp_ex) != QMAGIC)) { interpreter_type = INTERPRETER_ELF; } if (interp_elf_ex.e_ident[0] != 0x7f || strncmp((char *)&interp_elf_ex.e_ident[1], "ELF",3) != 0) { interpreter_type &= ~INTERPRETER_ELF; } if (!interpreter_type) { free(elf_interpreter); free(elf_phdata); close(bprm->fd); return -ELIBBAD; } } /* OK, we are done with that, now set up the arg stuff, and then start this sucker up */ { char * passed_p; if (interpreter_type == INTERPRETER_AOUT) { snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd); passed_p = passed_fileno; if (elf_interpreter) { bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p); bprm->argc++; } } if (!bprm->p) { if (elf_interpreter) { free(elf_interpreter); } free (elf_phdata); close(bprm->fd); return -E2BIG; } } /* OK, This is the point of no return */ info->end_data = 0; info->end_code = 0; info->start_mmap = (abi_ulong)ELF_START_MMAP; info->mmap = 0; info->elf_flags = elf_ex.e_flags; elf_entry = (abi_ulong) elf_ex.e_entry; /* Do this so that we can load the interpreter, if need be. We will change some of these later */ info->rss = 0; bprm->p = setup_arg_pages(bprm->p, bprm, info); info->start_stack = bprm->p; /* Now we do a little grungy work by mmaping the ELF image into * the correct location in memory. At this point, we assume that * the image should be loaded at fixed address, not at a variable * address. */ for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { int elf_prot = 0; int elf_flags = 0; abi_ulong error; if (elf_ppnt->p_type != PT_LOAD) continue; if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; elf_flags = MAP_PRIVATE | MAP_DENYWRITE; if (elf_ex.e_type == ET_EXEC || load_addr_set) { elf_flags |= MAP_FIXED; } else if (elf_ex.e_type == ET_DYN) { /* Try and get dynamic programs out of the way of the default mmap base, as well as whatever program they might try to exec. This is because the brk will follow the loader, and is not movable. */ /* NOTE: for qemu, we do a big mmap to get enough space without hardcoding any address */ error = target_mmap(0, ET_DYN_MAP_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); if (error == -1) { perror("mmap"); exit(-1); } load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr); } error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), (elf_ppnt->p_filesz + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), elf_prot, (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), bprm->fd, (elf_ppnt->p_offset - TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); if (error == -1) { perror("mmap"); exit(-1); } #ifdef LOW_ELF_STACK if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr); #endif if (!load_addr_set) { load_addr_set = 1; load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; if (elf_ex.e_type == ET_DYN) { load_bias += error - TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); load_addr += load_bias; reloc_func_desc = load_bias; } } k = elf_ppnt->p_vaddr; if (k < start_code) start_code = k; if (start_data < k) start_data = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; if (k > elf_bss) elf_bss = k; if ((elf_ppnt->p_flags & PF_X) && end_code < k) end_code = k; if (end_data < k) end_data = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; if (k > elf_brk) elf_brk = k; } elf_entry += load_bias; elf_bss += load_bias; elf_brk += load_bias; start_code += load_bias; end_code += load_bias; start_data += load_bias; end_data += load_bias; if (elf_interpreter) { if (interpreter_type & 1) { elf_entry = load_aout_interp(&interp_ex, interpreter_fd); } else if (interpreter_type & 2) { elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, &interp_load_addr); } reloc_func_desc = interp_load_addr; close(interpreter_fd); free(elf_interpreter); if (elf_entry == ~((abi_ulong)0UL)) { printf("Unable to load interpreter\n"); free(elf_phdata); exit(-1); return 0; } } free(elf_phdata); if (loglevel) load_symbols(&elf_ex, bprm->fd); if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd); info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX); #ifdef LOW_ELF_STACK info->start_stack = bprm->p = elf_stack - 4; #endif bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &elf_ex, load_addr, load_bias, interp_load_addr, (interpreter_type == INTERPRETER_AOUT ? 0 : 1), info); info->load_addr = reloc_func_desc; info->start_brk = info->brk = elf_brk; info->end_code = end_code; info->start_code = start_code; info->start_data = start_data; info->end_data = end_data; info->start_stack = bprm->p; /* Calling set_brk effectively mmaps the pages that we need for the bss and break sections */ set_brk(elf_bss, elf_brk); padzero(elf_bss, elf_brk); #if 0 printf("(start_brk) %x\n" , info->start_brk); printf("(end_code) %x\n" , info->end_code); printf("(start_code) %x\n" , info->start_code); printf("(end_data) %x\n" , info->end_data); printf("(start_stack) %x\n" , info->start_stack); printf("(brk) %x\n" , info->brk); #endif if ( info->personality == PER_SVR4 ) { /* Why this, you ask??? Well SVr4 maps page 0 as read-only, and some applications "depend" upon this behavior. Since we do not have the power to recompile these, we emulate the SVr4 behavior. Sigh. */ mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, -1, 0); } info->entry = elf_entry; return 0; }
/* If shared library, return a malloced copy of the soname and set the * type, else return NULL. * * expected_type should be either LIB_ANY or one of the following:- * LIB_DLL * LIB_ELF * LIB_ELF_LIBC5 * LIB_ELF_LIBC6 * * If the lib is ELF and we can not deduce the type the type will * be set based on expected_type. * * If the expected, actual/deduced types missmatch we display a warning * and use the actual/deduced type. */ static char *is_shlib(const char *dir, const char *name, int *type, int *islink, int expected_type) { char *good = NULL; char *cp, *cp2; FILE *file; struct exec exec; ElfW(Ehdr) *elf_hdr; struct stat statbuf; char buff[BUFFER_SIZE]; char real[BUFFER_SIZE]; static int byteswapflag = -1; /* start with byte-order unknown */ /* see if name is of the form *.so* */ if (name[strlen(name) - 1] != '~' && (cp = strstr(name, ".so"))) { /* find the start of the Vminor part, if any */ if (cp[3] == '.' && (cp2 = strchr(cp + 4, '.'))) cp = cp2; else cp = cp + strlen(cp); /* construct the full path name */ sprintf(buff, "%s%s%s", dir, (*dir && strcmp(dir, "/")) ? "/" : "", name); /* get real path in case of chroot */ if (!chroot_realpath(chroot_dir, buff, real)) warn("can't resolve %s in chroot %s", buff, chroot_dir); /* first, make sure it's a regular file */ if (lstat(real, &statbuf)) warn("skipping %s", buff); else if (!S_ISREG(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) warnx("%s is not a regular file or symlink, skipping", buff); else { /* is it a regular file or a symlink */ *islink = S_ISLNK(statbuf.st_mode); /* then try opening it */ if (!(file = fopen(real, "rb"))) warn("skipping %s", buff); else { /* now make sure it's a shared library */ if (fread(&exec, sizeof exec, 1, file) < 1) warnx("can't read header from %s, skipping", buff); else if (N_MAGIC(exec) != ZMAGIC && N_MAGIC(exec) != QMAGIC && N_MAGIC_SWAP(exec) != ZMAGIC && N_MAGIC_SWAP(exec) != QMAGIC) { elf_hdr = (ElfW(Ehdr) *) & exec; if (elf_hdr->e_ident[0] != 0x7f || strncmp((char *)elf_hdr->e_ident + 1, "ELF", 3) != 0) { /* silently ignore linker scripts */ if (strncmp((char *)&exec, "/* GNU ld", 9) != 0) warnx("%s is not a shared library, skipping", buff); } else { /* always call readsoname to update type */ if (expected_type == LIB_DLL) { warnx("%s is not an a.out library, it's ELF!", buff); expected_type = LIB_ANY; } *type = LIB_ELF; good = readsoname(buff, file, expected_type, type, elf_hdr->e_ident[EI_CLASS]); if (byteswapflag == -1) /* byte-order detected */ byteswapflag = byteswap; if (good == NULL || *islink) { if (good != NULL) free(good); good = xstrdup(name); } else { /* if the soname does not match the filename, issue a warning, but only in debug mode. */ int len = strlen(good); if (debug && (strncmp(good, name, len) != 0 || (name[len] != '\0' && name[len] != '.'))) warnx("%s has inconsistent soname (%s)", buff, good); } } } else { /* Determine byte-order */ byteswap = (N_MAGIC(exec) == ZMAGIC || N_MAGIC(exec) == QMAGIC) ? 0 : 1; if (byteswapflag == -1) /* byte-order detected */ byteswapflag = byteswap; if (*islink) good = xstrdup(name); else { good = xmalloc(cp - name + 1); strncpy(good, name, cp - name); good[cp - name] = '\0'; } if (expected_type != LIB_ANY && expected_type != LIB_DLL) { warnx("%s is not an ELF library, its an a.out DLL!", buff); expected_type = LIB_ANY; } *type = LIB_DLL; } fclose(file); if (byteswapflag >= 0 && byteswap != byteswapflag) { byteswapflag = -2; warnx("mixed byte-order detected, using host byte-order..."); } if (byteswapflag == -2) byteswap = 0; } }
/* N.B. Move to .h file and use code in fs/binfmt_aout.c? */ static int load_aout32_library(struct file *file) { struct inode * inode; unsigned long bss, start_addr, len; unsigned long error; int retval; struct exec ex; inode = file->f_path.dentry->d_inode; retval = -ENOEXEC; error = kernel_read(file, 0, (char *) &ex, sizeof(ex)); if (error != sizeof(ex)) goto out; /* We come in here for the regular a.out style of shared libraries */ if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) || N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) || inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { goto out; } if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) && (N_TXTOFF(ex) < inode->i_sb->s_blocksize)) { printk("N_TXTOFF < BLOCK_SIZE. Please convert library\n"); goto out; } if (N_FLAGS(ex)) goto out; /* For QMAGIC, the starting address is 0x20 into the page. We mask this off to get the starting address for the page */ start_addr = ex.a_entry & 0xfffff000; /* Now use mmap to map the library into memory. */ down_write(¤t->mm->mmap_sem); error = do_mmap(file, start_addr, ex.a_text + ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, N_TXTOFF(ex)); up_write(¤t->mm->mmap_sem); retval = error; if (error != start_addr) goto out; len = PAGE_ALIGN(ex.a_text + ex.a_data); bss = ex.a_text + ex.a_data + ex.a_bss; if (bss > len) { down_write(¤t->mm->mmap_sem); error = do_brk(start_addr + len, bss - len); up_write(¤t->mm->mmap_sem); retval = error; if (error != start_addr + len) goto out; } retval = 0; out: return retval; }
int aout_load(struct sys_info *info, ihandle_t dev) { int retval = -1; struct exec ehdr; unsigned long start, size; unsigned int offset; image_name = image_version = NULL; /* Mark the saved-program-state as invalid */ feval("0 state-valid !"); fd = open_ih(dev); if (fd == -1) { goto out; } for (offset = 0; offset < 16 * 512; offset += 512) { seek_io(fd, offset); if (read_io(fd, &ehdr, sizeof ehdr) != sizeof ehdr) { debug("Can't read a.out header\n"); retval = LOADER_NOT_SUPPORT; goto out; } if (is_aout(&ehdr)) break; } if (!is_aout(&ehdr)) { debug("Not a bootable a.out image\n"); retval = LOADER_NOT_SUPPORT; goto out; } if (ehdr.a_text == 0x30800007) ehdr.a_text=64*1024; if (N_MAGIC(ehdr) == NMAGIC) { size = addr_fixup(N_DATADDR(ehdr)) + addr_fixup(ehdr.a_data); } else { size = addr_fixup(ehdr.a_text) + addr_fixup(ehdr.a_data); } if (size < 7680) size = 7680; fword("load-base"); start = POP(); // N_TXTADDR(ehdr); memcpy((void *)start, &ehdr, sizeof(ehdr)); if (!check_mem_ranges(info, start, size)) goto out; printf("Loading a.out %s...\n", image_name ? image_name : "image"); seek_io(fd, offset + N_TXTOFF(ehdr)); if (N_MAGIC(ehdr) == NMAGIC) { if ((size_t)read_io(fd, (void *)(start + N_TXTOFF(ehdr)), ehdr.a_text) != ehdr.a_text) { printf("Can't read program text segment (size 0x" FMT_aout_ehdr ")\n", ehdr.a_text); goto out; } if ((size_t)read_io(fd, (void *)(start + N_DATADDR(ehdr)), ehdr.a_data) != ehdr.a_data) { printf("Can't read program data segment (size 0x" FMT_aout_ehdr ")\n", ehdr.a_data); goto out; } } else { if ((size_t)read_io(fd, (void *)(start + N_TXTOFF(ehdr)), size) != size) { printf("Can't read program (size 0x" FMT_sizet ")\n", size); goto out; } } debug("Loaded %lu bytes\n", size); debug("entry point is %#lx\n", start); // Initialise saved-program-state PUSH(size); feval("load-state >ls.file-size !"); feval("aout load-state >ls.file-type !"); out: close_io(fd); return retval; }
static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) { struct file *interpreter = NULL; /* to shut gcc up */ unsigned long load_addr = 0, load_bias = 0; int load_addr_set = 0; char * elf_interpreter = NULL; unsigned int interpreter_type = INTERPRETER_NONE; unsigned char ibcs2_interpreter = 0; unsigned long error; struct elf_phdr * elf_ppnt, *elf_phdata; unsigned long elf_bss, k, elf_brk; int elf_exec_fileno; int retval, i; unsigned int size; unsigned long elf_entry, interp_load_addr = 0; unsigned long start_code, end_code, start_data, end_data; unsigned long reloc_func_desc = 0; struct elfhdr elf_ex; struct elfhdr interp_elf_ex; struct exec interp_ex; char passed_fileno[6]; struct files_struct *files; /* Get the exec-header */ elf_ex = *((struct elfhdr *) bprm->buf); retval = -ENOEXEC; /* First of all, some simple consistency checks */ if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0) goto out; if (elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) goto out; if (!elf_check_arch(&elf_ex)) goto out; if (!bprm->file->f_op||!bprm->file->f_op->mmap) goto out; /* Now read in all of the header information */ if (elf_ex.e_phentsize != sizeof(struct elf_phdr)) goto out; if (elf_ex.e_phnum < 1 || elf_ex.e_phnum > 65536U / sizeof(struct elf_phdr)) goto out; size = elf_ex.e_phnum * sizeof(struct elf_phdr); retval = -ENOMEM; elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL); if (!elf_phdata) goto out; retval = kernel_read(bprm->file, elf_ex.e_phoff, (char *) elf_phdata, size); if (retval != size) { if (retval >= 0) retval = -EIO; goto out_free_ph; } files = current->files; /* Refcounted so ok */ retval = unshare_files(); if (retval < 0) goto out_free_ph; if (files == current->files) { put_files_struct(files); files = NULL; } /* exec will make our files private anyway, but for the a.out loader stuff we need to do it earlier */ retval = get_unused_fd(); if (retval < 0) goto out_free_fh; get_file(bprm->file); fd_install(elf_exec_fileno = retval, bprm->file); elf_ppnt = elf_phdata; elf_bss = 0; elf_brk = 0; start_code = ~0UL; end_code = 0; start_data = 0; end_data = 0; for (i = 0; i < elf_ex.e_phnum; i++) { if (elf_ppnt->p_type == PT_INTERP) { /* This is the program interpreter used for * shared libraries - for now assume that this * is an a.out format binary */ retval = -ENOEXEC; if (elf_ppnt->p_filesz > PATH_MAX || elf_ppnt->p_filesz < 2) goto out_free_file; retval = -ENOMEM; elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz, GFP_KERNEL); if (!elf_interpreter) goto out_free_file; retval = kernel_read(bprm->file, elf_ppnt->p_offset, elf_interpreter, elf_ppnt->p_filesz); if (retval != elf_ppnt->p_filesz) { if (retval >= 0) retval = -EIO; goto out_free_interp; } /* make sure path is NULL terminated */ retval = -ENOEXEC; if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') goto out_free_interp; /* If the program interpreter is one of these two, * then assume an iBCS2 image. Otherwise assume * a native linux image. */ if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) ibcs2_interpreter = 1; #if 0 printk("Using ELF interpreter %s\n", elf_interpreter); #endif SET_PERSONALITY(elf_ex, ibcs2_interpreter); interpreter = open_exec(elf_interpreter); retval = PTR_ERR(interpreter); if (IS_ERR(interpreter)) goto out_free_interp; retval = kernel_read(interpreter, 0, bprm->buf, BINPRM_BUF_SIZE); if (retval != BINPRM_BUF_SIZE) { if (retval >= 0) retval = -EIO; goto out_free_dentry; } /* Get the exec headers */ interp_ex = *((struct exec *) bprm->buf); interp_elf_ex = *((struct elfhdr *) bprm->buf); break; } elf_ppnt++; } /* Some simple consistency checks for the interpreter */ if (elf_interpreter) { interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; /* Now figure out which format our binary is */ if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && (N_MAGIC(interp_ex) != QMAGIC)) interpreter_type = INTERPRETER_ELF; if (memcmp(interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0) interpreter_type &= ~INTERPRETER_ELF; retval = -ELIBBAD; if (!interpreter_type) goto out_free_dentry; /* Make sure only one type was selected */ if ((interpreter_type & INTERPRETER_ELF) && interpreter_type != INTERPRETER_ELF) { // FIXME - ratelimit this before re-enabling // printk(KERN_WARNING "ELF: Ambiguous type, using ELF\n"); interpreter_type = INTERPRETER_ELF; } /* Verify the interpreter has a valid arch */ if ((interpreter_type == INTERPRETER_ELF) && !elf_check_arch(&interp_elf_ex)) goto out_free_dentry; } else { /* Executables without an interpreter also need a personality */ SET_PERSONALITY(elf_ex, ibcs2_interpreter); } /* OK, we are done with that, now set up the arg stuff, and then start this sucker up */ if (!bprm->sh_bang) { char * passed_p; if (interpreter_type == INTERPRETER_AOUT) { sprintf(passed_fileno, "%d", elf_exec_fileno); passed_p = passed_fileno; if (elf_interpreter) { retval = copy_strings_kernel(1,&passed_p,bprm); if (retval) goto out_free_dentry; bprm->argc++; } } } else { /* Executables without an interpreter also need a personality */ SET_PERSONALITY(elf_ex, ibcs2_interpreter); } /* Flush all traces of the currently running executable */ retval = flush_old_exec(bprm); if (retval) goto out_free_dentry; /* Discard our unneeded old files struct */ if (files) { steal_locks(files); put_files_struct(files); files = NULL; } /* OK, This is the point of no return */ current->mm->start_data = 0; current->mm->end_data = 0; current->mm->end_code = 0; current->mm->mmap = NULL; current->flags &= ~PF_FORKNOEXEC; elf_entry = (unsigned long) elf_ex.e_entry; /* Do this so that we can load the interpreter, if need be. We will change some of these later */ current->mm->rss = 0; retval = setup_arg_pages(bprm); if (retval < 0) { send_sig(SIGKILL, current, 0); return retval; } current->mm->start_stack = bprm->p; /* Now we do a little grungy work by mmaping the ELF image into the correct location in memory. At this point, we assume that the image should be loaded at fixed address, not at a variable address. */ for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { int elf_prot = 0, elf_flags; unsigned long vaddr; if (elf_ppnt->p_type != PT_LOAD) continue; if (unlikely (elf_brk > elf_bss)) { unsigned long nbyte; /* There was a PT_LOAD segment with p_memsz > p_filesz before this one. Map anonymous pages, if needed, and clear the area. */ retval = set_brk (elf_bss + load_bias, elf_brk + load_bias); if (retval) { send_sig(SIGKILL, current, 0); goto out_free_dentry; } nbyte = ELF_PAGEOFFSET(elf_bss); if (nbyte) { nbyte = ELF_MIN_ALIGN - nbyte; if (nbyte > elf_brk - elf_bss) nbyte = elf_brk - elf_bss; clear_user((void *) elf_bss + load_bias, nbyte); } } if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE; vaddr = elf_ppnt->p_vaddr; if (elf_ex.e_type == ET_EXEC || load_addr_set) { elf_flags |= MAP_FIXED; } else if (elf_ex.e_type == ET_DYN) { /* Try and get dynamic programs out of the way of the default mmap base, as well as whatever program they might try to exec. This is because the brk will follow the loader, and is not movable. */ load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); } error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags); if (BAD_ADDR(error)) { send_sig(SIGKILL, current, 0); goto out_free_dentry; } if (!load_addr_set) { load_addr_set = 1; load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset); if (elf_ex.e_type == ET_DYN) { load_bias += error - ELF_PAGESTART(load_bias + vaddr); load_addr += load_bias; reloc_func_desc = load_addr; } } k = elf_ppnt->p_vaddr; if (k < start_code) start_code = k; if (start_data < k) start_data = k; /* * Check to see if the section's size will overflow the * allowed task size. Note that p_filesz must always be * <= p_memsz so it is only necessary to check p_memsz. */ if (k > TASK_SIZE || elf_ppnt->p_filesz > elf_ppnt->p_memsz || elf_ppnt->p_memsz > TASK_SIZE || TASK_SIZE - elf_ppnt->p_memsz < k) { /* set_brk can never work. Avoid overflows. */ send_sig(SIGKILL, current, 0); goto out_free_dentry; } k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; if (k > elf_bss) elf_bss = k; if ((elf_ppnt->p_flags & PF_X) && end_code < k) end_code = k; if (end_data < k) end_data = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; if (k > elf_brk) elf_brk = k; } elf_entry += load_bias; elf_bss += load_bias; elf_brk += load_bias; start_code += load_bias; end_code += load_bias; start_data += load_bias; end_data += load_bias; /* Calling set_brk effectively mmaps the pages that we need * for the bss and break sections. We must do this before * mapping in the interpreter, to make sure it doesn't wind * up getting placed where the bss needs to go. */ retval = set_brk(elf_bss, elf_brk); if (retval) { send_sig(SIGKILL, current, 0); goto out_free_dentry; } padzero(elf_bss); if (elf_interpreter) { if (interpreter_type == INTERPRETER_AOUT) elf_entry = load_aout_interp(&interp_ex, interpreter); else elf_entry = load_elf_interp(&interp_elf_ex, interpreter, &interp_load_addr); if (BAD_ADDR(elf_entry)) { printk(KERN_ERR "Unable to load interpreter %.128s\n", elf_interpreter); force_sig(SIGSEGV, current); retval = -ENOEXEC; /* Nobody gets to see this, but.. */ goto out_free_dentry; } reloc_func_desc = interp_load_addr; allow_write_access(interpreter); fput(interpreter); kfree(elf_interpreter); } kfree(elf_phdata); if (interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno); set_binfmt(&elf_format); compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; bprm->p = (unsigned long) create_elf_tables((char *)bprm->p, bprm->argc, bprm->envc, &elf_ex, load_addr, load_bias, interp_load_addr, (interpreter_type == INTERPRETER_AOUT ? 0 : 1)); /* N.B. passed_fileno might not be initialized? */ if (interpreter_type == INTERPRETER_AOUT) current->mm->arg_start += strlen(passed_fileno) + 1; current->mm->start_brk = current->mm->brk = elf_brk; current->mm->end_code = end_code; current->mm->start_code = start_code; current->mm->start_data = start_data; current->mm->end_data = end_data; current->mm->start_stack = bprm->p; #if 0 printk("(start_brk) %lx\n" , (long) current->mm->start_brk); printk("(end_code) %lx\n" , (long) current->mm->end_code); printk("(start_code) %lx\n" , (long) current->mm->start_code); printk("(start_data) %lx\n" , (long) current->mm->start_data); printk("(end_data) %lx\n" , (long) current->mm->end_data); printk("(start_stack) %lx\n" , (long) current->mm->start_stack); printk("(brk) %lx\n" , (long) current->mm->brk); #endif if (current->personality & MMAP_PAGE_ZERO) { /* Why this, you ask??? Well SVr4 maps page 0 as read-only, and some applications "depend" upon this behavior. Since we do not have the power to recompile these, we emulate the SVr4 behavior. Sigh. */ /* N.B. Shouldn't the size here be PAGE_SIZE?? */ down_write(¤t->mm->mmap_sem); error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); up_write(¤t->mm->mmap_sem); } #ifdef ELF_PLAT_INIT /* * The ABI may specify that certain registers be set up in special * ways (on i386 %edx is the address of a DT_FINI function, for * example. In addition, it may also specify (eg, PowerPC64 ELF) * that the e_entry field is the address of the function descriptor * for the startup routine, rather than the address of the startup * routine itself. This macro performs whatever initialization to * the regs structure is required as well as any relocations to the * function descriptor entries when executing dynamically linked apps. */ ELF_PLAT_INIT(regs, reloc_func_desc); #endif start_thread(regs, elf_entry, bprm->p); if (current->ptrace & PT_PTRACED) send_sig(SIGTRAP, current, 0); retval = 0; out: return retval; /* error cleanup */ out_free_dentry: allow_write_access(interpreter); if (interpreter) fput(interpreter); out_free_interp: if (elf_interpreter) kfree(elf_interpreter); out_free_file: sys_close(elf_exec_fileno); out_free_fh: if (files) { put_files_struct(current->files); current->files = files; } out_free_ph: kfree(elf_phdata); goto out; }
int main (int argc, char *argv[]) { size_t nwritten, tocopy, n, mem_size, fil_size, pad = 0; int fd, ofd, i, j, verbose = 0, primary = 0; char buf[8192], *inname; struct exec * aout; /* includes file & aout header */ long offset; #ifdef __ELF__ struct elfhdr *elf; struct elf_phdr *elf_phdr; /* program header */ unsigned long long e_entry; #endif prog_name = argv[0]; for (i = 1; i < argc && argv[i][0] == '-'; ++i) { for (j = 1; argv[i][j]; ++j) { switch (argv[i][j]) { case 'v': verbose = ~verbose; break; case 'b': pad = BLOCK_SIZE; break; case 'p': primary = 1; /* make primary bootblock */ break; } } } if (i >= argc) { usage(); } inname = argv[i++]; fd = open(inname, O_RDONLY); if (fd == -1) { perror("open"); exit(1); } ofd = 1; if (i < argc) { ofd = open(argv[i++], O_WRONLY | O_CREAT | O_TRUNC, 0666); if (ofd == -1) { perror("open"); exit(1); } } if (primary) { /* generate bootblock for primary loader */ unsigned long bb[64], sum = 0; struct stat st; off_t size; int i; if (ofd == 1) { usage(); } if (fstat(fd, &st) == -1) { perror("fstat"); exit(1); } size = (st.st_size + BLOCK_SIZE - 1) & ~(BLOCK_SIZE - 1); memset(bb, 0, sizeof(bb)); strcpy((char *) bb, "Linux SRM bootblock"); bb[60] = size / BLOCK_SIZE; /* count */ bb[61] = 1; /* starting sector # */ bb[62] = 0; /* flags---must be 0 */ for (i = 0; i < 63; ++i) { sum += bb[i]; } bb[63] = sum; if (write(ofd, bb, sizeof(bb)) != sizeof(bb)) { perror("boot-block write"); exit(1); } printf("%lu\n", size); return 0; } /* read and inspect exec header: */ if (read(fd, buf, sizeof(buf)) < 0) { perror("read"); exit(1); } #ifdef __ELF__ elf = (struct elfhdr *) buf; if (elf->e_ident[0] == 0x7f && strncmp((char *)elf->e_ident + 1, "ELF", 3) == 0) { if (elf->e_type != ET_EXEC) { fprintf(stderr, "%s: %s is not an ELF executable\n", prog_name, inname); exit(1); } if (!elf_check_arch(elf)) { fprintf(stderr, "%s: is not for this processor (e_machine=%d)\n", prog_name, elf->e_machine); exit(1); } if (elf->e_phnum != 1) { fprintf(stderr, "%s: %d program headers (forgot to link with -N?)\n", prog_name, elf->e_phnum); } e_entry = elf->e_entry; lseek(fd, elf->e_phoff, SEEK_SET); if (read(fd, buf, sizeof(*elf_phdr)) != sizeof(*elf_phdr)) { perror("read"); exit(1); } elf_phdr = (struct elf_phdr *) buf; offset = elf_phdr->p_offset; mem_size = elf_phdr->p_memsz; fil_size = elf_phdr->p_filesz; /* work around ELF bug: */ if (elf_phdr->p_vaddr < e_entry) { unsigned long delta = e_entry - elf_phdr->p_vaddr; offset += delta; mem_size -= delta; fil_size -= delta; elf_phdr->p_vaddr += delta; } if (verbose) { fprintf(stderr, "%s: extracting %#016lx-%#016lx (at %lx)\n", prog_name, (long) elf_phdr->p_vaddr, elf_phdr->p_vaddr + fil_size, offset); } } else #endif { aout = (struct exec *) buf; if (!(aout->fh.f_flags & COFF_F_EXEC)) { fprintf(stderr, "%s: %s is not in executable format\n", prog_name, inname); exit(1); } if (aout->fh.f_opthdr != sizeof(aout->ah)) { fprintf(stderr, "%s: %s has unexpected optional header size\n", prog_name, inname); exit(1); } if (N_MAGIC(*aout) != OMAGIC) { fprintf(stderr, "%s: %s is not an OMAGIC file\n", prog_name, inname); exit(1); } offset = N_TXTOFF(*aout); fil_size = aout->ah.tsize + aout->ah.dsize; mem_size = fil_size + aout->ah.bsize; if (verbose) { fprintf(stderr, "%s: extracting %#016lx-%#016lx (at %lx)\n", prog_name, aout->ah.text_start, aout->ah.text_start + fil_size, offset); } } if (lseek(fd, offset, SEEK_SET) != offset) { perror("lseek"); exit(1); } if (verbose) { fprintf(stderr, "%s: copying %lu byte from %s\n", prog_name, (unsigned long) fil_size, inname); } tocopy = fil_size; while (tocopy > 0) { n = tocopy; if (n > sizeof(buf)) { n = sizeof(buf); } tocopy -= n; if ((size_t) read(fd, buf, n) != n) { perror("read"); exit(1); } do { nwritten = write(ofd, buf, n); if ((ssize_t) nwritten == -1) { perror("write"); exit(1); } n -= nwritten; } while (n > 0); } if (pad) { mem_size = ((mem_size + pad - 1) / pad) * pad; } tocopy = mem_size - fil_size; if (tocopy > 0) { fprintf(stderr, "%s: zero-filling bss and aligning to %lu with %lu bytes\n", prog_name, pad, (unsigned long) tocopy); memset(buf, 0x00, sizeof(buf)); do { n = tocopy; if (n > sizeof(buf)) { n = sizeof(buf); } nwritten = write(ofd, buf, n); if ((ssize_t) nwritten == -1) { perror("write"); exit(1); } tocopy -= nwritten; } while (tocopy > 0); } return 0; }