📄 binfmt_elf.c
字号:
/* * linux/fs/binfmt_elf.c * * These are the functions used to load ELF format executables as used * on SVr4 machines. Information on the format may be found in the book * "UNIX SYSTEM V RELEASE 4 Programmers Guide: Ansi C and Programming Support * Tools". * * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com). */#include <linux/module.h>#include <linux/fs.h>#include <linux/stat.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/mman.h>#include <linux/a.out.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/binfmts.h>#include <linux/string.h>#include <linux/fcntl.h>#include <linux/ptrace.h>#include <linux/malloc.h>#include <linux/shm.h>#include <linux/personality.h>#include <linux/elfcore.h>#include <asm/segment.h>#include <asm/pgtable.h>#include <linux/config.h>#define DLINFO_ITEMS 12#include <linux/elf.h>static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs);static int load_elf_library(int fd);extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);extern void dump_thread(struct pt_regs *, struct user *);/* * If we don't support core dumping, then supply a NULL so we * don't even try. */#ifdef USE_ELF_CORE_DUMPstatic int elf_core_dump(long signr, struct pt_regs *regs);#else#define elf_core_dump NULL#endif#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1))#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1))static struct linux_binfmt elf_format ={#ifndef MODULE NULL, NULL, load_elf_binary, load_elf_library, elf_core_dump#else NULL, &mod_use_count_, load_elf_binary, load_elf_library, elf_core_dump#endif};static void set_brk(unsigned long start, unsigned long end){ start = PAGE_ALIGN(start); end = PAGE_ALIGN(end); if (end <= start) return; do_mmap(NULL, start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0);}/* We need to explicitly zero any fractional pages after the data section (i.e. bss). This would contain the junk from the file that should not be in memory */static void padzero(unsigned long elf_bss){ unsigned long nbyte; char *fpnt; nbyte = elf_bss & (PAGE_SIZE - 1); if (nbyte) { nbyte = PAGE_SIZE - nbyte; /* FIXME: someone should investigate, why a bad binary is allowed to bring a wrong elf_bss until here, and how to react. Suffice the plain return? rossius@hrz.tu-chemnitz.de */ if (verify_area(VERIFY_WRITE, (void *) elf_bss, nbyte)) { return; } fpnt = (char *) elf_bss; do { put_user(0, fpnt++); } while (--nbyte); }}unsigned long *create_elf_tables(char *p, int argc, int envc, struct elfhdr *exec, unsigned long load_addr, unsigned long interp_load_addr, int ibcs){ unsigned long *argv, *envp, *dlinfo; unsigned long *sp; /* * Force 16 byte alignment here for generality. */ sp = (unsigned long *) (~15UL & (unsigned long) p); sp -= exec ? DLINFO_ITEMS * 2 : 2; dlinfo = sp; sp -= envc + 1; envp = sp; sp -= argc + 1; argv = sp; if (!ibcs) { put_user(envp, --sp); put_user(argv, --sp); }#define NEW_AUX_ENT(id, val) \ put_user ((id), dlinfo++); \ put_user ((val), dlinfo++) if (exec) { /* Put this here for an ELF program interpreter */ struct elf_phdr *eppnt; eppnt = (struct elf_phdr *) exec->e_phoff; NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff); NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); NEW_AUX_ENT(AT_PHNUM, exec->e_phnum); NEW_AUX_ENT(AT_PAGESZ, PAGE_SIZE); NEW_AUX_ENT(AT_BASE, interp_load_addr); NEW_AUX_ENT(AT_FLAGS, 0); NEW_AUX_ENT(AT_ENTRY, (unsigned long) exec->e_entry); NEW_AUX_ENT(AT_UID, (unsigned long) current->uid); NEW_AUX_ENT(AT_EUID, (unsigned long) current->euid); NEW_AUX_ENT(AT_GID, (unsigned long) current->gid); NEW_AUX_ENT(AT_EGID, (unsigned long) current->egid); } NEW_AUX_ENT(AT_NULL, 0);#undef NEW_AUX_ENT put_user((unsigned long) argc, --sp); current->mm->arg_start = (unsigned long) p; while (argc-- > 0) { put_user(p, argv++); while (get_user(p++)) /* nothing */ ; } put_user(0, argv); current->mm->arg_end = current->mm->env_start = (unsigned long) p; while (envc-- > 0) { put_user(p, envp++); while (get_user(p++)) /* nothing */ ; } put_user(0, envp); current->mm->env_end = (unsigned long) p; return sp;}/* This is much more generalized than the library routine read function, so we keep this separate. Technically the library read function is only provided so that we can read a.out libraries that have an ELF header */static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, struct inode *interpreter_inode, unsigned long *interp_load_addr){ struct file *file; struct elf_phdr *elf_phdata = NULL; struct elf_phdr *eppnt; unsigned long load_addr; int load_addr_set = 0; int elf_exec_fileno; int retval; unsigned long last_bss, elf_bss; unsigned long error; int i; elf_bss = 0; last_bss = 0; error = load_addr = 0; /* First of all, some simple consistency checks */ if ((interp_elf_ex->e_type != ET_EXEC && interp_elf_ex->e_type != ET_DYN) || !elf_check_arch(interp_elf_ex->e_machine) || (!interpreter_inode->i_op || !interpreter_inode->i_op->default_file_ops->mmap)) { return ~0UL; } /* Now read in all of the header information */ if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) return ~0UL; elf_phdata = (struct elf_phdr *) kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, GFP_KERNEL); if (!elf_phdata) return ~0UL; /* * If the size of this structure has changed, then punt, since * we will be doing the wrong thing. */ if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { kfree(elf_phdata); return ~0UL; } retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, (char *) elf_phdata, sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1); if (retval < 0) { kfree(elf_phdata); return retval; } elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY); if (elf_exec_fileno < 0) { kfree(elf_phdata); return ~0UL; } file = current->files->fd[elf_exec_fileno]; eppnt = elf_phdata; for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) if (eppnt->p_type == PT_LOAD) { int elf_type = MAP_PRIVATE | MAP_DENYWRITE; int elf_prot = 0; unsigned long vaddr = 0; unsigned long k; if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { elf_type |= MAP_FIXED; vaddr = eppnt->p_vaddr; } error = do_mmap(file, load_addr + ELF_PAGESTART(vaddr), eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), elf_prot, elf_type, eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr)); if (error > -1024UL) { /* Real error */ sys_close(elf_exec_fileno); kfree(elf_phdata); return ~0UL; } if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { load_addr = error; load_addr_set = 1; } /* * Find the end of the file mapping for this phdr, and keep * track of the largest address we see for this. */ k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; if (k > elf_bss) elf_bss = k; /* * Do the same thing for the memory mapping - between * elf_bss and last_bss is the bss section. */ k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; if (k > last_bss) last_bss = k; } /* Now use mmap to map the library into memory. */ sys_close(elf_exec_fileno); /* * Now fill out the bss section. First pad the last page up * to the page boundary, and then perform a mmap to make sure * that there are zeromapped pages up to and including the last * bss page. */ padzero(elf_bss); elf_bss = ELF_PAGESTART(elf_bss + ELF_EXEC_PAGESIZE - 1); /* What we have mapped so far */ /* Map the last of the bss segment */ if (last_bss > elf_bss) do_mmap(NULL, elf_bss, last_bss - elf_bss, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); kfree(elf_phdata); *interp_load_addr = load_addr; return ((unsigned long) interp_elf_ex->e_entry) + load_addr;}static unsigned long load_aout_interp(struct exec *interp_ex, struct inode *interpreter_inode){ int retval; unsigned long 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, 0); } 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, 0); } else retval = -1; if (retval >= 0) do_mmap(NULL, ELF_PAGESTART(interp_ex->a_text + interp_ex->a_data + ELF_EXEC_PAGESIZE - 1), interp_ex->a_bss, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); if (retval < 0) return ~0UL; return elf_entry;}/* * These are the functions used to load ELF style executables and shared * libraries. There is no binary dependent code anywhere else. */#define INTERPRETER_NONE 0#define INTERPRETER_AOUT 1#define INTERPRETER_ELF 2static inline int do_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 long load_addr; int load_addr_set = 0; unsigned int interpreter_type = INTERPRETER_NONE; unsigned char ibcs2_interpreter; int i; int old_fs; int error; struct elf_phdr *elf_ppnt, *elf_phdata; int elf_exec_fileno; unsigned long elf_bss, k, elf_brk; int retval, ret_namei = -1; char *elf_interpreter; unsigned long elf_entry, interp_load_addr = 0; int status; unsigned long start_code, end_code, end_data; unsigned long elf_stack; char passed_fileno[6]; ibcs2_interpreter = 0; 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_type != ET_DYN) || (!elf_check_arch(elf_ex.e_machine)) || (!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); if (elf_phdata == NULL) { return -ENOMEM; } retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata, elf_ex.e_phentsize * elf_ex.e_phnum, 1); 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 = ~0UL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -