Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dae6ad8f authored by Al Viro's avatar Al Viro
Browse files

new helpers: kern_path_create/user_path_create



combination of kern_path_parent() and lookup_create().  Does *not*
expose struct nameidata to caller.  Syscalls converted to that...

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 49084c3b
Loading
Loading
Loading
Loading
+76 −78
Original line number Diff line number Diff line
@@ -2311,6 +2311,35 @@ struct dentry *lookup_create(struct nameidata *nd, int is_dir)
}
EXPORT_SYMBOL_GPL(lookup_create);

struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path, int is_dir)
{
	struct nameidata nd;
	struct dentry *res;
	int error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd);
	if (error)
		return ERR_PTR(error);
	res = lookup_create(&nd, is_dir);
	if (IS_ERR(res)) {
		mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
		path_put(&nd.path);
	}
	*path = nd.path;
	return res;
}
EXPORT_SYMBOL(kern_path_create);

struct dentry *user_path_create(int dfd, const char __user *pathname, struct path *path, int is_dir)
{
	char *tmp = getname(pathname);
	struct dentry *res;
	if (IS_ERR(tmp))
		return ERR_CAST(tmp);
	res = kern_path_create(dfd, tmp, path, is_dir);
	putname(tmp);
	return res;
}
EXPORT_SYMBOL(user_path_create);

int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
{
	int error = may_create(dir, dentry);
@@ -2359,54 +2388,46 @@ static int may_mknod(mode_t mode)
SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, int, mode,
		unsigned, dev)
{
	int error;
	char *tmp;
	struct dentry *dentry;
	struct nameidata nd;
	struct path path;
	int error;

	if (S_ISDIR(mode))
		return -EPERM;

	error = user_path_parent(dfd, filename, &nd, &tmp);
	if (error)
		return error;
	dentry = user_path_create(dfd, filename, &path, 0);
	if (IS_ERR(dentry))
		return PTR_ERR(dentry);

	dentry = lookup_create(&nd, 0);
	if (IS_ERR(dentry)) {
		error = PTR_ERR(dentry);
		goto out_unlock;
	}
	if (!IS_POSIXACL(nd.path.dentry->d_inode))
	if (!IS_POSIXACL(path.dentry->d_inode))
		mode &= ~current_umask();
	error = may_mknod(mode);
	if (error)
		goto out_dput;
	error = mnt_want_write(nd.path.mnt);
	error = mnt_want_write(path.mnt);
	if (error)
		goto out_dput;
	error = security_path_mknod(&nd.path, dentry, mode, dev);
	error = security_path_mknod(&path, dentry, mode, dev);
	if (error)
		goto out_drop_write;
	switch (mode & S_IFMT) {
		case 0: case S_IFREG:
			error = vfs_create(nd.path.dentry->d_inode,dentry,mode,NULL);
			error = vfs_create(path.dentry->d_inode,dentry,mode,NULL);
			break;
		case S_IFCHR: case S_IFBLK:
			error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,
			error = vfs_mknod(path.dentry->d_inode,dentry,mode,
					new_decode_dev(dev));
			break;
		case S_IFIFO: case S_IFSOCK:
			error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0);
			error = vfs_mknod(path.dentry->d_inode,dentry,mode,0);
			break;
	}
out_drop_write:
	mnt_drop_write(nd.path.mnt);
	mnt_drop_write(path.mnt);
out_dput:
	dput(dentry);
out_unlock:
	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
	path_put(&nd.path);
	putname(tmp);
	mutex_unlock(&path.dentry->d_inode->i_mutex);
	path_put(&path);

	return error;
}
@@ -2439,38 +2460,29 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)

SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, int, mode)
{
	int error = 0;
	char * tmp;
	struct dentry *dentry;
	struct nameidata nd;

	error = user_path_parent(dfd, pathname, &nd, &tmp);
	if (error)
		goto out_err;
	struct path path;
	int error;

	dentry = lookup_create(&nd, 1);
	error = PTR_ERR(dentry);
	dentry = user_path_create(dfd, pathname, &path, 1);
	if (IS_ERR(dentry))
		goto out_unlock;
		return PTR_ERR(dentry);

	if (!IS_POSIXACL(nd.path.dentry->d_inode))
	if (!IS_POSIXACL(path.dentry->d_inode))
		mode &= ~current_umask();
	error = mnt_want_write(nd.path.mnt);
	error = mnt_want_write(path.mnt);
	if (error)
		goto out_dput;
	error = security_path_mkdir(&nd.path, dentry, mode);
	error = security_path_mkdir(&path, dentry, mode);
	if (error)
		goto out_drop_write;
	error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
	error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
out_drop_write:
	mnt_drop_write(nd.path.mnt);
	mnt_drop_write(path.mnt);
out_dput:
	dput(dentry);
out_unlock:
	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
	path_put(&nd.path);
	putname(tmp);
out_err:
	mutex_unlock(&path.dentry->d_inode->i_mutex);
	path_put(&path);
	return error;
}

