[Devel] [PATCH v7 VZ10] fs: enforce container device-mount policy in the common mount path
Konstantin Khorenko
khorenko at virtuozzo.com
Fri Jul 31 17:31:35 MSK 2026
Problem: a trap on the legacy mount path.
For filesystems still on the legacy API the two halves of the devmnt
policy no longer meet. Here is the whole picture as a call stack:
do_new_mount()
parse_monolithic_mount_data(fc, data)
legacy_parse_monolithic()
/*
* Legacy fs: the option string is only stashed away into
* ctx->legacy_data for the fs to parse later. Unlike
* generic_parse_monolithic() -> vfs_parse_monolithic_sep(),
* neither ve_devmnt_process() runs here nor is
* fc->ve_final_opts populated - it stays NULL.
*/
vfs_get_tree(fc)
fc->ops->get_tree(fc) /* legacy_get_tree() */
fc->fs_type->mount() /* e.g. ext2_mount() */
mount_bdev()
ve_devmnt_process(ve, dev, &data, 0) /* fs/super.c:1767 */
/*
* The "old" enforcement: allowed_options are checked
* and hidden_options are inserted into @data...
*/
fill_super(s, data, ...)
/*
* ...and the fs does parse them. So far so good.
*/
ve_devmnt_verify_fc(fc, true) /* fs/super.c:1933 */
/*
* The "new" enforcement. It builds the option string to vet
* from fc->ve_final_opts plus the synthesized ro/rw flag
* token. ve_final_opts is NULL on this path (see above), so
* opts ends up being just "rw".
*/
ve_devmnt_verify(ve, dev, opts = "rw", new_mount = true, ...)
ve_devmnt_options_subset(hidden, opts, NULL)
/*
* On a new mount every hidden option must be present in
* opts: hidden = "balloon_ino=42" vs opts = "rw" ->
* -EPERM. The mount is refused even though mount_bdev()
* inserted the hidden options and the fs consumed them
* just fine. Any listed device with non-empty
* hidden_options is unmountable through a legacy fs,
* unconditionally.
*/
In practice this looks unreachable today: every FS_VIRTUALIZED
block-device filesystem in 6.12 has been converted to fs_context,
and the typical hidden options (e.g. balloon_ino=...) target ext4,
which is on the new API. But if a legacy filesystem ever ends up in
the VE whitelist, this will be painful to debug: the mount fails with
a ratelimited "mount options not permitted" message that points at
the options, while the actual culprit is the missing ve_final_opts
stash on this path.
At a minimum, please add a comment at the mount_bdev() hook stating
that the ve_devmnt policy verification in vfs_get_tree() will refuse
any listed device with hidden_options mounted through this path.
Alternatively, declare the legacy path unsupported and drop the hook
there altogether, so the failure mode is explicit rather than
accidental.
#########################################
On 7/23/26 15:49, Vasileios Almpanis wrote:
...
> diff --git a/fs/internal.h b/fs/internal.h
> index 3647ce69b2c7..e33d3ae70cce 100644
> --- a/fs/internal.h
> +++ b/fs/internal.h
> @@ -46,6 +46,7 @@ extern void __init chrdev_init(void);
> */
> extern const struct fs_context_operations legacy_fs_context_ops;
> extern int parse_monolithic_mount_data(struct fs_context *, void *);
> +extern int ve_devmnt_verify_fc(struct fs_context *fc, bool new_mount);
+#ifdef CONFIG_VE
+extern int ve_devmnt_verify_fc(struct fs_context *fc, bool new_mount);
+#else
+static inline int ve_devmnt_verify_fc(struct fs_context *fc, bool new_mount)
+{
+ return 0;
+}
+#endif
> extern void vfs_clean_context(struct fs_context *fc);
> extern int finish_clean_context(struct fs_context *fc);
>
More information about the Devel
mailing list