From: Valerie Aurora <vaurora@xxxxxxxxxx> --- fs/namei.c | 23 ++++++++++++++++++++--- 1 files changed, 20 insertions(+), 3 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index fafd352..2b4780a 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3519,10 +3519,12 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, { struct dentry *new_dentry; struct nameidata nd; + struct nameidata old_nd; struct path old_path; int how = 0; int error; char *to; + char *from; if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0) return -EINVAL; @@ -3540,7 +3542,8 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, if (flags & AT_SYMLINK_FOLLOW) how |= LOOKUP_FOLLOW; - error = user_path_at(olddfd, oldname, how, &old_path); + error = user_path_nd(olddfd, oldname, how, + &old_nd, &old_path, &from); if (error) return error; @@ -3548,8 +3551,20 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, if (error) goto out; error = -EXDEV; - if (old_path.mnt != nd.path.mnt) - goto out_release; + if (old_path.mnt != nd.path.mnt) { + if (IS_DIR_UNIONED(old_nd.path.dentry) && + (old_nd.path.mnt == nd.path.mnt)) { + error = mnt_want_write(old_nd.path.mnt); + if (error) + goto out_release; + error = union_copyup(&old_nd, &old_path); + mnt_drop_write(old_nd.path.mnt); + if (error) + goto out_release; + } else { + goto out_release; + } + } new_dentry = lookup_create(&nd, 0); error = PTR_ERR(new_dentry); if (IS_ERR(new_dentry)) @@ -3572,6 +3587,8 @@ out_release: putname(to); out: path_put(&old_path); + path_put(&old_nd.path); + putname(from); return error; } -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html