2020#include <linux/init.h> /* init_rootfs */
2121#include <linux/fs_struct.h> /* get_fs_root et.al. */
2222#include <linux/fsnotify.h> /* fsnotify_vfsmount_delete */
23+ #include <linux/file.h>
2324#include <linux/uaccess.h>
2425#include <linux/proc_ns.h>
2526#include <linux/magic.h>
@@ -1832,6 +1833,21 @@ struct vfsmount *collect_mounts(const struct path *path)
18321833 return & tree -> mnt ;
18331834}
18341835
1836+ static void free_mnt_ns (struct mnt_namespace * );
1837+ static struct mnt_namespace * alloc_mnt_ns (struct user_namespace * , bool );
1838+
1839+ void dissolve_on_fput (struct vfsmount * mnt )
1840+ {
1841+ struct mnt_namespace * ns ;
1842+ namespace_lock ();
1843+ lock_mount_hash ();
1844+ ns = real_mount (mnt )-> mnt_ns ;
1845+ umount_tree (real_mount (mnt ), UMOUNT_CONNECTED );
1846+ unlock_mount_hash ();
1847+ namespace_unlock ();
1848+ free_mnt_ns (ns );
1849+ }
1850+
18351851void drop_collected_mounts (struct vfsmount * mnt )
18361852{
18371853 namespace_lock ();
@@ -2222,14 +2238,38 @@ static bool has_locked_children(struct mount *mnt, struct dentry *dentry)
22222238 return false;
22232239}
22242240
2241+ static struct mount * __do_loopback (struct path * old_path , int recurse )
2242+ {
2243+ struct mount * mnt = ERR_PTR (- EINVAL ), * old = real_mount (old_path -> mnt );
2244+
2245+ if (IS_MNT_UNBINDABLE (old ))
2246+ return mnt ;
2247+
2248+ if (!check_mnt (old ) && old_path -> dentry -> d_op != & ns_dentry_operations )
2249+ return mnt ;
2250+
2251+ if (!recurse && has_locked_children (old , old_path -> dentry ))
2252+ return mnt ;
2253+
2254+ if (recurse )
2255+ mnt = copy_tree (old , old_path -> dentry , CL_COPY_MNT_NS_FILE );
2256+ else
2257+ mnt = clone_mnt (old , old_path -> dentry , 0 );
2258+
2259+ if (!IS_ERR (mnt ))
2260+ mnt -> mnt .mnt_flags &= ~MNT_LOCKED ;
2261+
2262+ return mnt ;
2263+ }
2264+
22252265/*
22262266 * do loopback mount.
22272267 */
22282268static int do_loopback (struct path * path , const char * old_name ,
22292269 int recurse )
22302270{
22312271 struct path old_path ;
2232- struct mount * mnt = NULL , * old , * parent ;
2272+ struct mount * mnt = NULL , * parent ;
22332273 struct mountpoint * mp ;
22342274 int err ;
22352275 if (!old_name || !* old_name )
@@ -2243,38 +2283,21 @@ static int do_loopback(struct path *path, const char *old_name,
22432283 goto out ;
22442284
22452285 mp = lock_mount (path );
2246- err = PTR_ERR ( mp );
2247- if ( IS_ERR ( mp ))
2286+ if ( IS_ERR ( mp )) {
2287+ err = PTR_ERR ( mp );
22482288 goto out ;
2289+ }
22492290
2250- old = real_mount (old_path .mnt );
22512291 parent = real_mount (path -> mnt );
2252-
2253- err = - EINVAL ;
2254- if (IS_MNT_UNBINDABLE (old ))
2255- goto out2 ;
2256-
22572292 if (!check_mnt (parent ))
22582293 goto out2 ;
22592294
2260- if (!check_mnt (old ) && old_path .dentry -> d_op != & ns_dentry_operations )
2261- goto out2 ;
2262-
2263- if (!recurse && has_locked_children (old , old_path .dentry ))
2264- goto out2 ;
2265-
2266- if (recurse )
2267- mnt = copy_tree (old , old_path .dentry , CL_COPY_MNT_NS_FILE );
2268- else
2269- mnt = clone_mnt (old , old_path .dentry , 0 );
2270-
2295+ mnt = __do_loopback (& old_path , recurse );
22712296 if (IS_ERR (mnt )) {
22722297 err = PTR_ERR (mnt );
22732298 goto out2 ;
22742299 }
22752300
2276- mnt -> mnt .mnt_flags &= ~MNT_LOCKED ;
2277-
22782301 err = graft_tree (mnt , parent , mp );
22792302 if (err ) {
22802303 lock_mount_hash ();
@@ -2288,6 +2311,96 @@ static int do_loopback(struct path *path, const char *old_name,
22882311 return err ;
22892312}
22902313
2314+ static struct file * open_detached_copy (struct path * path , bool recursive )
2315+ {
2316+ struct user_namespace * user_ns = current -> nsproxy -> mnt_ns -> user_ns ;
2317+ struct mnt_namespace * ns = alloc_mnt_ns (user_ns , true);
2318+ struct mount * mnt , * p ;
2319+ struct file * file ;
2320+
2321+ if (IS_ERR (ns ))
2322+ return ERR_CAST (ns );
2323+
2324+ namespace_lock ();
2325+ mnt = __do_loopback (path , recursive );
2326+ if (IS_ERR (mnt )) {
2327+ namespace_unlock ();
2328+ free_mnt_ns (ns );
2329+ return ERR_CAST (mnt );
2330+ }
2331+
2332+ lock_mount_hash ();
2333+ for (p = mnt ; p ; p = next_mnt (p , mnt )) {
2334+ p -> mnt_ns = ns ;
2335+ ns -> mounts ++ ;
2336+ }
2337+ ns -> root = mnt ;
2338+ list_add_tail (& ns -> list , & mnt -> mnt_list );
2339+ mntget (& mnt -> mnt );
2340+ unlock_mount_hash ();
2341+ namespace_unlock ();
2342+
2343+ mntput (path -> mnt );
2344+ path -> mnt = & mnt -> mnt ;
2345+ file = dentry_open (path , O_PATH , current_cred ());
2346+ if (IS_ERR (file ))
2347+ dissolve_on_fput (path -> mnt );
2348+ else
2349+ file -> f_mode |= FMODE_NEED_UNMOUNT ;
2350+ return file ;
2351+ }
2352+
2353+ SYSCALL_DEFINE3 (open_tree , int , dfd , const char * , filename , unsigned , flags )
2354+ {
2355+ struct file * file ;
2356+ struct path path ;
2357+ int lookup_flags = LOOKUP_AUTOMOUNT | LOOKUP_FOLLOW ;
2358+ bool detached = flags & OPEN_TREE_CLONE ;
2359+ int error ;
2360+ int fd ;
2361+
2362+ BUILD_BUG_ON (OPEN_TREE_CLOEXEC != O_CLOEXEC );
2363+
2364+ if (flags & ~(AT_EMPTY_PATH | AT_NO_AUTOMOUNT | AT_RECURSIVE |
2365+ AT_SYMLINK_NOFOLLOW | OPEN_TREE_CLONE |
2366+ OPEN_TREE_CLOEXEC ))
2367+ return - EINVAL ;
2368+
2369+ if ((flags & (AT_RECURSIVE | OPEN_TREE_CLONE )) == AT_RECURSIVE )
2370+ return - EINVAL ;
2371+
2372+ if (flags & AT_NO_AUTOMOUNT )
2373+ lookup_flags &= ~LOOKUP_AUTOMOUNT ;
2374+ if (flags & AT_SYMLINK_NOFOLLOW )
2375+ lookup_flags &= ~LOOKUP_FOLLOW ;
2376+ if (flags & AT_EMPTY_PATH )
2377+ lookup_flags |= LOOKUP_EMPTY ;
2378+
2379+ if (detached && !may_mount ())
2380+ return - EPERM ;
2381+
2382+ fd = get_unused_fd_flags (flags & O_CLOEXEC );
2383+ if (fd < 0 )
2384+ return fd ;
2385+
2386+ error = user_path_at (dfd , filename , lookup_flags , & path );
2387+ if (unlikely (error )) {
2388+ file = ERR_PTR (error );
2389+ } else {
2390+ if (detached )
2391+ file = open_detached_copy (& path , flags & AT_RECURSIVE );
2392+ else
2393+ file = dentry_open (& path , O_PATH , current_cred ());
2394+ path_put (& path );
2395+ }
2396+ if (IS_ERR (file )) {
2397+ put_unused_fd (fd );
2398+ return PTR_ERR (file );
2399+ }
2400+ fd_install (fd , file );
2401+ return fd ;
2402+ }
2403+
22912404/*
22922405 * Don't allow locked mount flags to be cleared.
22932406 *
0 commit comments