diff options
Diffstat (limited to 'ipc/mqueue.c')
| -rw-r--r-- | ipc/mqueue.c | 119 | 
1 files changed, 48 insertions, 71 deletions
diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 8ce57691e7b..f8e54f5b908 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -413,7 +413,7 @@ static void mqueue_evict_inode(struct inode *inode)  }  static int mqueue_create(struct inode *dir, struct dentry *dentry, -				umode_t mode, struct nameidata *nd) +				umode_t mode, bool excl)  {  	struct inode *inode;  	struct mq_attr *attr = dentry->d_fsdata; @@ -721,8 +721,8 @@ static int mq_attr_ok(struct ipc_namespace *ipc_ns, struct mq_attr *attr)  /*   * Invoked when creating a new queue via sys_mq_open   */ -static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir, -			struct dentry *dentry, int oflag, umode_t mode, +static struct file *do_create(struct ipc_namespace *ipc_ns, struct inode *dir, +			struct path *path, int oflag, umode_t mode,  			struct mq_attr *attr)  {  	const struct cred *cred = current_cred(); @@ -732,9 +732,9 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir,  	if (attr) {  		ret = mq_attr_ok(ipc_ns, attr);  		if (ret) -			goto out; +			return ERR_PTR(ret);  		/* store for use during create */ -		dentry->d_fsdata = attr; +		path->dentry->d_fsdata = attr;  	} else {  		struct mq_attr def_attr; @@ -744,71 +744,51 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir,  					  ipc_ns->mq_msgsize_default);  		ret = mq_attr_ok(ipc_ns, &def_attr);  		if (ret) -			goto out; +			return ERR_PTR(ret);  	}  	mode &= ~current_umask(); -	ret = mnt_want_write(ipc_ns->mq_mnt); +	ret = mnt_want_write(path->mnt);  	if (ret) -		goto out; -	ret = vfs_create(dir->d_inode, dentry, mode, NULL); -	dentry->d_fsdata = NULL; -	if (ret) -		goto out_drop_write; - -	result = dentry_open(dentry, ipc_ns->mq_mnt, oflag, cred); +		return ERR_PTR(ret); +	ret = vfs_create(dir, path->dentry, mode, true); +	path->dentry->d_fsdata = NULL; +	if (!ret) +		result = dentry_open(path, oflag, cred); +	else +		result = ERR_PTR(ret);  	/*  	 * dentry_open() took a persistent mnt_want_write(),  	 * so we can now drop this one.  	 */ -	mnt_drop_write(ipc_ns->mq_mnt); +	mnt_drop_write(path->mnt);  	return result; - -out_drop_write: -	mnt_drop_write(ipc_ns->mq_mnt); -out: -	dput(dentry); -	mntput(ipc_ns->mq_mnt); -	return ERR_PTR(ret);  }  /* Opens existing queue */ -static struct file *do_open(struct ipc_namespace *ipc_ns, -				struct dentry *dentry, int oflag) +static struct file *do_open(struct path *path, int oflag)  { -	int ret; -	const struct cred *cred = current_cred(); -  	static const int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,  						  MAY_READ | MAY_WRITE }; - -	if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) { -		ret = -EINVAL; -		goto err; -	} - -	if (inode_permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE])) { -		ret = -EACCES; -		goto err; -	} - -	return dentry_open(dentry, ipc_ns->mq_mnt, oflag, cred); - -err: -	dput(dentry); -	mntput(ipc_ns->mq_mnt); -	return ERR_PTR(ret); +	int acc; +	if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) +		return ERR_PTR(-EINVAL); +	acc = oflag2acc[oflag & O_ACCMODE]; +	if (inode_permission(path->dentry->d_inode, acc)) +		return ERR_PTR(-EACCES); +	return dentry_open(path, oflag, current_cred());  }  SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,  		struct mq_attr __user *, u_attr)  { -	struct dentry *dentry; +	struct path path;  	struct file *filp;  	char *name;  	struct mq_attr attr;  	int fd, error;  	struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; +	struct dentry *root = ipc_ns->mq_mnt->mnt_root;  	if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr)))  		return -EFAULT; @@ -822,52 +802,49 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,  	if (fd < 0)  		goto out_putname; -	mutex_lock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex); -	dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name)); -	if (IS_ERR(dentry)) { -		error = PTR_ERR(dentry); +	error = 0; +	mutex_lock(&root->d_inode->i_mutex); +	path.dentry = lookup_one_len(name, root, strlen(name)); +	if (IS_ERR(path.dentry)) { +		error = PTR_ERR(path.dentry);  		goto out_putfd;  	} -	mntget(ipc_ns->mq_mnt); +	path.mnt = mntget(ipc_ns->mq_mnt);  	if (oflag & O_CREAT) { -		if (dentry->d_inode) {	/* entry already exists */ -			audit_inode(name, dentry); +		if (path.dentry->d_inode) {	/* entry already exists */ +			audit_inode(name, path.dentry);  			if (oflag & O_EXCL) {  				error = -EEXIST;  				goto out;  			} -			filp = do_open(ipc_ns, dentry, oflag); +			filp = do_open(&path, oflag);  		} else { -			filp = do_create(ipc_ns, ipc_ns->mq_mnt->mnt_root, -						dentry, oflag, mode, +			filp = do_create(ipc_ns, root->d_inode, +						&path, oflag, mode,  						u_attr ? &attr : NULL);  		}  	} else { -		if (!dentry->d_inode) { +		if (!path.dentry->d_inode) {  			error = -ENOENT;  			goto out;  		} -		audit_inode(name, dentry); -		filp = do_open(ipc_ns, dentry, oflag); +		audit_inode(name, path.dentry); +		filp = do_open(&path, oflag);  	} -	if (IS_ERR(filp)) { +	if (!IS_ERR(filp)) +		fd_install(fd, filp); +	else  		error = PTR_ERR(filp); -		goto out_putfd; -	} - -	fd_install(fd, filp); -	goto out_upsem; -  out: -	dput(dentry); -	mntput(ipc_ns->mq_mnt); +	path_put(&path);  out_putfd: -	put_unused_fd(fd); -	fd = error; -out_upsem: -	mutex_unlock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex); +	if (error) { +		put_unused_fd(fd); +		fd = error; +	} +	mutex_unlock(&root->d_inode->i_mutex);  out_putname:  	putname(name);  	return fd;  |