📄 binfmt_elf.c
字号:
elf_interpreter = NULL; 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) { if (elf_interpreter != NULL) { iput(interpreter_inode); kfree(elf_phdata); kfree(elf_interpreter); sys_close(elf_exec_fileno); 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 *) kmalloc(elf_ppnt->p_filesz, GFP_KERNEL); if (elf_interpreter == NULL) { kfree(elf_phdata); sys_close(elf_exec_fileno); return -ENOMEM; } retval = read_exec(bprm->inode, elf_ppnt->p_offset, elf_interpreter, elf_ppnt->p_filesz, 1); /* 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 if (retval >= 0) { old_fs = get_fs(); /* This could probably be optimized */ set_fs(get_ds()); retval = ret_namei = open_namei(elf_interpreter, 0, 0, &interpreter_inode, NULL); set_fs(old_fs); } if (retval >= 0) retval = permission(interpreter_inode, MAY_EXEC); if (retval >= 0) retval = S_ISREG(interpreter_inode->i_mode) ? 0 : -EACCES; if (retval >= 0) retval = read_exec(interpreter_inode, 0, bprm->buf, 128, 1); if (retval >= 0) { interp_ex = *((struct exec *) bprm->buf); /* exec-header */ interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ } if (retval < 0) { if (ret_namei >= 0) iput(interpreter_inode); kfree(elf_phdata); kfree(elf_interpreter); sys_close(elf_exec_fileno); 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(&interp_elf_ex.e_ident[1], "ELF", 3) != 0) interpreter_type &= ~INTERPRETER_ELF; if (!interpreter_type) { iput(interpreter_inode); kfree(elf_interpreter); kfree(elf_phdata); sys_close(elf_exec_fileno); 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); } iput(interpreter_inode); kfree(elf_phdata); sys_close(elf_exec_fileno); return -E2BIG; } } if (flush_old_exec(bprm)) { iput(interpreter_inode); return -ENOMEM; } /* OK, This is the point of no return */ current->mm->end_data = 0; current->mm->end_code = 0; current->mm->start_mmap = ELF_START_MMAP; current->mm->mmap = NULL; 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; bprm->p = setup_arg_pages(bprm->p, bprm); 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()); for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { if (elf_ppnt->p_type == PT_LOAD) { int elf_prot = 0; 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; error = do_mmap(file, ELF_PAGESTART(elf_ppnt->p_vaddr), (elf_ppnt->p_filesz + ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), elf_prot, (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE), (elf_ppnt->p_offset - ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));#ifdef LOW_ELF_STACK if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) elf_stack = ELF_PAGESTART(elf_ppnt->p_vaddr);#endif if (!load_addr_set) { load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; load_addr_set = 1; } 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 1 if ((elf_ppnt->p_flags & PF_X) && end_code < k)#else if (!(elf_ppnt->p_flags & PF_W) && end_code < k)#endif 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); if (elf_interpreter) { if (interpreter_type & 1) elf_entry = load_aout_interp(&interp_ex, interpreter_inode); else if (interpreter_type & 2) elf_entry = load_elf_interp(&interp_elf_ex, interpreter_inode, &interp_load_addr); iput(interpreter_inode); kfree(elf_interpreter); if (elf_entry == ~0UL) { printk("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); current->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX); 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 = &elf_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)++;#ifndef VM_STACK_FLAGS current->executable = bprm->inode; bprm->inode->i_count++;#endif#ifdef LOW_ELF_STACK current->start_stack = bprm->p = elf_stack - 4;#endif current->suid = current->euid = current->fsuid = bprm->e_uid; current->sgid = current->egid = current->fsgid = bprm->e_gid; 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, interp_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; /* 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. */ 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); return 0;}static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs){ int retval; MOD_INC_USE_COUNT; retval = do_load_elf_binary(bprm, regs); MOD_DEC_USE_COUNT; return retval;}/* This is really simpleminded and specialized - we are loading an a.out library that is given an ELF header. */static inline int do_load_elf_library(int fd){ struct file *file; struct elfhdr elf_ex; struct elf_phdr *elf_phdata = NULL; struct inode *inode; unsigned long len; int elf_bss; int retval; unsigned long bss; int error; int i, j, k; len = 0; file = current->files->fd[fd]; inode = file->f_inode; elf_bss = 0; if (!file || !file->f_op) return -EACCES; /* seek to the beginning of 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 *) &elf_ex, sizeof(elf_ex)); set_fs(USER_DS); if (error != sizeof(elf_ex)) return -ENOEXEC; 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_phnum > 2 || !elf_check_arch(elf_ex.e_machine) || (!inode->i_op || !inode->i_op->default_file_ops->mmap)) return -ENOEXEC; /* Now read in all of the header information */ if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE) return -ENOEXEC; elf_phdata = (struct elf_phdr *) kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL); if (elf_phdata == NULL) return -ENOMEM; retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata, sizeof(struct elf_phdr) * elf_ex.e_phnum, 1); j = 0; for (i = 0; i < elf_ex.e_phnum; i++) if ((elf_phdata + i)->p_type == PT_LOAD) j++; if (j != 1) { kfree(elf_phdata); return -ENOEXEC; } while (elf_phdata->p_type != PT_LOAD) elf_phdata++; /* Now use mmap to map the library into memory. */ error = do_mmap(file, ELF_PAGESTART(elf_phdata->p_vaddr), (elf_phdata->p_filesz + ELF_PAGEOFFSET(elf_phdata->p_vaddr)), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, (elf_phdata->p_offset - ELF_PAGEOFFSET(elf_phdata->p_vaddr))); k = elf_phdata->p_vaddr + elf_phdata->p_filesz; if (k > elf_bss) elf_bss = k; if (error != ELF_PAGESTART(elf_phdata->p_vaddr)) { kfree(elf_phdata); return error; } padzero(elf_bss); len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr + ELF_EXEC_PAGESIZE - 1); bss = elf_phdata->p_memsz + elf_phdata->p_vaddr; if (bss > len) do_mmap(NULL, len, bss - len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); kfree(elf_phdata); return 0;}static int load_elf_library(int fd){ int retval; MOD_INC_USE_COUNT; retval = do_load_elf_library(fd); MOD_DEC_USE_COUNT; return retval;}/* * Note that some platforms still use traditional core dumps and not * the ELF core dump. Each platform can select it as appropriate. */#ifdef USE_ELF_CORE_DUMP/* * ELF core dumper * * Modelled on fs/exec.c:aout_core_dump() * Jeremy Fitzhardinge <jeremy@sw.oz.au> *//*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -