diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-08-07 21:03:25 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-08-07 21:03:25 -0700 |
commit | d57b2b5bc4301f37d1b07e3351d575bd634c7300 (patch) | |
tree | df66f74a8c060b9a2c699e40615915af01aec03f /fs/namespace.c | |
parent | 049eb096da48db0421dd5e358b9b082a1a8a2025 (diff) | |
parent | 25ccd24ffd9119c452d711efa2604a7a0c35956e (diff) | |
download | lwn-d57b2b5bc4301f37d1b07e3351d575bd634c7300.tar.gz lwn-d57b2b5bc4301f37d1b07e3351d575bd634c7300.zip |
Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull mount leak fix from Al Viro:
"Regression fix for the syscalls-for-init series - fix a leak of a 'struct path'"
* 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
fs: fix a struct path leak in path_umount
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 32 |
1 files changed, 18 insertions, 14 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 016553d0f925..bae0e95b3713 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1706,34 +1706,38 @@ static inline bool may_mandlock(void) } #endif -int path_umount(struct path *path, int flags) +static int can_umount(const struct path *path, int flags) { - struct mount *mnt; - int retval; + struct mount *mnt = real_mount(path->mnt); if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW)) return -EINVAL; if (!may_mount()) return -EPERM; - - mnt = real_mount(path->mnt); - retval = -EINVAL; if (path->dentry != path->mnt->mnt_root) - goto dput_and_out; + return -EINVAL; if (!check_mnt(mnt)) - goto dput_and_out; + return -EINVAL; if (mnt->mnt.mnt_flags & MNT_LOCKED) /* Check optimistically */ - goto dput_and_out; - retval = -EPERM; + return -EINVAL; if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN)) - goto dput_and_out; + return -EPERM; + return 0; +} + +int path_umount(struct path *path, int flags) +{ + struct mount *mnt = real_mount(path->mnt); + int ret; + + ret = can_umount(path, flags); + if (!ret) + ret = do_umount(mnt, flags); - retval = do_umount(mnt, flags); -dput_and_out: /* we mustn't call path_put() as that would clear mnt_expiry_mark */ dput(path->dentry); mntput_no_expire(mnt); - return retval; + return ret; } static int ksys_umount(char __user *name, int flags) |