@@ -2730,38 +2742,31 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
{
	int error;
	char *from;
	char *to;
	struct dentry *dentry;
	struct nameidata nd;
	struct path path;

	from = getname(oldname);
	if (IS_ERR(from))
		return PTR_ERR(from);

	error = user_path_parent(newdfd, newname, &nd, &to);
	if (error)
		goto out_putname;

	dentry = lookup_create(&nd, 0);
	dentry = user_path_create(newdfd, newname, &path, 0);
	error = PTR_ERR(dentry);
	if (IS_ERR(dentry))
		goto out_unlock;
		goto out_putname;

	error = mnt_want_write(nd.path.mnt);
	error = mnt_want_write(path.mnt);
	if (error)
		goto out_dput;
	error = security_path_symlink(&nd.path, dentry, from);
	error = security_path_symlink(&path, dentry, from);
	if (error)
		goto out_drop_write;
	error = vfs_symlink(nd.path.dentry->d_inode, dentry, from);
	error = vfs_symlink(path.dentry->d_inode, dentry, from);
out_drop_write:
	mnt_drop_write(nd.path.mnt);
	mnt_drop_write(path.mnt);
out_dput:
	dput(dentry);
out_unlock:
	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
	path_put(&nd.path);
	putname(to);
	mutex_unlock(&path.dentry->d_inode->i_mutex);
	path_put(&path);
out_putname:
	putname(from);
	return error;
@@ -2826,11 +2831,9 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
		int, newdfd, const char __user *, newname, int, flags)
{
	struct dentry *new_dentry;
	struct nameidata nd;
	struct path old_path;
	struct path old_path, new_path;
	int how = 0;
	int error;
	char *to;

	if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
		return -EINVAL;
@@ -2852,32 +2855,27 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
	if (error)
		return error;

	error = user_path_parent(newdfd, newname, &nd, &to);
	if (error)
		goto out;
	error = -EXDEV;
	if (old_path.mnt != nd.path.mnt)
		goto out_release;
	new_dentry = lookup_create(&nd, 0);
	new_dentry = user_path_create(newdfd, newname, &new_path, 0);
	error = PTR_ERR(new_dentry);
	if (IS_ERR(new_dentry))
		goto out_unlock;
	error = mnt_want_write(nd.path.mnt);
		goto out;

	error = -EXDEV;
	if (old_path.mnt != new_path.mnt)
		goto out_dput;
	error = mnt_want_write(new_path.mnt);
	if (error)
		goto out_dput;
	error = security_path_link(old_path.dentry, &nd.path, new_dentry);
	error = security_path_link(old_path.dentry, &new_path, new_dentry);
	if (error)
		goto out_drop_write;
	error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry);
	error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry);
out_drop_write:
	mnt_drop_write(nd.path.mnt);
	mnt_drop_write(new_path.mnt);
out_dput:
	dput(new_dentry);
out_unlock:
	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
out_release:
	path_put(&nd.path);
	putname(to);
	mutex_unlock(&new_path.dentry->d_inode->i_mutex);
	path_put(&new_path);
out:
	path_put(&old_path);

+11 −38
Original line number Diff line number Diff line
@@ -4368,25 +4368,6 @@ static inline int ocfs2_may_create(struct inode *dir, struct dentry *child)
	return inode_permission(dir, MAY_WRITE | MAY_EXEC);
}

/* copied from user_path_parent. */
static int ocfs2_user_path_parent(const char __user *path,
				  struct nameidata *nd, char **name)
{
	char *s = getname(path);
	int error;

	if (IS_ERR(s))
		return PTR_ERR(s);

	error = kern_path_parent(s, nd);
	if (error)
		putname(s);
	else
		*name = s;

	return error;
}

