📄 exec.c
字号:
/* * linux/fs/exec.c * * Copyright (C) 1991, 1992 Linus Torvalds *//* * #!-checking implemented by tytso. *//* * Demand-loading implemented 01.12.91 - no need to read anything but * the header into memory. The inode of the executable is put into * "current->executable", and page faults do the actual loading. Clean. * * Once more I can proudly say that linux stood up to being changed: it * was less than 2 hours work to get demand-loading completely implemented. * * Demand loading changed July 1993 by Eric Youngdale. Use mmap instead, * current->executable is only used by the procfs. This allows a dispatch * table to check for several different types of binary formats. We keep * trying until we recognize the file or we run out of supported binary * formats. */#include <linux/fs.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/mman.h>#include <linux/a.out.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/string.h>#include <linux/stat.h>#include <linux/fcntl.h>#include <linux/ptrace.h>#include <linux/user.h>#include <linux/malloc.h>#include <linux/binfmts.h>#include <linux/personality.h>#include <asm/system.h>#include <asm/segment.h>#include <asm/pgtable.h>#include <linux/config.h>#ifdef CONFIG_KERNELD#include <linux/kerneld.h>#endifasmlinkage int sys_exit(int exit_code);asmlinkage int sys_brk(unsigned long);/* * Here are the actual binaries that will be accepted: * add more with "register_binfmt()" if using modules... * * These are defined again for the 'real' modules if you are using a * module definition for these routines. */static struct linux_binfmt *formats = (struct linux_binfmt *) NULL;void binfmt_setup(void){#ifdef CONFIG_BINFMT_ELF init_elf_binfmt();#endif#ifdef CONFIG_BINFMT_AOUT init_aout_binfmt();#endif#ifdef CONFIG_BINFMT_JAVA init_java_binfmt();#endif /* This cannot be configured out of the kernel */ init_script_binfmt();}int register_binfmt(struct linux_binfmt * fmt){ struct linux_binfmt ** tmp = &formats; if (!fmt) return -EINVAL; if (fmt->next) return -EBUSY; while (*tmp) { if (fmt == *tmp) return -EBUSY; tmp = &(*tmp)->next; } fmt->next = formats; formats = fmt; return 0; }#ifdef CONFIG_MODULESint unregister_binfmt(struct linux_binfmt * fmt){ struct linux_binfmt ** tmp = &formats; while (*tmp) { if (fmt == *tmp) { *tmp = fmt->next; return 0; } tmp = &(*tmp)->next; } return -EINVAL;}#endif /* CONFIG_MODULES */int open_inode(struct inode * inode, int mode){ int fd; if (!inode->i_op || !inode->i_op->default_file_ops) return -EINVAL; fd = get_unused_fd(); if (fd >= 0) { struct file * f = get_empty_filp(); if (!f) { put_unused_fd(fd); return -ENFILE; } f->f_flags = mode; f->f_mode = (mode+1) & O_ACCMODE; f->f_inode = inode; f->f_pos = 0; f->f_reada = 0; f->f_op = inode->i_op->default_file_ops; if (f->f_op->open) { int error = f->f_op->open(inode,f); if (error) { f->f_count--; put_unused_fd(fd); return error; } } current->files->fd[fd] = f; inode->i_count++; } return fd;}/* * Note that a shared library must be both readable and executable due to * security reasons. * * Also note that we take the address to load from from the file itself. */asmlinkage int sys_uselib(const char * library){ int fd, retval; struct file * file; struct linux_binfmt * fmt; fd = sys_open(library, 0, 0); if (fd < 0) return fd; file = current->files->fd[fd]; retval = -ENOEXEC; if (file && file->f_inode && file->f_op && file->f_op->read) { for (fmt = formats ; fmt ; fmt = fmt->next) { int (*fn)(int) = fmt->load_shlib; if (!fn) continue; retval = fn(fd); if (retval != -ENOEXEC) break; } } sys_close(fd); return retval;}/* * count() counts the number of arguments/envelopes * * We also do some limited EFAULT checking: this isn't complete, but * it does cover most cases. I'll have to do this correctly some day.. */static int count(char ** argv){ int error, i = 0; char ** tmp, *p; if ((tmp = argv) != NULL) { error = verify_area(VERIFY_READ, tmp, sizeof(char *)); if (error) return error; while ((p = get_user(tmp++)) != NULL) { i++; error = verify_area(VERIFY_READ, p, 1); if (error) return error; } } return i;}/* * 'copy_string()' copies argument/envelope strings from user * memory to free pages in kernel mem. These are in a format ready * to be put directly into the top of new user memory. * * Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies * whether the string and the string array are from user or kernel segments: * * from_kmem argv * argv ** * 0 user space user space * 1 kernel space user space * 2 kernel space kernel space * * We do this by playing games with the fs segment register. Since it * is expensive to load a segment register, we try to avoid calling * set_fs() unless we absolutely have to. */unsigned long copy_strings(int argc,char ** argv,unsigned long *page, unsigned long p, int from_kmem){ char *tmp, *tmp1, *pag = NULL; int len, offset = 0; unsigned long old_fs, new_fs; if (!p) return 0; /* bullet-proofing */ new_fs = get_ds(); old_fs = get_fs(); if (from_kmem==2) set_fs(new_fs); while (argc-- > 0) { if (from_kmem == 1) set_fs(new_fs); if (!(tmp1 = tmp = get_user(argv+argc))) panic("VFS: argc is wrong"); if (from_kmem == 1) set_fs(old_fs); while (get_user(tmp++)); len = tmp - tmp1; if (p < len) { /* this shouldn't happen - 128kB */ set_fs(old_fs); return 0; } while (len) { --p; --tmp; --len; if (--offset < 0) { offset = p % PAGE_SIZE; if (from_kmem==2) set_fs(old_fs); if (!(pag = (char *) page[p/PAGE_SIZE]) && !(pag = (char *) page[p/PAGE_SIZE] = (unsigned long *) get_free_page(GFP_USER))) return 0; if (from_kmem==2) set_fs(new_fs); } if (len == 0 || offset == 0) *(pag + offset) = get_user(tmp); else { int bytes_to_copy = (len > offset) ? offset : len; tmp -= bytes_to_copy; p -= bytes_to_copy; offset -= bytes_to_copy; len -= bytes_to_copy; memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1); } } } if (from_kmem==2) set_fs(old_fs); return p;}unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm){ unsigned long stack_base; struct vm_area_struct *mpnt; int i; stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; p += stack_base; if (bprm->loader) bprm->loader += stack_base; bprm->exec += stack_base; mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL); if (mpnt) { mpnt->vm_mm = current->mm; mpnt->vm_start = PAGE_MASK & (unsigned long) p; mpnt->vm_end = STACK_TOP; mpnt->vm_page_prot = PAGE_COPY; mpnt->vm_flags = VM_STACK_FLAGS; mpnt->vm_ops = NULL; mpnt->vm_offset = 0; mpnt->vm_inode = NULL; mpnt->vm_pte = 0; insert_vm_struct(current->mm, mpnt); current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { if (bprm->page[i]) { current->mm->rss++; put_dirty_page(current,bprm->page[i],stack_base); } stack_base += PAGE_SIZE; } return p;}/* * Read in the complete executable. This is used for "-N" files * that aren't on a block boundary, and for files on filesystems * without bmap support. */int read_exec(struct inode *inode, unsigned long offset, char * addr, unsigned long count, int to_kmem){ struct file file; int result = -ENOEXEC; if (!inode->i_op || !inode->i_op->default_file_ops) goto end_readexec; file.f_mode = 1; file.f_flags = 0; file.f_count = 1; file.f_inode = inode; file.f_pos = 0; file.f_reada = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -