⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exec.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  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/personality.h>#define __NO_VERSION__#include <linux/module.h>#include <asm/uaccess.h>#include <asm/pgalloc.h>#include <asm/mmu_context.h>#ifdef CONFIG_KMOD#include <linux/kmod.h>#endifint core_uses_pid;static struct linux_binfmt *formats;static rwlock_t binfmt_lock = RW_LOCK_UNLOCKED;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;	}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;}static inline void put_binfmt(struct linux_binfmt * fmt){	if (fmt->module)		__MOD_DEC_USE_COUNT(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 * library){	struct file * file;	struct nameidata nd;	int error;	error = user_path_walk(library, &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);	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 && file->f_op->read) {		struct linux_binfmt * fmt;		read_lock(&binfmt_lock);		for (fmt = formats ; fmt ; fmt = fmt->next) {			if (!fmt->load_shlib)				continue;			if (!try_inc_mod_count(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 arguments/envelopes */static int count(char ** argv, int max){	int i = 0;	if (argv != NULL) {		for (;;) {			char * p;			if (get_user(p, argv))				return -EFAULT;			if (!p)				break;			argv++;			if(++i > max)				return -E2BIG;		}	}	return i;}/* * 'copy_strings()' 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. */int copy_strings(int argc,char ** argv, struct linux_binprm *bprm) {	while (argc-- > 0) {		char *str;		int len;		unsigned long pos;		if (get_user(str, argv+argc) || !(len = strnlen_user(str, bprm->p)))			return -EFAULT;		if (bprm->p < len) 			return -E2BIG; 		bprm->p -= len;		/* XXX: add architecture specific overflow check here. */ 		pos = bprm->p;		while (len > 0) {			char *kaddr;			int i, new, err;			struct page *page;			int offset, bytes_to_copy;			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)					return -ENOMEM;				new = 1;			}			kaddr = kmap(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);			kunmap(page);			if (err)				return -EFAULT; 			pos += bytes_to_copy;			str += bytes_to_copy;			len -= bytes_to_copy;		}	}	return 0;}/* * 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, argv, bprm);	set_fs(oldfs);	return r; }/* * This routine is used to map in a page into an address space: needed by * execve() for the initial stack and environment pages. * * tsk->mmap_sem is held for writing. */void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address){	pgd_t * pgd;	pmd_t * pmd;	pte_t * pte;	if (page_count(page) != 1)		printk(KERN_ERR "mem_map disagrees with %p at %08lx\n", page, address);	pgd = pgd_offset(tsk->mm, address);	spin_lock(&tsk->mm->page_table_lock);	pmd = pmd_alloc(tsk->mm, pgd, address);	if (!pmd)		goto out;	pte = pte_alloc(tsk->mm, pmd, address);	if (!pte)		goto out;	if (!pte_none(*pte))		goto out;	lru_cache_add(page);	flush_dcache_page(page);	flush_page_to_ram(page);	set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY))));	tsk->mm->rss++;	spin_unlock(&tsk->mm->page_table_lock);	/* no need for flush_tlb */	memc_update_addr(tsk->mm, *pte, address);	return;out:	spin_unlock(&tsk->mm->page_table_lock);	__free_page(page);	force_sig(SIGKILL, tsk);	return;}int setup_arg_pages(struct linux_binprm *bprm){	unsigned long stack_base;	struct vm_area_struct *mpnt;	int i;	stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;	bprm->p += stack_base;	if (bprm->loader)		bprm->loader += stack_base;	bprm->exec += stack_base;	mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);	if (!mpnt) 		return -ENOMEM; 		down_write(&current->mm->mmap_sem);	{		mpnt->vm_mm = current->mm;		mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;		mpnt->vm_end = STACK_TOP;		mpnt->vm_page_prot = PAGE_COPY;		mpnt->vm_flags = VM_STACK_FLAGS;		mpnt->vm_ops = NULL;		mpnt->vm_pgoff = 0;		mpnt->vm_file = NULL;		mpnt->vm_private_data = (void *) 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++) {		struct page *page = bprm->page[i];		if (page) {			bprm->page[i] = NULL;			put_dirty_page(current,page,stack_base);		}		stack_base += PAGE_SIZE;	}	up_write(&current->mm->mmap_sem);		return 0;}struct file *open_exec(const char *name){	struct nameidata nd;	struct inode *inode;	struct file *file;	int err = 0;	if (path_init(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))		err = path_walk(name, &nd);	file = ERR_PTR(err);	if (!err) {		inode = nd.dentry->d_inode;		file = ERR_PTR(-EACCES);		if (!(nd.mnt->mnt_flags & MNT_NOEXEC) &&		    S_ISREG(inode->i_mode)) {			int err = permission(inode, MAY_EXEC);			if (!err && !(inode->i_mode & 0111))				err = -EACCES;			file = ERR_PTR(err);			if (!err) {				file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);				if (!IS_ERR(file)) {					err = deny_write_access(file);					if (err) {						fput(file);						file = ERR_PTR(err);					}				}out:				return file;			}		}		path_release(&nd);	}	goto out;}int kernel_read(struct file *file, unsigned long offset,	char * addr, unsigned long count){	mm_segment_t old_fs;	loff_t pos = offset;	int result = -ENOSYS;	if (!file->f_op->read)		goto fail;	old_fs = get_fs();	set_fs(get_ds());	result = file->f_op->read(file, addr, count, &pos);	set_fs(old_fs);fail:	return result;}static int exec_mmap(void){	struct mm_struct * mm, * old_mm;	old_mm = current->mm;	if (old_mm && atomic_read(&old_mm->mm_users) == 1) {		mm_release();		exit_mmap(old_mm);		return 0;	}	mm = mm_alloc();	if (mm) {		struct mm_struct *active_mm;		if (init_new_context(current, mm)) {			mmdrop(mm);			return -ENOMEM;		}		/* Add it to the list of mm's */		spin_lock(&mmlist_lock);		list_add(&mm->mmlist, &init_mm.mmlist);		mmlist_nr++;		spin_unlock(&mmlist_lock);		task_lock(current);		active_mm = current->active_mm;		current->mm = mm;		current->active_mm = mm;		task_unlock(current);		activate_mm(active_mm, mm);		mm_release();		if (old_mm) {			if (active_mm != old_mm) BUG();			mmput(old_mm);			return 0;		}		mmdrop(active_mm);		return 0;	}	return -ENOMEM;}/* * This function makes sure the current process has its own signal table, * so that flush_signal_handlers can later reset the handlers without * disturbing other processes.  (Other processes might share the signal * table via the CLONE_SIGNAL option to clone().) */ static inline int make_private_signals(void){	struct signal_struct * newsig;	if (atomic_read(&current->sig->count) <= 1)		return 0;	newsig = kmem_cache_alloc(sigact_cachep, GFP_KERNEL);	if (newsig == NULL)		return -ENOMEM;	spin_lock_init(&newsig->siglock);	atomic_set(&newsig->count, 1);	memcpy(newsig->action, current->sig->action, sizeof(newsig->action));	spin_lock_irq(&current->sigmask_lock);	current->sig = newsig;	spin_unlock_irq(&current->sigmask_lock);	return 0;}	/* * If make_private_signals() made a copy of the signal table, decrement the * refcount of the original table, and free it if necessary. * We don't do that in make_private_signals() so that we can back off * in flush_old_exec() if an error occurs after calling make_private_signals(). */static inline void release_old_signals(struct signal_struct * oldsig){	if (current->sig == oldsig)		return;	if (atomic_dec_and_test(&oldsig->count))		kmem_cache_free(sigact_cachep, oldsig);}/* * These functions flushes out all traces of the currently running executable * so that a new one can be started */static inline void flush_old_files(struct files_struct * files){	long j = -1;	write_lock(&files->file_lock);	for (;;) {		unsigned long set, i;		j++;		i = j * __NFDBITS;		if (i >= files->max_fds || i >= files->max_fdset)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -