diff options
Diffstat (limited to 'fs/exec.c')
| -rw-r--r-- | fs/exec.c | 111 | 
1 files changed, 41 insertions, 70 deletions
diff --git a/fs/exec.c b/fs/exec.c index 052a961e41a..895823d0149 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -69,17 +69,18 @@ int suid_dumpable = 0;  static LIST_HEAD(formats);  static DEFINE_RWLOCK(binfmt_lock); -int register_binfmt(struct linux_binfmt * fmt) +int __register_binfmt(struct linux_binfmt * fmt, int insert)  {  	if (!fmt)  		return -EINVAL;  	write_lock(&binfmt_lock); -	list_add(&fmt->lh, &formats); +	insert ? list_add(&fmt->lh, &formats) : +		 list_add_tail(&fmt->lh, &formats);  	write_unlock(&binfmt_lock);  	return 0;	  } -EXPORT_SYMBOL(register_binfmt); +EXPORT_SYMBOL(__register_binfmt);  void unregister_binfmt(struct linux_binfmt * fmt)  { @@ -104,40 +105,28 @@ static inline void put_binfmt(struct linux_binfmt * fmt)  SYSCALL_DEFINE1(uselib, const char __user *, library)  {  	struct file *file; -	struct nameidata nd;  	char *tmp = getname(library);  	int error = PTR_ERR(tmp); -	if (!IS_ERR(tmp)) { -		error = path_lookup_open(AT_FDCWD, tmp, -					 LOOKUP_FOLLOW, &nd, -					 FMODE_READ|FMODE_EXEC); -		putname(tmp); -	} -	if (error) +	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))  		goto out;  	error = -EINVAL; -	if (!S_ISREG(nd.path.dentry->d_inode->i_mode)) +	if (!S_ISREG(file->f_path.dentry->d_inode->i_mode))  		goto exit;  	error = -EACCES; -	if (nd.path.mnt->mnt_flags & MNT_NOEXEC) +	if (file->f_path.mnt->mnt_flags & MNT_NOEXEC)  		goto exit; -	error = inode_permission(nd.path.dentry->d_inode, -				 MAY_READ | MAY_EXEC | MAY_OPEN); -	if (error) -		goto exit; -	error = ima_path_check(&nd.path, MAY_READ | MAY_EXEC | MAY_OPEN); -	if (error) -		goto exit; - -	file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE); -	error = PTR_ERR(file); -	if (IS_ERR(file)) -		goto out; -  	fsnotify_open(file->f_path.dentry);  	error = -ENOEXEC; @@ -159,13 +148,10 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)  		}  		read_unlock(&binfmt_lock);  	} +exit:  	fput(file);  out:    	return error; -exit: -	release_open_intent(&nd); -	path_put(&nd.path); -	goto out;  }  #ifdef CONFIG_MMU @@ -660,47 +646,33 @@ EXPORT_SYMBOL(setup_arg_pages);  struct file *open_exec(const char *name)  { -	struct nameidata nd;  	struct file *file;  	int err; -	err = path_lookup_open(AT_FDCWD, name, LOOKUP_FOLLOW, &nd, -				FMODE_READ|FMODE_EXEC); -	if (err) +	file = do_filp_open(AT_FDCWD, name, +				O_LARGEFILE | O_RDONLY | FMODE_EXEC, 0, +				MAY_EXEC | MAY_OPEN); +	if (IS_ERR(file))  		goto out;  	err = -EACCES; -	if (!S_ISREG(nd.path.dentry->d_inode->i_mode)) -		goto out_path_put; - -	if (nd.path.mnt->mnt_flags & MNT_NOEXEC) -		goto out_path_put; - -	err = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_OPEN); -	if (err) -		goto out_path_put; -	err = ima_path_check(&nd.path, MAY_EXEC | MAY_OPEN); -	if (err) -		goto out_path_put; +	if (!S_ISREG(file->f_path.dentry->d_inode->i_mode)) +		goto exit; -	file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE); -	if (IS_ERR(file)) -		return file; +	if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) +		goto exit;  	fsnotify_open(file->f_path.dentry);  	err = deny_write_access(file); -	if (err) { -		fput(file); -		goto out; -	} +	if (err) +		goto exit; +out:  	return file; - out_path_put: -	release_open_intent(&nd); -	path_put(&nd.path); - out: +exit: +	fput(file);  	return ERR_PTR(err);  }  EXPORT_SYMBOL(open_exec); @@ -1060,7 +1032,6 @@ EXPORT_SYMBOL(install_exec_creds);  int check_unsafe_exec(struct linux_binprm *bprm)  {  	struct task_struct *p = current, *t; -	unsigned long flags;  	unsigned n_fs;  	int res = 0; @@ -1068,21 +1039,22 @@ int check_unsafe_exec(struct linux_binprm *bprm)  	n_fs = 1;  	write_lock(&p->fs->lock); -	lock_task_sighand(p, &flags); +	rcu_read_lock();  	for (t = next_thread(p); t != p; t = next_thread(t)) {  		if (t->fs == p->fs)  			n_fs++;  	} +	rcu_read_unlock();  	if (p->fs->users > n_fs) {  		bprm->unsafe |= LSM_UNSAFE_SHARE;  	} else { -		if (p->fs->in_exec) -			res = -EAGAIN; -		p->fs->in_exec = 1; +		res = -EAGAIN; +		if (!p->fs->in_exec) { +			p->fs->in_exec = 1; +			res = 1; +		}  	} - -	unlock_task_sighand(p, &flags);  	write_unlock(&p->fs->lock);  	return res; @@ -1284,6 +1256,7 @@ int do_execve(char * filename,  	struct linux_binprm *bprm;  	struct file *file;  	struct files_struct *displaced; +	bool clear_in_exec;  	int retval;  	retval = unshare_files(&displaced); @@ -1306,8 +1279,9 @@ int do_execve(char * filename,  		goto out_unlock;  	retval = check_unsafe_exec(bprm); -	if (retval) +	if (retval < 0)  		goto out_unlock; +	clear_in_exec = retval;  	file = open_exec(filename);  	retval = PTR_ERR(file); @@ -1355,9 +1329,7 @@ int do_execve(char * filename,  		goto out;  	/* execve succeeded */ -	write_lock(¤t->fs->lock);  	current->fs->in_exec = 0; -	write_unlock(¤t->fs->lock);  	current->in_execve = 0;  	mutex_unlock(¤t->cred_exec_mutex);  	acct_update_integrals(current); @@ -1377,9 +1349,8 @@ out_file:  	}  out_unmark: -	write_lock(¤t->fs->lock); -	current->fs->in_exec = 0; -	write_unlock(¤t->fs->lock); +	if (clear_in_exec) +		current->fs->in_exec = 0;  out_unlock:  	current->in_execve = 0;  | 
