summaryrefslogtreecommitdiff
path: root/fs/namei.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2020-02-26 19:59:02 +0300
committerAl Viro <viro@zeniv.linux.org.uk>2020-03-14 04:09:13 +0300
commitc9a0f75d81e3ffccb885f0069d45e065acc0349a (patch)
tree1b8e6d6d6fb425783d1eea0d0f37a1bcedbbbacb /fs/namei.c
parentabc2c632e0cec6f76883d008c298e31cb3e2d242 (diff)
downloadlinux-c9a0f75d81e3ffccb885f0069d45e065acc0349a.tar.xz
follow_dotdot{,_rcu}(): lift LOOKUP_BENEATH checks out of loop
Behaviour change: LOOKUP_BENEATH lookup of .. in absolute root yields an error even if it's not the process' root. That's possible only if you'd managed to escape chroot jail by way of procfs symlinks, but IMO the resulting behaviour is not worse - more consistent and easier to describe: ".." in root is "stay where you are", uness LOOKUP_BENEATH has been given, in which case it's "fail with EXDEV". Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c20
1 files changed, 10 insertions, 10 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 772d82daf3b4..577dc541a4d4 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1370,11 +1370,8 @@ static int follow_dotdot_rcu(struct nameidata *nd)
unsigned seq;
while (1) {
- if (path_equal(&nd->path, &nd->root)) {
- if (unlikely(nd->flags & LOOKUP_BENEATH))
- return -ECHILD;
+ if (path_equal(&nd->path, &nd->root))
break;
- }
if (nd->path.dentry != nd->path.mnt->mnt_root) {
struct dentry *old = nd->path.dentry;
@@ -1405,7 +1402,10 @@ static int follow_dotdot_rcu(struct nameidata *nd)
nd->seq = seq;
}
}
- if (likely(parent)) {
+ if (unlikely(!parent)) {
+ if (unlikely(nd->flags & LOOKUP_BENEATH))
+ return -ECHILD;
+ } else {
nd->path.dentry = parent;
nd->seq = seq;
}
@@ -1447,11 +1447,8 @@ static int follow_dotdot(struct nameidata *nd)
{
struct dentry *parent = NULL;
while (1) {
- if (path_equal(&nd->path, &nd->root)) {
- if (unlikely(nd->flags & LOOKUP_BENEATH))
- return -EXDEV;
+ if (path_equal(&nd->path, &nd->root))
break;
- }
if (nd->path.dentry != nd->path.mnt->mnt_root) {
/* rare case of legitimate dget_parent()... */
parent = dget_parent(nd->path.dentry);
@@ -1466,7 +1463,10 @@ static int follow_dotdot(struct nameidata *nd)
if (unlikely(nd->flags & LOOKUP_NO_XDEV))
return -EXDEV;
}
- if (likely(parent)) {
+ if (unlikely(!parent)) {
+ if (unlikely(nd->flags & LOOKUP_BENEATH))
+ return -EXDEV;
+ } else {
dput(nd->path.dentry);
nd->path.dentry = parent;
}