/**
 * ocfs2_vfs_reflink - Create a reference-counted link
 *
@@ -4460,10 +4441,8 @@ int ocfs2_reflink_ioctl(struct inode *inode,
			bool preserve)
{
	struct dentry *new_dentry;
	struct nameidata nd;
	struct path old_path;
	struct path old_path, new_path;
	int error;
	char *to = NULL;

	if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb)))
		return -EOPNOTSUPP;
@@ -4474,39 +4453,33 @@ int ocfs2_reflink_ioctl(struct inode *inode,
		return error;
	}

	error = ocfs2_user_path_parent(newname, &nd, &to);
	if (error) {
	new_dentry = user_path_create(AT_FDCWD, newname, &new_path, 0);
	error = PTR_ERR(new_dentry);
	if (IS_ERR(new_dentry)) {
		mlog_errno(error);
		goto out;
	}

	error = -EXDEV;
	if (old_path.mnt != nd.path.mnt)
		goto out_release;
	new_dentry = lookup_create(&nd, 0);
	error = PTR_ERR(new_dentry);
	if (IS_ERR(new_dentry)) {
	if (old_path.mnt != new_path.mnt) {
		mlog_errno(error);
		goto out_unlock;
		goto out_dput;
	}

	error = mnt_want_write(nd.path.mnt);
	error = mnt_want_write(new_path.mnt);
	if (error) {
		mlog_errno(error);
		goto out_dput;
	}

	error = ocfs2_vfs_reflink(old_path.dentry,
				  nd.path.dentry->d_inode,
				  new_path.dentry->d_inode,
				  new_dentry, preserve);
	mnt_drop_write(nd.path.mnt);
	mnt_drop_write(new_path.mnt);
out_dput:
	dput(new_dentry);
out_unlock:
	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
out_release:
	path_put(&nd.path);
	putname(to);
	mutex_unlock(&new_path.dentry->d_inode->i_mutex);
	path_put(&new_path);
out:
	path_put(&old_path);

+2 −0
Original line number Diff line number Diff line
@@ -74,6 +74,8 @@ extern int user_path_at(int, const char __user *, unsigned, struct path *);

extern int kern_path(const char *, unsigned, struct path *);

extern struct dentry *kern_path_create(int, const char *, struct path *, int);
extern struct dentry *user_path_create(int, const char __user *, struct path *, int);
extern int kern_path_parent(const char *, struct nameidata *);
extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
			   const char *, unsigned int, struct nameidata *);
+17 −21
Original line number Diff line number Diff line
@@ -808,8 +808,9 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
	struct net *net = sock_net(sk);
	struct unix_sock *u = unix_sk(sk);
	struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
	char *sun_path = sunaddr->sun_path;
	struct dentry *dentry = NULL;
	struct nameidata nd;
	struct path path;
	int err;
	unsigned hash;
	struct unix_address *addr;
@@ -845,48 +846,44 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
	addr->hash = hash ^ sk->sk_type;
	atomic_set(&addr->refcnt, 1);

	if (sunaddr->sun_path[0]) {
	if (sun_path[0]) {
		unsigned int mode;
		err = 0;
		/*
		 * Get the parent directory, calculate the hash for last
		 * component.
		 */
		err = kern_path_parent(sunaddr->sun_path, &nd);
		if (err)
			goto out_mknod_parent;

		dentry = lookup_create(&nd, 0);
		dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0);
		err = PTR_ERR(dentry);
		if (IS_ERR(dentry))
			goto out_mknod_unlock;
			goto out_mknod_parent;

		/*
		 * All right, let's create it.
		 */
		mode = S_IFSOCK |
		       (SOCK_INODE(sock)->i_mode & ~current_umask());
		err = mnt_want_write(nd.path.mnt);
		err = mnt_want_write(path.mnt);
		if (err)
			goto out_mknod_dput;
		err = security_path_mknod(&nd.path, dentry, mode, 0);
		err = security_path_mknod(&path, dentry, mode, 0);
		if (err)
			goto out_mknod_drop_write;
		err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, 0);
		err = vfs_mknod(path.dentry->d_inode, dentry, mode, 0);
out_mknod_drop_write:
		mnt_drop_write(nd.path.mnt);
		mnt_drop_write(path.mnt);
		if (err)
			goto out_mknod_dput;
		mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
		dput(nd.path.dentry);
		nd.path.dentry = dentry;
		mutex_unlock(&path.dentry->d_inode->i_mutex);
		dput(path.dentry);
		path.dentry = dentry;

		addr->hash = UNIX_HASH_SIZE;
	}

	spin_lock(&unix_table_lock);

	if (!sunaddr->sun_path[0]) {
	if (!sun_path[0]) {
		err = -EADDRINUSE;
		if (__unix_find_socket_byname(net, sunaddr, addr_len,
					      sk->sk_type, hash)) {
@@ -897,8 +894,8 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
		list = &unix_socket_table[addr->hash];
	} else {
		list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)];
		u->dentry = nd.path.dentry;
		u->mnt    = nd.path.mnt;
		u->dentry = path.dentry;
		u->mnt    = path.mnt;
	}

	err = 0;
@@ -915,9 +912,8 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)

out_mknod_dput:
	dput(dentry);
out_mknod_unlock:
	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
	path_put(&nd.path);
	mutex_unlock(&path.dentry->d_inode->i_mutex);
	path_put(&path);
out_mknod_parent:
	if (err == -EEXIST)
		err = -EADDRINUSE;