Separate the __user pathname handling from the bulk of the syscall.
Since we're doing this to enable relinking of unlinked files by
sys_checkpoint and not sys_linkat we're not using a sys-wrapper.

Signed-off-by: Matt Helsley <matth...@us.ibm.com>
Cc: contain...@lists.linux-foundation.org
Cc: Oren Laadan <or...@cs.columbia.edu>
Cc: Amir Goldstein <amir7...@users.sf.net>
Cc: linux-fsde...@vger.kernel.org
Cc: Al Viro <v...@zeniv.linux.org.uk>
Cc: Christoph Hellwig <h...@infradead.org>
Cc: Jamie Lokier <ja...@shareable.org>
---
 fs/namei.c |   79 ++++++++++++++++++++++++++++++++++++++---------------------
 1 files changed, 51 insertions(+), 28 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index eb279e3..8c9663d 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2456,6 +2456,51 @@ int vfs_link(struct dentry *old_dentry, struct inode 
*dir, struct dentry *new_de
        return error;
 }
 
+/* If the file has been unlinked then old_dentry doesn't match old_path */
+static int do_linkat(struct path *old_path, struct dentry *old_dentry,
+                    struct nameidata *nd, int flags)
+{
+       struct dentry *new_dentry;
+       int error = -EXDEV;
+
+       if (old_path->mnt != nd->path.mnt)
+               goto out;
+       new_dentry = lookup_create(nd, 0);
+       error = PTR_ERR(new_dentry);
+       if (IS_ERR(new_dentry))
+               goto out_unlock;
+       error = mnt_want_write(nd->path.mnt);
+       if (error)
+               goto out_dput;
+       error = security_path_link(old_dentry, &nd->path, new_dentry);
+       if (error)
+               goto out_drop_write;
+       error = vfs_link(old_dentry, nd->path.dentry->d_inode, new_dentry);
+out_drop_write:
+       mnt_drop_write(nd->path.mnt);
+out_dput:
+       dput(new_dentry);
+out_unlock:
+       mutex_unlock(&nd->path.dentry->d_inode->i_mutex);
+out:
+       return error;
+}
+
+static int do_kern_linkat(struct path *old_path, struct dentry *old_dentry,
+                         int newdfd, const char * newname, int flags)
+{
+       struct nameidata nd;
+       int error;
+
+       error = do_path_lookup(newdfd, newname, LOOKUP_PARENT, &nd);
+       if (error)
+               goto out;
+       error = do_linkat(old_path, old_dentry, &nd, flags);
+       path_put(&nd.path);
+out:
+       return error;
+}
+
 /*
  * Hardlinks are often used in delicate situations.  We avoid
  * security-related surprises by not following symlinks on the
@@ -2468,11 +2513,10 @@ int vfs_link(struct dentry *old_dentry, struct inode 
*dir, struct dentry *new_de
 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;
-       int error;
        char *to;
+       int error;
 
        if ((flags & ~AT_SYMLINK_FOLLOW) != 0)
                return -EINVAL;
@@ -2481,37 +2525,16 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user 
*, oldname,
                             flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0,
                             &old_path);
        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);
-       error = PTR_ERR(new_dentry);
-       if (IS_ERR(new_dentry))
-               goto out_unlock;
-       error = mnt_want_write(nd.path.mnt);
-       if (error)
-               goto out_dput;
-       error = security_path_link(old_path.dentry, &nd.path, new_dentry);
+       error = user_path_parent(newdfd, newname, &nd, &to);
        if (error)
-               goto out_drop_write;
-       error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry);
-out_drop_write:
-       mnt_drop_write(nd.path.mnt);
-out_dput:
-       dput(new_dentry);
-out_unlock:
-       mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
-out_release:
+               goto out_put_old_path;
+       error = do_linkat(&old_path, old_path.dentry, &nd, flags);
        path_put(&nd.path);
        putname(to);
-out:
+out_put_old_path:
        path_put(&old_path);
-
+out:
        return error;
 }
 
-- 
1.6.3.3

_______________________________________________
Containers mailing list
contain...@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers

_______________________________________________
Devel mailing list
Devel@openvz.org
https://openvz.org/mailman/listinfo/devel

Reply via email to