📄 binfmt_pe.c
字号:
/* * binfmt_pe.c * * Copyright (C) 2006 Insigme Co., Ltd * * Authors: * - Chenzhan Hu * * This software has been developed while working on the Linux Unified Kernel * project (http://linux.insigma.com.cn) in the Insigma Reaserch Institute, * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). * * The project is sponsored by Insigma Co., Ltd. * * The authors can be reached at linux@insigma.com.cn. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * Revision History: * Jan 2006 - Created. */ /* * binfmt_pe.c: * Reference to Linux Kernel code */#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/stat.h>#include <linux/time.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/file.h>#include <linux/fcntl.h>#include <linux/ptrace.h>#include <linux/slab.h>#include <linux/shm.h>#include <linux/personality.h>#include <linux/elfcore.h>#include <linux/init.h>#include <linux/highuid.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/compiler.h>#include <linux/highmem.h>#include <linux/pagemap.h>#include <linux/security.h>#include <linux/syscalls.h>#include <linux/random.h>#include <asm/uaccess.h>#include <asm/param.h>#include <asm/page.h>#include <linux/elf.h>#include <linux/win32_process.h>#include <linux/win32_thread.h>#include "win32.h"#include "pefile.h"#include "section.h"#include "process.h"#include "thread.h"#include "apc.h"#ifdef CONFIG_UNIFIED_KERNELunsigned long extra_page = 0;extern asmlinkage void w32syscall_exit(void);#define NTDLL_SO#define ELF_PLATFORM (system_utsname.machine)#define ELF_HWCAP (boot_cpu_data.x86_capability[0])#define ELF_EXEC_PAGESIZE 4096#ifdef NTDLL_SO#ifndef elf_addr_t#define elf_addr_t unsigned long#endif#if ELF_EXEC_PAGESIZE > PAGE_SIZE# define ELF_MIN_ALIGN ELF_EXEC_PAGESIZE#else# define ELF_MIN_ALIGN PAGE_SIZE#endif#ifndef ELF_CORE_EFLAGS#define ELF_CORE_EFLAGS 0#endif#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_MIN_ALIGN-1))#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_MIN_ALIGN-1))#define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1))#ifdef CONFIG_STACK_GROWSUP#define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) + (items))#define STACK_ROUND(sp, items) \ ((15 + (unsigned long) ((sp) + (items))) &~ 15UL)#define STACK_ALLOC(sp, len) ({ elf_addr_t __user *old_sp = (elf_addr_t __user *)sp; sp += len; old_sp; })#else#define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) - (items))#define STACK_ROUND(sp, items) \ (((unsigned long) (sp - items)) &~ 15UL)#define STACK_ALLOC(sp, len) ({ sp -= len ; sp; })#endif#if ELF_CLASS == ELFCLASS32#define elf_off_t Elf32_Off#define elf_half_t Elf32_Half#else#define elf_off_t Elf64_Off#define elf_half_t Elf64_Half#endif#endifextern unsigned long get_ntdll_entry(void);extern unsigned long get_apc_dispatcher(void);extern unsigned long get_pe_entry(void);extern unsigned long get_interp_entry(void);extern unsigned long get_start_thunk(void);extern NTSTATUS STDCALL LdrpMapSystemDll(struct task_struct *tsk, char *name, unsigned long *ntdll_load_addr, unsigned long *interp_load_addr);voidSTDCALLPspThreadSpecialApc(PKAPC Apc, PKNORMAL_ROUTINE* NormalRoutine, PVOID* NormalContext, PVOID* SystemArgument1, PVOID* SystemArgument2);static int load_pe_binary(struct linux_binprm * bprm, struct pt_regs * regs);static struct linux_binfmt pe_format = { .module = THIS_MODULE, .load_binary = load_pe_binary, .load_shlib = NULL, .core_dump = NULL, .min_coredump = ELF_EXEC_PAGESIZE};#define BAD_ADDR(x) ((unsigned long)(x) > TASK_SIZE)#ifdef NTDLL_SOextern elf_off_t ntdll_phoff;extern elf_half_t ntdll_phnum;/* * create_elf_tables */static intcreate_elf_tables(struct linux_binprm *bprm, unsigned long load_addr, elf_off_t phoff, elf_half_t phnum, unsigned long entry){ unsigned long p = bprm->p; int argc = bprm->argc; int envc = bprm->envc; elf_addr_t __user *argv; elf_addr_t __user *envp; elf_addr_t __user *sp; elf_addr_t __user *u_platform; const char *k_platform = ELF_PLATFORM; int items; elf_addr_t *elf_info; int ei_index = 0; struct task_struct *tsk = current; /* * If this architecture has a platform capability string, copy it * to userspace. In some cases (Sparc), this info is impossible * for userspace to get any other way, in others (i386) it is * merely difficult. */ u_platform = NULL; if (k_platform) { size_t len = strlen(k_platform) + 1; /* * In some cases (e.g. Hyper-Threading), we want to avoid L1 * evictions by the processes running on the same package. One * thing we can do is to shuffle the initial stack for them. */ p = arch_align_stack(p); u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); if (__copy_to_user(u_platform, k_platform, len)) return -EFAULT; } /* Create the ELF interpreter info */ elf_info = (elf_addr_t *) current->mm->saved_auxv;#define NEW_AUX_ENT(id, val) \ do { elf_info[ei_index++] = id; elf_info[ei_index++] = val; } while (0)#ifdef ARCH_DLINFO11 /* * ARCH_DLINFO must come first so PPC can do its special alignment of * AUXV. */ ARCH_DLINFO;#endif NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP); NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE); NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); NEW_AUX_ENT(AT_PHDR, load_addr + phoff); NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); NEW_AUX_ENT(AT_PHNUM, phnum); NEW_AUX_ENT(AT_BASE, 0); NEW_AUX_ENT(AT_FLAGS, 0); NEW_AUX_ENT(AT_ENTRY, entry); NEW_AUX_ENT(AT_UID, (elf_addr_t) tsk->uid); NEW_AUX_ENT(AT_EUID, (elf_addr_t) tsk->euid); NEW_AUX_ENT(AT_GID, (elf_addr_t) tsk->gid); NEW_AUX_ENT(AT_EGID, (elf_addr_t) tsk->egid); NEW_AUX_ENT(AT_SECURE, (elf_addr_t) security_bprm_secureexec(bprm)); if (k_platform) {// NEW_AUX_ENT(AT_PLATFORM, (elf_addr_t)(unsigned long)u_platform); } if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) { NEW_AUX_ENT(AT_EXECFD, (elf_addr_t) bprm->interp_data); }#undef NEW_AUX_ENT /* AT_NULL is zero; clear the rest too */ memset(&elf_info[ei_index], 0, sizeof current->mm->saved_auxv - ei_index * sizeof elf_info[0]); /* And advance past the AT_NULL entry. */ ei_index += 2; sp = STACK_ADD(p, ei_index); items = (argc + 1) + (envc + 1); items += 1; /* ELF interpreters only put argc on the stack */ bprm->p = STACK_ROUND(sp, items); /* Point sp at the lowest address on the stack */#ifdef CONFIG_STACK_GROWSUP sp = (elf_addr_t __user *)bprm->p - items - ei_index; bprm->exec = (unsigned long) sp; /* XXX: PARISC HACK */#else sp = (elf_addr_t __user *)bprm->p;#endif /* Now, let's put argc (and argv, envp if appropriate) on the stack */ if (__put_user(argc, sp++)) return -EFAULT; argv = sp; envp = argv + argc + 1; /* Populate argv and envp */ p = current->mm->arg_end = current->mm->arg_start; while (argc-- > 0) { size_t len; __put_user((elf_addr_t)p, argv++); len = strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PAGES); if (!len || len > PAGE_SIZE*MAX_ARG_PAGES) return 0; p += len; } if (__put_user(0, argv)) return -EFAULT; current->mm->arg_end = current->mm->env_start = p; while (envc-- > 0) { size_t len; __put_user((elf_addr_t)p, envp++); len = strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PAGES); if (!len || len > PAGE_SIZE*MAX_ARG_PAGES) return 0; p += len; } if (__put_user(0, envp)) return -EFAULT; current->mm->env_end = p; /* Put the elf_info on the stack in the right place. */ sp = (elf_addr_t __user *)envp + 1; if (copy_to_user(sp, elf_info, ei_index * sizeof(elf_addr_t))) return -EFAULT; return 0;} /* end create_elf_tables *//* * search_ntdll */static char *search_ntdll(struct linux_binprm *bprm){ unsigned long pos = bprm->p; unsigned long kaddr; char *buf, *bp = NULL; char *filename = NULL; struct page *page; int len; int offset = 0; int i = MAX_ARG_PAGES; buf = kmalloc(PAGE_SIZE, GFP_KERNEL); while (pos < MAX_ARG_PAGES * PAGE_SIZE - sizeof(void *)) { i = pos >> PAGE_SHIFT; offset = pos & (PAGE_SIZE - 1); page = bprm->page[i]; if (!page) break; kaddr = (unsigned long)kmap(page); len = strnlen((char *)kaddr + offset, PAGE_SIZE - offset); if (len == PAGE_SIZE - offset) { memcpy(buf, (char *)kaddr + offset, PAGE_SIZE - offset); bp = buf + PAGE_SIZE - offset; pos += len; } else { if (bp) memcpy(bp, (char *)kaddr + offset, len + 1); else bp = (char *)kaddr + offset; if (!strncmp(bp, "WINE_DLL_PATH", strlen("WINE_DLL_PATH"))) { char *p = &bp[strlen("WINE_DLL_PATH")]; if (*p == '=') { filename = kmalloc(strlen(++p) + sizeof("/ntdll.dll.so"), GFP_KERNEL); strcpy(filename, p); strcat(filename + strlen(p), "/ntdll.dll.so"); } } bp = NULL; pos += len + 1; } kunmap(page); if (filename) break; } kfree(buf); return filename ? : kstrdup("/usr/local/lib/wine/ntdll.dll.so", GFP_KERNEL);} /* end search_ntdll */#else /* NTDLL_SO *//* * create_pe_tables */static intcreate_pe_tables(struct linux_binprm *bprm, struct win32_section *ws, unsigned long load_addr, unsigned long interp_load_addr){ return 0;} /* end create_pe_tables *//* * load_pe_interp */static unsigned long load_pe_interp(void *interp_hdr, struct file *interpreter, unsigned long *interp_load_addr){ return 0;} /* end load_pe_interp */#endif/* * pe_map */static unsigned long pe_map(struct win32_section *ws, unsigned long base_addr){ int ret = -ENOSYS; unsigned long addr = base_addr; if (!ws) return -EINVAL; if (ws->ws_mmap) { /* grab the process's memory mapping semaphore */ down_write(¤t->mm->mmap_sem); /* do the mmap operation */ addr = base_addr; ret = ws->ws_mmap(current, ws, &addr, 0, 0, 0); /* release the process's memory mapping semaphore */ up_write(¤t->mm->mmap_sem); } return ret;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -