Loading fs/namespace.c +59 −60 Original line number Diff line number Diff line Loading @@ -1167,19 +1167,19 @@ asmlinkage long sys_oldumount(char __user * name) #endif static int mount_is_safe(struct nameidata *nd) static int mount_is_safe(struct path *path) { if (capable(CAP_SYS_ADMIN)) return 0; return -EPERM; #ifdef notyet if (S_ISLNK(nd->path.dentry->d_inode->i_mode)) if (S_ISLNK(path->dentry->d_inode->i_mode)) return -EPERM; if (nd->path.dentry->d_inode->i_mode & S_ISVTX) { if (current->uid != nd->path.dentry->d_inode->i_uid) if (path->dentry->d_inode->i_mode & S_ISVTX) { if (current->uid != path->dentry->d_inode->i_uid) return -EPERM; } if (vfs_permission(nd, MAY_WRITE)) if (inode_permission(path->dentry->d_inode, MAY_WRITE)) return -EPERM; return 0; #endif Loading Loading @@ -1427,9 +1427,9 @@ static int graft_tree(struct vfsmount *mnt, struct path *path) * recursively change the type of the mountpoint. * noinline this do_mount helper to save do_mount stack space. */ static noinline int do_change_type(struct nameidata *nd, int flag) static noinline int do_change_type(struct path *path, int flag) { struct vfsmount *m, *mnt = nd->path.mnt; struct vfsmount *m, *mnt = path->mnt; int recurse = flag & MS_REC; int type = flag & ~MS_REC; int err = 0; Loading @@ -1437,7 +1437,7 @@ static noinline int do_change_type(struct nameidata *nd, int flag) if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (nd->path.dentry != nd->path.mnt->mnt_root) if (path->dentry != path->mnt->mnt_root) return -EINVAL; down_write(&namespace_sem); Loading @@ -1461,38 +1461,38 @@ static noinline int do_change_type(struct nameidata *nd, int flag) * do loopback mount. * noinline this do_mount helper to save do_mount stack space. */ static noinline int do_loopback(struct nameidata *nd, char *old_name, static noinline int do_loopback(struct path *path, char *old_name, int recurse) { struct nameidata old_nd; struct path old_path; struct vfsmount *mnt = NULL; int err = mount_is_safe(nd); int err = mount_is_safe(path); if (err) return err; if (!old_name || !*old_name) return -EINVAL; err = path_lookup(old_name, LOOKUP_FOLLOW, &old_nd); err = kern_path(old_name, LOOKUP_FOLLOW, &old_path); if (err) return err; down_write(&namespace_sem); err = -EINVAL; if (IS_MNT_UNBINDABLE(old_nd.path.mnt)) if (IS_MNT_UNBINDABLE(old_path.mnt)) goto out; if (!check_mnt(nd->path.mnt) || !check_mnt(old_nd.path.mnt)) if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) goto out; err = -ENOMEM; if (recurse) mnt = copy_tree(old_nd.path.mnt, old_nd.path.dentry, 0); mnt = copy_tree(old_path.mnt, old_path.dentry, 0); else mnt = clone_mnt(old_nd.path.mnt, old_nd.path.dentry, 0); mnt = clone_mnt(old_path.mnt, old_path.dentry, 0); if (!mnt) goto out; err = graft_tree(mnt, &nd->path); err = graft_tree(mnt, path); if (err) { LIST_HEAD(umount_list); spin_lock(&vfsmount_lock); Loading @@ -1503,7 +1503,7 @@ static noinline int do_loopback(struct nameidata *nd, char *old_name, out: up_write(&namespace_sem); path_put(&old_nd.path); path_put(&old_path); return err; } Loading @@ -1530,31 +1530,31 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags) * on it - tough luck. * noinline this do_mount helper to save do_mount stack space. */ static noinline int do_remount(struct nameidata *nd, int flags, int mnt_flags, static noinline int do_remount(struct path *path, int flags, int mnt_flags, void *data) { int err; struct super_block *sb = nd->path.mnt->mnt_sb; struct super_block *sb = path->mnt->mnt_sb; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (!check_mnt(nd->path.mnt)) if (!check_mnt(path->mnt)) return -EINVAL; if (nd->path.dentry != nd->path.mnt->mnt_root) if (path->dentry != path->mnt->mnt_root) return -EINVAL; down_write(&sb->s_umount); if (flags & MS_BIND) err = change_mount_flags(nd->path.mnt, flags); err = change_mount_flags(path->mnt, flags); else err = do_remount_sb(sb, flags, data, 0); if (!err) nd->path.mnt->mnt_flags = mnt_flags; path->mnt->mnt_flags = mnt_flags; up_write(&sb->s_umount); if (!err) security_sb_post_remount(nd->path.mnt, flags, data); security_sb_post_remount(path->mnt, flags, data); return err; } Loading @@ -1571,78 +1571,77 @@ static inline int tree_contains_unbindable(struct vfsmount *mnt) /* * noinline this do_mount helper to save do_mount stack space. */ static noinline int do_move_mount(struct nameidata *nd, char *old_name) static noinline int do_move_mount(struct path *path, char *old_name) { struct nameidata old_nd; struct path parent_path; struct path old_path, parent_path; struct vfsmount *p; int err = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (!old_name || !*old_name) return -EINVAL; err = path_lookup(old_name, LOOKUP_FOLLOW, &old_nd); err = kern_path(old_name, LOOKUP_FOLLOW, &old_path); if (err) return err; down_write(&namespace_sem); while (d_mountpoint(nd->path.dentry) && follow_down(&nd->path.mnt, &nd->path.dentry)) while (d_mountpoint(path->dentry) && follow_down(&path->mnt, &path->dentry)) ; err = -EINVAL; if (!check_mnt(nd->path.mnt) || !check_mnt(old_nd.path.mnt)) if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) goto out; err = -ENOENT; mutex_lock(&nd->path.dentry->d_inode->i_mutex); if (IS_DEADDIR(nd->path.dentry->d_inode)) mutex_lock(&path->dentry->d_inode->i_mutex); if (IS_DEADDIR(path->dentry->d_inode)) goto out1; if (!IS_ROOT(nd->path.dentry) && d_unhashed(nd->path.dentry)) if (!IS_ROOT(path->dentry) && d_unhashed(path->dentry)) goto out1; err = -EINVAL; if (old_nd.path.dentry != old_nd.path.mnt->mnt_root) if (old_path.dentry != old_path.mnt->mnt_root) goto out1; if (old_nd.path.mnt == old_nd.path.mnt->mnt_parent) if (old_path.mnt == old_path.mnt->mnt_parent) goto out1; if (S_ISDIR(nd->path.dentry->d_inode->i_mode) != S_ISDIR(old_nd.path.dentry->d_inode->i_mode)) if (S_ISDIR(path->dentry->d_inode->i_mode) != S_ISDIR(old_path.dentry->d_inode->i_mode)) goto out1; /* * Don't move a mount residing in a shared parent. */ if (old_nd.path.mnt->mnt_parent && IS_MNT_SHARED(old_nd.path.mnt->mnt_parent)) if (old_path.mnt->mnt_parent && IS_MNT_SHARED(old_path.mnt->mnt_parent)) goto out1; /* * Don't move a mount tree containing unbindable mounts to a destination * mount which is shared. */ if (IS_MNT_SHARED(nd->path.mnt) && tree_contains_unbindable(old_nd.path.mnt)) if (IS_MNT_SHARED(path->mnt) && tree_contains_unbindable(old_path.mnt)) goto out1; err = -ELOOP; for (p = nd->path.mnt; p->mnt_parent != p; p = p->mnt_parent) if (p == old_nd.path.mnt) for (p = path->mnt; p->mnt_parent != p; p = p->mnt_parent) if (p == old_path.mnt) goto out1; err = attach_recursive_mnt(old_nd.path.mnt, &nd->path, &parent_path); err = attach_recursive_mnt(old_path.mnt, path, &parent_path); if (err) goto out1; /* if the mount is moved, it should no longer be expire * automatically */ list_del_init(&old_nd.path.mnt->mnt_expire); list_del_init(&old_path.mnt->mnt_expire); out1: mutex_unlock(&nd->path.dentry->d_inode->i_mutex); mutex_unlock(&path->dentry->d_inode->i_mutex); out: up_write(&namespace_sem); if (!err) path_put(&parent_path); path_put(&old_nd.path); path_put(&old_path); return err; } Loading @@ -1651,7 +1650,7 @@ static noinline int do_move_mount(struct nameidata *nd, char *old_name) * namespace's tree * noinline this do_mount helper to save do_mount stack space. */ static noinline int do_new_mount(struct nameidata *nd, char *type, int flags, static noinline int do_new_mount(struct path *path, char *type, int flags, int mnt_flags, char *name, void *data) { struct vfsmount *mnt; Loading @@ -1667,7 +1666,7 @@ static noinline int do_new_mount(struct nameidata *nd, char *type, int flags, if (IS_ERR(mnt)) return PTR_ERR(mnt); return do_add_mount(mnt, &nd->path, mnt_flags, NULL); return do_add_mount(mnt, path, mnt_flags, NULL); } /* Loading Loading @@ -1902,7 +1901,7 @@ int copy_mount_options(const void __user * data, unsigned long *where) long do_mount(char *dev_name, char *dir_name, char *type_page, unsigned long flags, void *data_page) { struct nameidata nd; struct path path; int retval = 0; int mnt_flags = 0; Loading Loading @@ -1940,29 +1939,29 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT); /* ... and get the mountpoint */ retval = path_lookup(dir_name, LOOKUP_FOLLOW, &nd); retval = kern_path(dir_name, LOOKUP_FOLLOW, &path); if (retval) return retval; retval = security_sb_mount(dev_name, &nd.path, retval = security_sb_mount(dev_name, &path, type_page, flags, data_page); if (retval) goto dput_out; if (flags & MS_REMOUNT) retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags, retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags, data_page); else if (flags & MS_BIND) retval = do_loopback(&nd, dev_name, flags & MS_REC); retval = do_loopback(&path, dev_name, flags & MS_REC); else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) retval = do_change_type(&nd, flags); retval = do_change_type(&path, flags); else if (flags & MS_MOVE) retval = do_move_mount(&nd, dev_name); retval = do_move_mount(&path, dev_name); else retval = do_new_mount(&nd, type_page, flags, mnt_flags, retval = do_new_mount(&path, type_page, flags, mnt_flags, dev_name, data_page); dput_out: path_put(&nd.path); path_put(&path); return retval; } Loading Loading
fs/namespace.c +59 −60 Original line number Diff line number Diff line Loading @@ -1167,19 +1167,19 @@ asmlinkage long sys_oldumount(char __user * name) #endif static int mount_is_safe(struct nameidata *nd) static int mount_is_safe(struct path *path) { if (capable(CAP_SYS_ADMIN)) return 0; return -EPERM; #ifdef notyet if (S_ISLNK(nd->path.dentry->d_inode->i_mode)) if (S_ISLNK(path->dentry->d_inode->i_mode)) return -EPERM; if (nd->path.dentry->d_inode->i_mode & S_ISVTX) { if (current->uid != nd->path.dentry->d_inode->i_uid) if (path->dentry->d_inode->i_mode & S_ISVTX) { if (current->uid != path->dentry->d_inode->i_uid) return -EPERM; } if (vfs_permission(nd, MAY_WRITE)) if (inode_permission(path->dentry->d_inode, MAY_WRITE)) return -EPERM; return 0; #endif Loading Loading @@ -1427,9 +1427,9 @@ static int graft_tree(struct vfsmount *mnt, struct path *path) * recursively change the type of the mountpoint. * noinline this do_mount helper to save do_mount stack space. */ static noinline int do_change_type(struct nameidata *nd, int flag) static noinline int do_change_type(struct path *path, int flag) { struct vfsmount *m, *mnt = nd->path.mnt; struct vfsmount *m, *mnt = path->mnt; int recurse = flag & MS_REC; int type = flag & ~MS_REC; int err = 0; Loading @@ -1437,7 +1437,7 @@ static noinline int do_change_type(struct nameidata *nd, int flag) if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (nd->path.dentry != nd->path.mnt->mnt_root) if (path->dentry != path->mnt->mnt_root) return -EINVAL; down_write(&namespace_sem); Loading @@ -1461,38 +1461,38 @@ static noinline int do_change_type(struct nameidata *nd, int flag) * do loopback mount. * noinline this do_mount helper to save do_mount stack space. */ static noinline int do_loopback(struct nameidata *nd, char *old_name, static noinline int do_loopback(struct path *path, char *old_name, int recurse) { struct nameidata old_nd; struct path old_path; struct vfsmount *mnt = NULL; int err = mount_is_safe(nd); int err = mount_is_safe(path); if (err) return err; if (!old_name || !*old_name) return -EINVAL; err = path_lookup(old_name, LOOKUP_FOLLOW, &old_nd); err = kern_path(old_name, LOOKUP_FOLLOW, &old_path); if (err) return err; down_write(&namespace_sem); err = -EINVAL; if (IS_MNT_UNBINDABLE(old_nd.path.mnt)) if (IS_MNT_UNBINDABLE(old_path.mnt)) goto out; if (!check_mnt(nd->path.mnt) || !check_mnt(old_nd.path.mnt)) if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) goto out; err = -ENOMEM; if (recurse) mnt = copy_tree(old_nd.path.mnt, old_nd.path.dentry, 0); mnt = copy_tree(old_path.mnt, old_path.dentry, 0); else mnt = clone_mnt(old_nd.path.mnt, old_nd.path.dentry, 0); mnt = clone_mnt(old_path.mnt, old_path.dentry, 0); if (!mnt) goto out; err = graft_tree(mnt, &nd->path); err = graft_tree(mnt, path); if (err) { LIST_HEAD(umount_list); spin_lock(&vfsmount_lock); Loading @@ -1503,7 +1503,7 @@ static noinline int do_loopback(struct nameidata *nd, char *old_name, out: up_write(&namespace_sem); path_put(&old_nd.path); path_put(&old_path); return err; } Loading @@ -1530,31 +1530,31 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags) * on it - tough luck. * noinline this do_mount helper to save do_mount stack space. */ static noinline int do_remount(struct nameidata *nd, int flags, int mnt_flags, static noinline int do_remount(struct path *path, int flags, int mnt_flags, void *data) { int err; struct super_block *sb = nd->path.mnt->mnt_sb; struct super_block *sb = path->mnt->mnt_sb; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (!check_mnt(nd->path.mnt)) if (!check_mnt(path->mnt)) return -EINVAL; if (nd->path.dentry != nd->path.mnt->mnt_root) if (path->dentry != path->mnt->mnt_root) return -EINVAL; down_write(&sb->s_umount); if (flags & MS_BIND) err = change_mount_flags(nd->path.mnt, flags); err = change_mount_flags(path->mnt, flags); else err = do_remount_sb(sb, flags, data, 0); if (!err) nd->path.mnt->mnt_flags = mnt_flags; path->mnt->mnt_flags = mnt_flags; up_write(&sb->s_umount); if (!err) security_sb_post_remount(nd->path.mnt, flags, data); security_sb_post_remount(path->mnt, flags, data); return err; } Loading @@ -1571,78 +1571,77 @@ static inline int tree_contains_unbindable(struct vfsmount *mnt) /* * noinline this do_mount helper to save do_mount stack space. */ static noinline int do_move_mount(struct nameidata *nd, char *old_name) static noinline int do_move_mount(struct path *path, char *old_name) { struct nameidata old_nd; struct path parent_path; struct path old_path, parent_path; struct vfsmount *p; int err = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (!old_name || !*old_name) return -EINVAL; err = path_lookup(old_name, LOOKUP_FOLLOW, &old_nd); err = kern_path(old_name, LOOKUP_FOLLOW, &old_path); if (err) return err; down_write(&namespace_sem); while (d_mountpoint(nd->path.dentry) && follow_down(&nd->path.mnt, &nd->path.dentry)) while (d_mountpoint(path->dentry) && follow_down(&path->mnt, &path->dentry)) ; err = -EINVAL; if (!check_mnt(nd->path.mnt) || !check_mnt(old_nd.path.mnt)) if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) goto out; err = -ENOENT; mutex_lock(&nd->path.dentry->d_inode->i_mutex); if (IS_DEADDIR(nd->path.dentry->d_inode)) mutex_lock(&path->dentry->d_inode->i_mutex); if (IS_DEADDIR(path->dentry->d_inode)) goto out1; if (!IS_ROOT(nd->path.dentry) && d_unhashed(nd->path.dentry)) if (!IS_ROOT(path->dentry) && d_unhashed(path->dentry)) goto out1; err = -EINVAL; if (old_nd.path.dentry != old_nd.path.mnt->mnt_root) if (old_path.dentry != old_path.mnt->mnt_root) goto out1; if (old_nd.path.mnt == old_nd.path.mnt->mnt_parent) if (old_path.mnt == old_path.mnt->mnt_parent) goto out1; if (S_ISDIR(nd->path.dentry->d_inode->i_mode) != S_ISDIR(old_nd.path.dentry->d_inode->i_mode)) if (S_ISDIR(path->dentry->d_inode->i_mode) != S_ISDIR(old_path.dentry->d_inode->i_mode)) goto out1; /* * Don't move a mount residing in a shared parent. */ if (old_nd.path.mnt->mnt_parent && IS_MNT_SHARED(old_nd.path.mnt->mnt_parent)) if (old_path.mnt->mnt_parent && IS_MNT_SHARED(old_path.mnt->mnt_parent)) goto out1; /* * Don't move a mount tree containing unbindable mounts to a destination * mount which is shared. */ if (IS_MNT_SHARED(nd->path.mnt) && tree_contains_unbindable(old_nd.path.mnt)) if (IS_MNT_SHARED(path->mnt) && tree_contains_unbindable(old_path.mnt)) goto out1; err = -ELOOP; for (p = nd->path.mnt; p->mnt_parent != p; p = p->mnt_parent) if (p == old_nd.path.mnt) for (p = path->mnt; p->mnt_parent != p; p = p->mnt_parent) if (p == old_path.mnt) goto out1; err = attach_recursive_mnt(old_nd.path.mnt, &nd->path, &parent_path); err = attach_recursive_mnt(old_path.mnt, path, &parent_path); if (err) goto out1; /* if the mount is moved, it should no longer be expire * automatically */ list_del_init(&old_nd.path.mnt->mnt_expire); list_del_init(&old_path.mnt->mnt_expire); out1: mutex_unlock(&nd->path.dentry->d_inode->i_mutex); mutex_unlock(&path->dentry->d_inode->i_mutex); out: up_write(&namespace_sem); if (!err) path_put(&parent_path); path_put(&old_nd.path); path_put(&old_path); return err; } Loading @@ -1651,7 +1650,7 @@ static noinline int do_move_mount(struct nameidata *nd, char *old_name) * namespace's tree * noinline this do_mount helper to save do_mount stack space. */ static noinline int do_new_mount(struct nameidata *nd, char *type, int flags, static noinline int do_new_mount(struct path *path, char *type, int flags, int mnt_flags, char *name, void *data) { struct vfsmount *mnt; Loading @@ -1667,7 +1666,7 @@ static noinline int do_new_mount(struct nameidata *nd, char *type, int flags, if (IS_ERR(mnt)) return PTR_ERR(mnt); return do_add_mount(mnt, &nd->path, mnt_flags, NULL); return do_add_mount(mnt, path, mnt_flags, NULL); } /* Loading Loading @@ -1902,7 +1901,7 @@ int copy_mount_options(const void __user * data, unsigned long *where) long do_mount(char *dev_name, char *dir_name, char *type_page, unsigned long flags, void *data_page) { struct nameidata nd; struct path path; int retval = 0; int mnt_flags = 0; Loading Loading @@ -1940,29 +1939,29 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT); /* ... and get the mountpoint */ retval = path_lookup(dir_name, LOOKUP_FOLLOW, &nd); retval = kern_path(dir_name, LOOKUP_FOLLOW, &path); if (retval) return retval; retval = security_sb_mount(dev_name, &nd.path, retval = security_sb_mount(dev_name, &path, type_page, flags, data_page); if (retval) goto dput_out; if (flags & MS_REMOUNT) retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags, retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags, data_page); else if (flags & MS_BIND) retval = do_loopback(&nd, dev_name, flags & MS_REC); retval = do_loopback(&path, dev_name, flags & MS_REC); else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) retval = do_change_type(&nd, flags); retval = do_change_type(&path, flags); else if (flags & MS_MOVE) retval = do_move_mount(&nd, dev_name); retval = do_move_mount(&path, dev_name); else retval = do_new_mount(&nd, type_page, flags, mnt_flags, retval = do_new_mount(&path, type_page, flags, mnt_flags, dev_name, data_page); dput_out: path_put(&nd.path); path_put(&path); return retval; } Loading