Commit dae6ad8f authored by Al Viro's avatar Al Viro

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
...@@ -2311,6 +2311,35 @@ struct dentry *lookup_create(struct nameidata *nd, int is_dir) ...@@ -2311,6 +2311,35 @@ struct dentry *lookup_create(struct nameidata *nd, int is_dir)
} }
EXPORT_SYMBOL_GPL(lookup_create); 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 vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
{ {
int error = may_create(dir, dentry); int error = may_create(dir, dentry);
...@@ -2359,54 +2388,46 @@ static int may_mknod(mode_t mode) ...@@ -2359,54 +2388,46 @@ static int may_mknod(mode_t mode)
SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, int, mode, SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, int, mode,
unsigned, dev) unsigned, dev)
{ {
int error;
char *tmp;
struct dentry *dentry; struct dentry *dentry;
struct nameidata nd; struct path path;
int error;
if (S_ISDIR(mode)) if (S_ISDIR(mode))
return -EPERM; return -EPERM;
error = user_path_parent(dfd, filename, &nd, &tmp); dentry = user_path_create(dfd, filename, &path, 0);
if (error) if (IS_ERR(dentry))
return error; return PTR_ERR(dentry);
dentry = lookup_create(&nd, 0); if (!IS_POSIXACL(path.dentry->d_inode))
if (IS_ERR(dentry)) {
error = PTR_ERR(dentry);
goto out_unlock;
}
if (!IS_POSIXACL(nd.path.dentry->d_inode))
mode &= ~current_umask(); mode &= ~current_umask();
error = may_mknod(mode); error = may_mknod(mode);
if (error) if (error)
goto out_dput; goto out_dput;
error = mnt_want_write(nd.path.mnt); error = mnt_want_write(path.mnt);
if (error) if (error)
goto out_dput; goto out_dput;
error = security_path_mknod(&nd.path, dentry, mode, dev); error = security_path_mknod(&path, dentry, mode, dev);
if (error) if (error)
goto out_drop_write; goto out_drop_write;
switch (mode & S_IFMT) { switch (mode & S_IFMT) {
case 0: case S_IFREG: 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; break;
case S_IFCHR: case S_IFBLK: 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)); new_decode_dev(dev));
break; break;
case S_IFIFO: case S_IFSOCK: 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; break;
} }
out_drop_write: out_drop_write:
mnt_drop_write(nd.path.mnt); mnt_drop_write(path.mnt);
out_dput: out_dput:
dput(dentry); dput(dentry);
out_unlock: mutex_unlock(&path.dentry->d_inode->i_mutex);
mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&path);
path_put(&nd.path);
putname(tmp);
return error; return error;
} }
...@@ -2439,38 +2460,29 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -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) SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, int, mode)
{ {
int error = 0;
char * tmp;
struct dentry *dentry; struct dentry *dentry;
struct nameidata nd; struct path path;
int error;
error = user_path_parent(dfd, pathname, &nd, &tmp);
if (error)
goto out_err;
dentry = lookup_create(&nd, 1); dentry = user_path_create(dfd, pathname, &path, 1);
error = PTR_ERR(dentry);
if (IS_ERR(dentry)) 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(); mode &= ~current_umask();
error = mnt_want_write(nd.path.mnt); error = mnt_want_write(path.mnt);
if (error) if (error)
goto out_dput; goto out_dput;
error = security_path_mkdir(&nd.path, dentry, mode); error = security_path_mkdir(&path, dentry, mode);
if (error) if (error)
goto out_drop_write; 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: out_drop_write:
mnt_drop_write(nd.path.mnt); mnt_drop_write(path.mnt);
out_dput: out_dput:
dput(dentry); dput(dentry);
out_unlock: mutex_unlock(&path.dentry->d_inode->i_mutex);
mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&path);
path_put(&nd.path);
putname(tmp);
out_err:
return error; return error;
} }
...@@ -2730,38 +2742,31 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, ...@@ -2730,38 +2742,31 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
{ {
int error; int error;
char *from; char *from;
char *to;
struct dentry *dentry; struct dentry *dentry;
struct nameidata nd; struct path path;
from = getname(oldname); from = getname(oldname);
if (IS_ERR(from)) if (IS_ERR(from))
return PTR_ERR(from); return PTR_ERR(from);
error = user_path_parent(newdfd, newname, &nd, &to); dentry = user_path_create(newdfd, newname, &path, 0);
if (error)
goto out_putname;
dentry = lookup_create(&nd, 0);
error = PTR_ERR(dentry); error = PTR_ERR(dentry);
if (IS_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) if (error)
goto out_dput; goto out_dput;
error = security_path_symlink(&nd.path, dentry, from); error = security_path_symlink(&path, dentry, from);
if (error) if (error)
goto out_drop_write; 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: out_drop_write:
mnt_drop_write(nd.path.mnt); mnt_drop_write(path.mnt);
out_dput: out_dput:
dput(dentry); dput(dentry);
out_unlock: mutex_unlock(&path.dentry->d_inode->i_mutex);
mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&path);
path_put(&nd.path);
putname(to);
out_putname: out_putname:
putname(from); putname(from);
return error; return error;
...@@ -2826,11 +2831,9 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, ...@@ -2826,11 +2831,9 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
int, newdfd, const char __user *, newname, int, flags) int, newdfd, const char __user *, newname, int, flags)
{ {
struct dentry *new_dentry; struct dentry *new_dentry;
struct nameidata nd; struct path old_path, new_path;
struct path old_path;
int how = 0; int how = 0;
int error; int error;
char *to;
if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0) if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
return -EINVAL; return -EINVAL;
...@@ -2852,32 +2855,27 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, ...@@ -2852,32 +2855,27 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
if (error) if (error)
return error; return error;
error = user_path_parent(newdfd, newname, &nd, &to); new_dentry = user_path_create(newdfd, newname, &new_path, 0);
if (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); error = PTR_ERR(new_dentry);
if (IS_ERR(new_dentry)) if (IS_ERR(new_dentry))
goto out_unlock; goto out;
error = mnt_want_write(nd.path.mnt);
error = -EXDEV;
if (old_path.mnt != new_path.mnt)
goto out_dput;
error = mnt_want_write(new_path.mnt);
if (error) if (error)
goto out_dput; 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) if (error)
goto out_drop_write; 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: out_drop_write:
mnt_drop_write(nd.path.mnt); mnt_drop_write(new_path.mnt);
out_dput: out_dput:
dput(new_dentry); dput(new_dentry);
out_unlock: mutex_unlock(&new_path.dentry->d_inode->i_mutex);
mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&new_path);
out_release:
path_put(&nd.path);
putname(to);
out: out:
path_put(&old_path); path_put(&old_path);
......
...@@ -4368,25 +4368,6 @@ static inline int ocfs2_may_create(struct inode *dir, struct dentry *child) ...@@ -4368,25 +4368,6 @@ static inline int ocfs2_may_create(struct inode *dir, struct dentry *child)
return inode_permission(dir, MAY_WRITE | MAY_EXEC); 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 * ocfs2_vfs_reflink - Create a reference-counted link
* *
...@@ -4460,10 +4441,8 @@ int ocfs2_reflink_ioctl(struct inode *inode, ...@@ -4460,10 +4441,8 @@ int ocfs2_reflink_ioctl(struct inode *inode,
bool preserve) bool preserve)
{ {
struct dentry *new_dentry; struct dentry *new_dentry;
struct nameidata nd; struct path old_path, new_path;
struct path old_path;
int error; int error;
char *to = NULL;
if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb)))
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -4474,39 +4453,33 @@ int ocfs2_reflink_ioctl(struct inode *inode, ...@@ -4474,39 +4453,33 @@ int ocfs2_reflink_ioctl(struct inode *inode,
return error; return error;
} }
error = ocfs2_user_path_parent(newname, &nd, &to); new_dentry = user_path_create(AT_FDCWD, newname, &new_path, 0);
if (error) { error = PTR_ERR(new_dentry);
if (IS_ERR(new_dentry)) {
mlog_errno(error); mlog_errno(error);
goto out; goto out;
} }
error = -EXDEV; error = -EXDEV;
if (old_path.mnt != nd.path.mnt) if (old_path.mnt != new_path.mnt) {
goto out_release;
new_dentry = lookup_create(&nd, 0);
error = PTR_ERR(new_dentry);
if (IS_ERR(new_dentry)) {
mlog_errno(error); 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) { if (error) {
mlog_errno(error); mlog_errno(error);
goto out_dput; goto out_dput;
} }
error = ocfs2_vfs_reflink(old_path.dentry, error = ocfs2_vfs_reflink(old_path.dentry,
nd.path.dentry->d_inode, new_path.dentry->d_inode,
new_dentry, preserve); new_dentry, preserve);
mnt_drop_write(nd.path.mnt); mnt_drop_write(new_path.mnt);
out_dput: out_dput:
dput(new_dentry); dput(new_dentry);
out_unlock: mutex_unlock(&new_path.dentry->d_inode->i_mutex);
mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&new_path);
out_release:
path_put(&nd.path);
putname(to);
out: out:
path_put(&old_path); path_put(&old_path);
......
...@@ -74,6 +74,8 @@ extern int user_path_at(int, const char __user *, unsigned, struct path *); ...@@ -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 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 kern_path_parent(const char *, struct nameidata *);
extern int vfs_path_lookup(struct dentry *, struct vfsmount *, extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
const char *, unsigned int, struct nameidata *); const char *, unsigned int, struct nameidata *);
......
...@@ -808,8 +808,9 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -808,8 +808,9 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct net *net = sock_net(sk); struct net *net = sock_net(sk);
struct unix_sock *u = unix_sk(sk); struct unix_sock *u = unix_sk(sk);
struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
char *sun_path = sunaddr->sun_path;
struct dentry *dentry = NULL; struct dentry *dentry = NULL;
struct nameidata nd; struct path path;
int err; int err;
unsigned hash; unsigned hash;
struct unix_address *addr; struct unix_address *addr;
...@@ -845,48 +846,44 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -845,48 +846,44 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
addr->hash = hash ^ sk->sk_type; addr->hash = hash ^ sk->sk_type;
atomic_set(&addr->refcnt, 1); atomic_set(&addr->refcnt, 1);
if (sunaddr->sun_path[0]) { if (sun_path[0]) {
unsigned int mode; unsigned int mode;
err = 0; err = 0;
/* /*
* Get the parent directory, calculate the hash for last * Get the parent directory, calculate the hash for last
* component. * component.
*/ */
err = kern_path_parent(sunaddr->sun_path, &nd); dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0);
if (err)
goto out_mknod_parent;
dentry = lookup_create(&nd, 0);
err = PTR_ERR(dentry); err = PTR_ERR(dentry);
if (IS_ERR(dentry)) if (IS_ERR(dentry))
goto out_mknod_unlock; goto out_mknod_parent;
/* /*
* All right, let's create it. * All right, let's create it.
*/ */
mode = S_IFSOCK | mode = S_IFSOCK |
(SOCK_INODE(sock)->i_mode & ~current_umask()); (SOCK_INODE(sock)->i_mode & ~current_umask());
err = mnt_want_write(nd.path.mnt); err = mnt_want_write(path.mnt);
if (err) if (err)
goto out_mknod_dput; goto out_mknod_dput;
err = security_path_mknod(&nd.path, dentry, mode, 0); err = security_path_mknod(&path, dentry, mode, 0);
if (err) if (err)
goto out_mknod_drop_write; 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: out_mknod_drop_write:
mnt_drop_write(nd.path.mnt); mnt_drop_write(path.mnt);
if (err) if (err)
goto out_mknod_dput; goto out_mknod_dput;
mutex_unlock(&nd.path.dentry->d_inode->i_mutex); mutex_unlock(&path.dentry->d_inode->i_mutex);
dput(nd.path.dentry); dput(path.dentry);
nd.path.dentry = dentry; path.dentry = dentry;
addr->hash = UNIX_HASH_SIZE; addr->hash = UNIX_HASH_SIZE;
} }
spin_lock(&unix_table_lock); spin_lock(&unix_table_lock);
if (!sunaddr->sun_path[0]) { if (!sun_path[0]) {
err = -EADDRINUSE; err = -EADDRINUSE;
if (__unix_find_socket_byname(net, sunaddr, addr_len, if (__unix_find_socket_byname(net, sunaddr, addr_len,
sk->sk_type, hash)) { sk->sk_type, hash)) {
...@@ -897,8 +894,8 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -897,8 +894,8 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
list = &unix_socket_table[addr->hash]; list = &unix_socket_table[addr->hash];
} else { } else {
list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)]; list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)];
u->dentry = nd.path.dentry; u->dentry = path.dentry;
u->mnt = nd.path.mnt; u->mnt = path.mnt;
} }
err = 0; err = 0;
...@@ -915,9 +912,8 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -915,9 +912,8 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
out_mknod_dput: out_mknod_dput:
dput(dentry); dput(dentry);
out_mknod_unlock: mutex_unlock(&path.dentry->d_inode->i_mutex);
mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&path);
path_put(&nd.path);
out_mknod_parent: out_mknod_parent:
if (err == -EEXIST) if (err == -EEXIST)
err = -EADDRINUSE; err = -EADDRINUSE;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment