Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

get rid of unprotected dereferencing of mnt->mnt_ns

It's safe only under namespace_sem or vfsmount_lock; all places
in fs/namespace.c that want mnt->mnt_ns->user_ns actually want to use
current->nsproxy->mnt_ns->user_ns (note the calls of check_mnt() in
there).

Cc: stable@vger.kernel.org
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Al Viro 9b40bc90 3a142ed9

+17 -12
+17 -12
fs/namespace.c
··· 1237 1237 return retval; 1238 1238 } 1239 1239 1240 + /* 1241 + * Is the caller allowed to modify his namespace? 1242 + */ 1243 + static inline bool may_mount(void) 1244 + { 1245 + return ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN); 1246 + } 1247 + 1240 1248 /* 1241 1249 * Now umount can handle mount points as well as block devices. 1242 1250 * This is important for filesystems which use unnamed block devices. ··· 1263 1255 if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW)) 1264 1256 return -EINVAL; 1265 1257 1258 + if (!may_mount()) 1259 + return -EPERM; 1260 + 1266 1261 if (!(flags & UMOUNT_NOFOLLOW)) 1267 1262 lookup_flags |= LOOKUP_FOLLOW; 1268 1263 ··· 1277 1266 if (path.dentry != path.mnt->mnt_root) 1278 1267 goto dput_and_out; 1279 1268 if (!check_mnt(mnt)) 1280 - goto dput_and_out; 1281 - 1282 - retval = -EPERM; 1283 - if (!ns_capable(mnt->mnt_ns->user_ns, CAP_SYS_ADMIN)) 1284 1269 goto dput_and_out; 1285 1270 1286 1271 retval = do_umount(mnt, flags); ··· 1302 1295 1303 1296 static int mount_is_safe(struct path *path) 1304 1297 { 1305 - if (ns_capable(real_mount(path->mnt)->mnt_ns->user_ns, CAP_SYS_ADMIN)) 1298 + if (may_mount()) 1306 1299 return 0; 1307 1300 return -EPERM; 1308 1301 #ifdef notyet ··· 1640 1633 int type; 1641 1634 int err = 0; 1642 1635 1643 - if (!ns_capable(mnt->mnt_ns->user_ns, CAP_SYS_ADMIN)) 1636 + if (!may_mount()) 1644 1637 return -EPERM; 1645 1638 1646 1639 if (path->dentry != path->mnt->mnt_root) ··· 1804 1797 struct mount *p; 1805 1798 struct mount *old; 1806 1799 int err = 0; 1807 - if (!ns_capable(real_mount(path->mnt)->mnt_ns->user_ns, CAP_SYS_ADMIN)) 1800 + if (!may_mount()) 1808 1801 return -EPERM; 1809 1802 if (!old_name || !*old_name) 1810 1803 return -EINVAL; ··· 1940 1933 int mnt_flags, const char *name, void *data) 1941 1934 { 1942 1935 struct file_system_type *type; 1943 - struct user_namespace *user_ns; 1936 + struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns; 1944 1937 struct vfsmount *mnt; 1945 1938 int err; 1946 1939 1947 1940 if (!fstype) 1948 1941 return -EINVAL; 1949 1942 1950 - /* we need capabilities... */ 1951 - user_ns = real_mount(path->mnt)->mnt_ns->user_ns; 1952 - if (!ns_capable(user_ns, CAP_SYS_ADMIN)) 1943 + if (!may_mount()) 1953 1944 return -EPERM; 1954 1945 1955 1946 type = get_fs_type(fstype); ··· 2572 2567 struct mount *new_mnt, *root_mnt; 2573 2568 int error; 2574 2569 2575 - if (!ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN)) 2570 + if (!may_mount()) 2576 2571 return -EPERM; 2577 2572 2578 2573 error = user_path_dir(new_root, &new);