Skip to content

Commit 3cab989

Browse files
author
Al Viro
committed
RCU pathwalk breakage when running into a symlink overmounting something
Calling unlazy_walk() in walk_component() and do_last() when we find a symlink that needs to be followed doesn't acquire a reference to vfsmount. That's fine when the symlink is on the same vfsmount as the parent directory (which is almost always the case), but it's not always true - one _can_ manage to bind a symlink on top of something. And in such cases we end up with excessive mntput(). Cc: [email protected] # since 2.6.39 Signed-off-by: Al Viro <[email protected]>
1 parent ac74d8d commit 3cab989

File tree

1 file changed

+4
-2
lines changed

1 file changed

+4
-2
lines changed

fs/namei.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1590,7 +1590,8 @@ static inline int walk_component(struct nameidata *nd, struct path *path,
15901590

15911591
if (should_follow_link(path->dentry, follow)) {
15921592
if (nd->flags & LOOKUP_RCU) {
1593-
if (unlikely(unlazy_walk(nd, path->dentry))) {
1593+
if (unlikely(nd->path.mnt != path->mnt ||
1594+
unlazy_walk(nd, path->dentry))) {
15941595
err = -ECHILD;
15951596
goto out_err;
15961597
}
@@ -3045,7 +3046,8 @@ static int do_last(struct nameidata *nd, struct path *path,
30453046

30463047
if (should_follow_link(path->dentry, !symlink_ok)) {
30473048
if (nd->flags & LOOKUP_RCU) {
3048-
if (unlikely(unlazy_walk(nd, path->dentry))) {
3049+
if (unlikely(nd->path.mnt != path->mnt ||
3050+
unlazy_walk(nd, path->dentry))) {
30493051
error = -ECHILD;
30503052
goto out;
30513053
}

0 commit comments

Comments
 (0)