Message ID | 20210405164603.281189-1-brauner@kernel.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | cachefiles: use private mounts in cache->mnt | expand |
Christian Brauner <brauner@kernel.org> wrote: > Besides that - and probably irrelevant from the perspective of a > cachefiles developer - it also makes things simpler for a variety of > other vfs features. One concrete example is fanotify. What about cachefilesd? That walks over the tree regularly, stats things and maybe deletes things. Should that be in a private mount/namespace too? > This seems a rather desirable property as the underlying path can't e.g. > suddenly go from read-write to read-only and in general it means that > cachefiles is always in full control of the underlying mount after the > user has allowed it to be used as a cache. That's not entirely true, but I guess that emergency R/O conversion isn't a case that's worrisome - and, in any case, only affects the superblock. > ret = -EINVAL; > - if (mnt_user_ns(path.mnt) != &init_user_ns) { > + if (mnt_user_ns(cache->mnt) != &init_user_ns) { > pr_warn("File cache on idmapped mounts not supported"); > goto error_unsupported; > } Is it worth doing this check before calling clone_private_mount()? > + cache_path = path; > + cache_path.mnt = cache->mnt; Seems pointless to copy all of path into cache_path rather than just path.dentry. Apart from that, looks okay. David
On Tue, Apr 06, 2021 at 10:12:25AM +0100, David Howells wrote: > Christian Brauner <brauner@kernel.org> wrote: > > > Besides that - and probably irrelevant from the perspective of a > > cachefiles developer - it also makes things simpler for a variety of > > other vfs features. One concrete example is fanotify. > > What about cachefilesd? That walks over the tree regularly, stats things and > maybe deletes things. Should that be in a private mount/namespace too? You mean running the userspace cachefilesd daemon in a separate mount namespace? I think that would make a lot of sense. Either the daemon could manage a separate private mount namespace itself or if you support systemd service files you could set: PrivateMounts=yes in the service file which: "Takes a boolean parameter. If set, the processes of this unit will be run in their own private file system (mount) namespace with all mount propagation from the processes towards the host's main file system namespace turned off. This means any file system mount points established or removed by the unit's processes will be private to them and not be visible to the host." (Fwiw, Debian still ships /etc/init.d/cachefilesd which seems a bit antique imho.) > > > This seems a rather desirable property as the underlying path can't e.g. > > suddenly go from read-write to read-only and in general it means that > > cachefiles is always in full control of the underlying mount after the > > user has allowed it to be used as a cache. > > That's not entirely true, but I guess that emergency R/O conversion isn't a > case that's worrisome - and, in any case, only affects the superblock. > > > ret = -EINVAL; > > - if (mnt_user_ns(path.mnt) != &init_user_ns) { > > + if (mnt_user_ns(cache->mnt) != &init_user_ns) { > > pr_warn("File cache on idmapped mounts not supported"); > > goto error_unsupported; > > } > > Is it worth doing this check before calling clone_private_mount()? Yes, it's safe to do that. It's just my paranoia that made me write it this way. In order to create an idmapped mount real_mount(&path->mnt)->mnt_ns->seq must be 0, i.e. an anonymous mount which can't be found through the fileystem. So in order for path->mnt to be idmapped it must be already attached to the fileystem and we don't allow mnt_userns to change (for good reasons). > > > + cache_path = path; > > + cache_path.mnt = cache->mnt; > > Seems pointless to copy all of path into cache_path rather than just > path.dentry. Sure, will change to: cache_path.dentry = path.dentry; cache_path.mnt = cache->mnt; Christian
diff --git a/fs/cachefiles/bind.c b/fs/cachefiles/bind.c index 38bb7764b454..ac03af93437b 100644 --- a/fs/cachefiles/bind.c +++ b/fs/cachefiles/bind.c @@ -81,7 +81,7 @@ int cachefiles_daemon_bind(struct cachefiles_cache *cache, char *args) static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache) { struct cachefiles_object *fsdef; - struct path path; + struct path path, cache_path; struct kstatfs stats; struct dentry *graveyard, *cachedir, *root; const struct cred *saved_cred; @@ -115,16 +115,22 @@ static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache) if (ret < 0) goto error_open_root; - cache->mnt = path.mnt; - root = path.dentry; + cache->mnt = clone_private_mount(&path); + if (IS_ERR(cache->mnt)) { + ret = PTR_ERR(cache->mnt); + cache->mnt = NULL; + pr_warn("Failed to create private mount for file cache\n"); + goto error_unsupported; + } ret = -EINVAL; - if (mnt_user_ns(path.mnt) != &init_user_ns) { + if (mnt_user_ns(cache->mnt) != &init_user_ns) { pr_warn("File cache on idmapped mounts not supported"); goto error_unsupported; } /* check parameters */ + root = path.dentry; ret = -EOPNOTSUPP; if (d_is_negative(root) || !d_backing_inode(root)->i_op->lookup || @@ -144,8 +150,10 @@ static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache) if (ret < 0) goto error_unsupported; + cache_path = path; + cache_path.mnt = cache->mnt; /* get the cache size and blocksize */ - ret = vfs_statfs(&path, &stats); + ret = vfs_statfs(&cache_path, &stats); if (ret < 0) goto error_unsupported; @@ -229,7 +237,12 @@ static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache) /* done */ set_bit(CACHEFILES_READY, &cache->flags); - dput(root); + + /* + * We've created a private mount and we've stashed our "cache" and + * "graveyard" dentries so we don't need the path anymore. + */ + path_put(&path); pr_info("File cache on %s registered\n", cache->cache.identifier); @@ -242,11 +255,11 @@ static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache) dput(cache->graveyard); cache->graveyard = NULL; error_unsupported: + path_put(&path); mntput(cache->mnt); cache->mnt = NULL; dput(fsdef->dentry); fsdef->dentry = NULL; - dput(root); error_open_root: kmem_cache_free(cachefiles_object_jar, fsdef); error_root_object: