Skip to content
Snippets Groups Projects
exec.c 45.2 KiB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
/*
 *  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/slab.h>
#include <linux/file.h>
Al Viro's avatar
Al Viro committed
#include <linux/fdtable.h>
Hugh Dickins's avatar
Hugh Dickins committed
#include <linux/mm.h>
Linus Torvalds's avatar
Linus Torvalds committed
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/smp_lock.h>
Hugh Dickins's avatar
Hugh Dickins committed
#include <linux/swap.h>
Linus Torvalds's avatar
Linus Torvalds committed
#include <linux/init.h>
#include <linux/pagemap.h>
#include <linux/perf_event.h>
Linus Torvalds's avatar
Linus Torvalds committed
#include <linux/highmem.h>
#include <linux/spinlock.h>
#include <linux/key.h>
#include <linux/personality.h>
#include <linux/binfmts.h>
#include <linux/utsname.h>
#include <linux/pid_namespace.h>
Linus Torvalds's avatar
Linus Torvalds committed
#include <linux/module.h>
#include <linux/namei.h>
#include <linux/proc_fs.h>
#include <linux/mount.h>
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/tsacct_kern.h>
#include <linux/cn_proc.h>
Al Viro's avatar
Al Viro committed
#include <linux/audit.h>
Roland McGrath's avatar
Roland McGrath committed
#include <linux/tracehook.h>
#include <linux/kmod.h>
#include <linux/fsnotify.h>
#include <linux/fs_struct.h>
Linus Torvalds's avatar
Linus Torvalds committed

#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/tlb.h>
Linus Torvalds's avatar
Linus Torvalds committed

int core_uses_pid;
char core_pattern[CORENAME_MAX_SIZE] = "core";
Alan Cox's avatar
Alan Cox committed
int suid_dumpable = 0;

Linus Torvalds's avatar
Linus Torvalds committed
/* The maximal length of core_pattern is also specified in sysctl.c */

static LIST_HEAD(formats);
Linus Torvalds's avatar
Linus Torvalds committed
static DEFINE_RWLOCK(binfmt_lock);

Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
int __register_binfmt(struct linux_binfmt * fmt, int insert)
Linus Torvalds's avatar
Linus Torvalds committed
{
	if (!fmt)
		return -EINVAL;
	write_lock(&binfmt_lock);
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
	insert ? list_add(&fmt->lh, &formats) :
		 list_add_tail(&fmt->lh, &formats);
Linus Torvalds's avatar
Linus Torvalds committed
	write_unlock(&binfmt_lock);
	return 0;	
}

Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
EXPORT_SYMBOL(__register_binfmt);
Linus Torvalds's avatar
Linus Torvalds committed

void unregister_binfmt(struct linux_binfmt * fmt)
Linus Torvalds's avatar
Linus Torvalds committed
{
	write_lock(&binfmt_lock);
	list_del(&fmt->lh);
Linus Torvalds's avatar
Linus Torvalds committed
	write_unlock(&binfmt_lock);
}

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.
 */
SYSCALL_DEFINE1(uselib, const char __user *, library)
Linus Torvalds's avatar
Linus Torvalds committed
{
	struct file *file;
	char *tmp = getname(library);
	int error = PTR_ERR(tmp);

	if (IS_ERR(tmp))
		goto out;

	file = do_filp_open(AT_FDCWD, tmp,
				O_LARGEFILE | O_RDONLY | FMODE_EXEC, 0,
				MAY_READ | MAY_EXEC | MAY_OPEN);
	putname(tmp);
	error = PTR_ERR(file);
	if (IS_ERR(file))
Linus Torvalds's avatar
Linus Torvalds committed
		goto out;

	error = -EINVAL;
	if (!S_ISREG(file->f_path.dentry->d_inode->i_mode))
Linus Torvalds's avatar
Linus Torvalds committed
		goto exit;

	if (file->f_path.mnt->mnt_flags & MNT_NOEXEC)
Linus Torvalds's avatar
Linus Torvalds committed
		goto exit;

	fsnotify_open(file->f_path.dentry);

Linus Torvalds's avatar
Linus Torvalds committed
	error = -ENOEXEC;
	if(file->f_op) {
		struct linux_binfmt * fmt;

		read_lock(&binfmt_lock);
		list_for_each_entry(fmt, &formats, lh) {
Linus Torvalds's avatar
Linus Torvalds committed
			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);
	}
Linus Torvalds's avatar
Linus Torvalds committed
	fput(file);
out:
  	return error;
}

#ifdef CONFIG_MMU

static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
		int write)
{
	struct page *page;
	int ret;

#ifdef CONFIG_STACK_GROWSUP
	if (write) {
		ret = expand_stack_downwards(bprm->vma, pos);
		if (ret < 0)
			return NULL;
	}
#endif
	ret = get_user_pages(current, bprm->mm, pos,
			1, write, 1, &page, NULL);
	if (ret <= 0)
		return NULL;

	if (write) {
		unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start;
		struct rlimit *rlim;

		/*
		 * We've historically supported up to 32 pages (ARG_MAX)
		 * of argument strings even with small stacks
		 */
		if (size <= ARG_MAX)
			return page;

		/*
		 * Limit to 1/4-th the stack size for the argv+env strings.
		 * This ensures that:
		 *  - the remaining binfmt code will not run out of stack space,
		 *  - the program will have a reasonable amount of stack left
		 *    to work from.
		 */
		rlim = current->signal->rlim;
		if (size > rlim[RLIMIT_STACK].rlim_cur / 4) {
			put_page(page);
			return NULL;
Loading
Loading full blame...