|
@@ -2311,6 +2311,35 @@ fail:
|
|
|
}
|
|
|
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);
|
|
|
|