1533 lines · 35.1 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 <linux/cn_proc.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; 	error = __user_path_lookup_open(library, LOOKUP_FOLLOW, &nd, FMODE_READ|FMODE_EXEC);	if (error)		goto out; 	error = -EINVAL;	if (!S_ISREG(nd.dentry->d_inode->i_mode))		goto exit; 	error = vfs_permission(&nd, MAY_READ | MAY_EXEC);	if (error)		goto exit; 	file = nameidata_to_filp(&nd, 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:	release_open_intent(&nd);	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;	pte_t * pte;	spinlock_t *ptl; 	if (unlikely(anon_vma_prepare(vma)))		goto out; 	flush_dcache_page(page);	pte = get_locked_pte(mm, address, &ptl);	if (!pte)		goto out;	if (!pte_none(*pte)) {		pte_unmap_unlock(pte, ptl);		goto out;	}	inc_mm_counter(mm, anon_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_new_anon_rmap(page, vma, address);	pte_unmap_unlock(pte, ptl); 	/* no need for flush_tlb */	return;out:	__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; 	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; 	err = path_lookup_open(AT_FDCWD, name, LOOKUP_FOLLOW, &nd, FMODE_READ|FMODE_EXEC);	file = ERR_PTR(err); 	if (!err) {		struct inode *inode = nd.dentry->d_inode;		file = ERR_PTR(-EACCES);		if (!(nd.mnt->mnt_flags & MNT_NOEXEC) &&		    S_ISREG(inode->i_mode)) {			int err = vfs_permission(&nd, MAY_EXEC);			if (!err && !(inode->i_mode & 0111))				err = -EACCES;			file = ERR_PTR(err);			if (!err) {				file = nameidata_to_filp(&nd, O_RDONLY);				if (!IS_ERR(file)) {					err = deny_write_access(file);					if (err) {						fput(file);						file = ERR_PTR(err);					}				}

Lines 1–500 of 1533.