1528 lines · 34.6 KB · C
RawDownload
/* *  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/config.h>#include <linux/slab.h>#include <linux/file.h>#include <linux/mman.h>#include <linux/a.out.h>#include <linux/stat.h>#include <linux/fcntl.h>#include <linux/smp_lock.h>#include <linux/init.h>#include <linux/pagemap.h>#include <linux/highmem.h>#include <linux/spinlock.h>#include <linux/key.h>#include <linux/personality.h>#include <linux/binfmts.h>#include <linux/swap.h>#include <linux/utsname.h>#include <linux/module.h>#include <linux/namei.h>#include <linux/proc_fs.h>#include <linux/ptrace.h>#include <linux/mount.h>#include <linux/security.h>#include <linux/syscalls.h>#include <linux/rmap.h>#include <linux/acct.h> #include <asm/uaccess.h>#include <asm/mmu_context.h> #ifdef CONFIG_KMOD#include <linux/kmod.h>#endif int core_uses_pid;char core_pattern[65] = "core";int suid_dumpable = 0; EXPORT_SYMBOL(suid_dumpable);/* The maximal length of core_pattern is also specified in sysctl.c */ static struct linux_binfmt *formats;static DEFINE_RWLOCK(binfmt_lock); int register_binfmt(struct linux_binfmt * fmt){	struct linux_binfmt ** tmp = &formats; 	if (!fmt)		return -EINVAL;	if (fmt->next)		return -EBUSY;	write_lock(&binfmt_lock);	while (*tmp) {		if (fmt == *tmp) {			write_unlock(&binfmt_lock);			return -EBUSY;		}		tmp = &(*tmp)->next;	}	fmt->next = formats;	formats = fmt;	write_unlock(&binfmt_lock);	return 0;	} EXPORT_SYMBOL(register_binfmt); int unregister_binfmt(struct linux_binfmt * fmt){	struct linux_binfmt ** tmp = &formats; 	write_lock(&binfmt_lock);	while (*tmp) {		if (fmt == *tmp) {			*tmp = fmt->next;			write_unlock(&binfmt_lock);			return 0;		}		tmp = &(*tmp)->next;	}	write_unlock(&binfmt_lock);	return -EINVAL;} EXPORT_SYMBOL(unregister_binfmt); static inline void put_binfmt(struct linux_binfmt * fmt){	module_put(fmt->module);} /* * 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 long sys_uselib(const char __user * library){	struct file * file;	struct nameidata nd;	int error; 	nd.intent.open.flags = FMODE_READ;	error = __user_walk(library, LOOKUP_FOLLOW|LOOKUP_OPEN, &nd);	if (error)		goto out; 	error = -EINVAL;	if (!S_ISREG(nd.dentry->d_inode->i_mode))		goto exit; 	error = permission(nd.dentry->d_inode, MAY_READ | MAY_EXEC, &nd);	if (error)		goto exit; 	file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);	error = PTR_ERR(file);	if (IS_ERR(file))		goto out; 	error = -ENOEXEC;	if(file->f_op) {		struct linux_binfmt * fmt; 		read_lock(&binfmt_lock);		for (fmt = formats ; fmt ; fmt = fmt->next) {			if (!fmt->load_shlib)				continue;			if (!try_module_get(fmt->module))				continue;			read_unlock(&binfmt_lock);			error = fmt->load_shlib(file);			read_lock(&binfmt_lock);			put_binfmt(fmt);			if (error != -ENOEXEC)				break;		}		read_unlock(&binfmt_lock);	}	fput(file);out:  	return error;exit:	path_release(&nd);	goto out;} /* * count() counts the number of strings in array ARGV. */static int count(char __user * __user * argv, int max){	int i = 0; 	if (argv != NULL) {		for (;;) {			char __user * p; 			if (get_user(p, argv))				return -EFAULT;			if (!p)				break;			argv++;			if(++i > max)				return -E2BIG;			cond_resched();		}	}	return i;} /* * 'copy_strings()' copies argument/environment 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. */static int copy_strings(int argc, char __user * __user * argv,			struct linux_binprm *bprm){	struct page *kmapped_page = NULL;	char *kaddr = NULL;	int ret; 	while (argc-- > 0) {		char __user *str;		int len;		unsigned long pos; 		if (get_user(str, argv+argc) ||				!(len = strnlen_user(str, bprm->p))) {			ret = -EFAULT;			goto out;		} 		if (bprm->p < len)  {			ret = -E2BIG;			goto out;		} 		bprm->p -= len;		/* XXX: add architecture specific overflow check here. */		pos = bprm->p; 		while (len > 0) {			int i, new, err;			int offset, bytes_to_copy;			struct page *page; 			offset = pos % PAGE_SIZE;			i = pos/PAGE_SIZE;			page = bprm->page[i];			new = 0;			if (!page) {				page = alloc_page(GFP_HIGHUSER);				bprm->page[i] = page;				if (!page) {					ret = -ENOMEM;					goto out;				}				new = 1;			} 			if (page != kmapped_page) {				if (kmapped_page)					kunmap(kmapped_page);				kmapped_page = page;				kaddr = kmap(kmapped_page);			}			if (new && offset)				memset(kaddr, 0, offset);			bytes_to_copy = PAGE_SIZE - offset;			if (bytes_to_copy > len) {				bytes_to_copy = len;				if (new)					memset(kaddr+offset+len, 0,						PAGE_SIZE-offset-len);			}			err = copy_from_user(kaddr+offset, str, bytes_to_copy);			if (err) {				ret = -EFAULT;				goto out;			} 			pos += bytes_to_copy;			str += bytes_to_copy;			len -= bytes_to_copy;		}	}	ret = 0;out:	if (kmapped_page)		kunmap(kmapped_page);	return ret;} /* * Like copy_strings, but get argv and its values from kernel memory. */int copy_strings_kernel(int argc,char ** argv, struct linux_binprm *bprm){	int r;	mm_segment_t oldfs = get_fs();	set_fs(KERNEL_DS);	r = copy_strings(argc, (char __user * __user *)argv, bprm);	set_fs(oldfs);	return r;} EXPORT_SYMBOL(copy_strings_kernel); #ifdef CONFIG_MMU/* * This routine is used to map in a page into an address space: needed by * execve() for the initial stack and environment pages. * * vma->vm_mm->mmap_sem is held for writing. */void install_arg_page(struct vm_area_struct *vma,			struct page *page, unsigned long address){	struct mm_struct *mm = vma->vm_mm;	pgd_t * pgd;	pud_t * pud;	pmd_t * pmd;	pte_t * pte; 	if (unlikely(anon_vma_prepare(vma)))		goto out_sig; 	flush_dcache_page(page);	pgd = pgd_offset(mm, address); 	spin_lock(&mm->page_table_lock);	pud = pud_alloc(mm, pgd, address);	if (!pud)		goto out;	pmd = pmd_alloc(mm, pud, address);	if (!pmd)		goto out;	pte = pte_alloc_map(mm, pmd, address);	if (!pte)		goto out;	if (!pte_none(*pte)) {		pte_unmap(pte);		goto out;	}	inc_mm_counter(mm, rss);	lru_cache_add_active(page);	set_pte_at(mm, address, pte, pte_mkdirty(pte_mkwrite(mk_pte(					page, vma->vm_page_prot))));	page_add_anon_rmap(page, vma, address);	pte_unmap(pte);	spin_unlock(&mm->page_table_lock); 	/* no need for flush_tlb */	return;out:	spin_unlock(&mm->page_table_lock);out_sig:	__free_page(page);	force_sig(SIGKILL, current);} #define EXTRA_STACK_VM_PAGES	20	/* random */ int setup_arg_pages(struct linux_binprm *bprm,		    unsigned long stack_top,		    int executable_stack){	unsigned long stack_base;	struct vm_area_struct *mpnt;	struct mm_struct *mm = current->mm;	int i, ret;	long arg_size; #ifdef CONFIG_STACK_GROWSUP	/* Move the argument and environment strings to the bottom of the	 * stack space.	 */	int offset, j;	char *to, *from; 	/* Start by shifting all the pages down */	i = 0;	for (j = 0; j < MAX_ARG_PAGES; j++) {		struct page *page = bprm->page[j];		if (!page)			continue;		bprm->page[i++] = page;	} 	/* Now move them within their pages */	offset = bprm->p % PAGE_SIZE;	to = kmap(bprm->page[0]);	for (j = 1; j < i; j++) {		memmove(to, to + offset, PAGE_SIZE - offset);		from = kmap(bprm->page[j]);		memcpy(to + PAGE_SIZE - offset, from, offset);		kunmap(bprm->page[j - 1]);		to = from;	}	memmove(to, to + offset, PAGE_SIZE - offset);	kunmap(bprm->page[j - 1]); 	/* Limit stack size to 1GB */	stack_base = current->signal->rlim[RLIMIT_STACK].rlim_max;	if (stack_base > (1 << 30))		stack_base = 1 << 30;	stack_base = PAGE_ALIGN(stack_top - stack_base); 	/* Adjust bprm->p to point to the end of the strings. */	bprm->p = stack_base + PAGE_SIZE * i - offset; 	mm->arg_start = stack_base;	arg_size = i << PAGE_SHIFT; 	/* zero pages that were copied above */	while (i < MAX_ARG_PAGES)		bprm->page[i++] = NULL;#else	stack_base = arch_align_stack(stack_top - MAX_ARG_PAGES*PAGE_SIZE);	stack_base = PAGE_ALIGN(stack_base);	bprm->p += stack_base;	mm->arg_start = bprm->p;	arg_size = stack_top - (PAGE_MASK & (unsigned long) mm->arg_start);#endif 	arg_size += EXTRA_STACK_VM_PAGES * PAGE_SIZE; 	if (bprm->loader)		bprm->loader += stack_base;	bprm->exec += stack_base; 	mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);	if (!mpnt)		return -ENOMEM; 	if (security_vm_enough_memory(arg_size >> PAGE_SHIFT)) {		kmem_cache_free(vm_area_cachep, mpnt);		return -ENOMEM;	} 	memset(mpnt, 0, sizeof(*mpnt)); 	down_write(&mm->mmap_sem);	{		mpnt->vm_mm = mm;#ifdef CONFIG_STACK_GROWSUP		mpnt->vm_start = stack_base;		mpnt->vm_end = stack_base + arg_size;#else		mpnt->vm_end = stack_top;		mpnt->vm_start = mpnt->vm_end - arg_size;#endif		/* Adjust stack execute permissions; explicitly enable		 * for EXSTACK_ENABLE_X, disable for EXSTACK_DISABLE_X		 * and leave alone (arch default) otherwise. */		if (unlikely(executable_stack == EXSTACK_ENABLE_X))			mpnt->vm_flags = VM_STACK_FLAGS |  VM_EXEC;		else if (executable_stack == EXSTACK_DISABLE_X)			mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC;		else			mpnt->vm_flags = VM_STACK_FLAGS;		mpnt->vm_flags |= mm->def_flags;		mpnt->vm_page_prot = protection_map[mpnt->vm_flags & 0x7];		if ((ret = insert_vm_struct(mm, mpnt))) {			up_write(&mm->mmap_sem);			kmem_cache_free(vm_area_cachep, mpnt);			return ret;		}		mm->stack_vm = mm->total_vm = vma_pages(mpnt);	} 	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {		struct page *page = bprm->page[i];		if (page) {			bprm->page[i] = NULL;			install_arg_page(mpnt, page, stack_base);		}		stack_base += PAGE_SIZE;	}	up_write(&mm->mmap_sem);		return 0;} EXPORT_SYMBOL(setup_arg_pages); #define free_arg_pages(bprm) do { } while (0) #else static inline void free_arg_pages(struct linux_binprm *bprm){	int i; 	for (i = 0; i < MAX_ARG_PAGES; i++) {		if (bprm->page[i])			__free_page(bprm->page[i]);		bprm->page[i] = NULL;	}} #endif /* CONFIG_MMU */ struct file *open_exec(const char *name){	struct nameidata nd;	int err;	struct file *file; 	nd.intent.open.flags = FMODE_READ;	err = path_lookup(name, LOOKUP_FOLLOW|LOOKUP_OPEN, &nd);	file = ERR_PTR(err);

Lines 1–500 of 1528.