From: Kirill Tkhai <ktk...@odin.com> Port patch diff-ve-fs-process-mount-options-check-and-insert by Maxim Patlasov:
The patch implements two kinds of processing mount options: check and insert. Check is OK if and only if each option supplied by CT-user is present among options listed in allowed_options. Insert transforms mount options supplied by CT-user like this: <mount_options> = <hidden_options> + <user_supplied_mount_options> Check is performed both for mount and remount. Insert - only for mount. All this happens only for mount/remount inside CT and if proper ve_devmnt struct is found in ve->devmnt_list (searched by 'dev'). https://jira.sw.ru/browse/PSBM-32273 Signed-off-by: Kirill Tkhai <ktk...@odin.com> Acked-by: Maxim Patlasov <mpatla...@openvz.org> +++ ve/fs/devmnt: allow more than one mount option inside a CT strsep() changes provided string: puts '\0' instead of separators, thus after successful call to ve_devmnt_check() we insert only first provided mount options, ignoring others. mFixes: bc4143b ("ve/fs/devmnt: process mount options") Found during implementation of https://jira.sw.ru/browse/PSBM-40075 Signed-off-by: Konstantin Khorenko <khore...@virtuozzo.com> Reviewed-by: Kirill Tkhai <ktk...@virtuozzo.com> https://jira.sw.ru/browse/PSBM-108196 Signed-off-by: Andrey Ryabinin <aryabi...@virtuozzo.com> +++ ve/devmnt: initialize s_mode before deactivate_locked_super to suppress warning WARNING: CPU: 12 PID: 898592 at fs/super.c:1120 kill_block_super+0x63/0x70 Call Trace: [<ffffffff816a02f8>] dump_stack+0x19/0x1b [<ffffffff81088be8>] __warn+0xd8/0x100 [<ffffffff81088d2d>] warn_slowpath_null+0x1d/0x20 [<ffffffff8121dfa3>] kill_block_super+0x63/0x70 [<ffffffffc04891ec>] ext4_kill_sb+0x4c/0x60 [ext4] [<ffffffff8121e499>] deactivate_locked_super+0x49/0x80 [<ffffffff8121efd7>] mount_bdev+0x227/0x240 [<ffffffffc048f330>] ? ext4_calculate_overhead+0x430/0x430 [ext4] [<ffffffffc0489f34>] ext4_mount+0x44/0x60 [ext4] [<ffffffff8121fb35>] mount_fs+0x15/0xc0 [<ffffffff8123c757>] vfs_kern_mount+0x67/0x110 [<ffffffff8123efb9>] do_mount+0x219/0xae0 [<ffffffff8123fbc6>] SyS_mount+0x96/0xf0 [<ffffffff816b1649>] system_call_fastpath+0x16/0x1b On 3.10.0-693.1.1.vz7.37.30 kernel. We warn on no FMODE_EXCL on super block at kill_block_super. We get there from ve_devmnt_process's error path in mount_bdev, here we have yet uninitialized sb, thus it's s_mode has no FMODE_EXCL. So lets move s_mode initialization before these error path. mFixes: vz7 commit 0759581712eb ("ve/fs/devmnt: process mount options") https://jira.sw.ru/browse/PSBM-80743 Signed-off-by: Pavel Tikhomirov <ptikhomi...@virtuozzo.com> Reviewed-by: Kirill Tkhai <ktk...@virtuozzo.com> (cherry picked from vz7 commit 3543274fc3f1 ("ve/devmnt: initialize s_mode before deactivate_locked_super to suppress warning")) mFixes: vz8 commit b7285b56b1a9 ("ve/fs/devmnt: process mount options") VZ 8 rebase part https://jira.sw.ru/browse/PSBM-127837 Signed-off-by: Alexander Mikhalitsyn <alexander.mikhalit...@virtuozzo.com> (cherry-picked from vz8 commit 511fc2b59027 ("ve/fs/devmnt: process mount options")) Signed-off-by: Nikita Yushchenko <nikita.yushche...@virtuozzo.com> --- fs/namespace.c | 148 +++++++++++++++++++++++++++++++++++++++++++++ fs/super.c | 18 ++++++ include/linux/fs.h | 2 + 3 files changed, 168 insertions(+) diff --git a/fs/namespace.c b/fs/namespace.c index 954238cab6ec..bc2819c49315 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2625,6 +2625,149 @@ static int do_reconfigure_mnt(struct path *path, unsigned int mnt_flags) return ret; } +#ifdef CONFIG_VE +/* + * Returns first occurrence of needle in haystack separated by sep, + * or NULL if not found + */ +static char *strstr_separated(char *haystack, char *needle, char sep) +{ + int needle_len = strlen(needle); + + while (haystack) { + if (!strncmp(haystack, needle, needle_len) && + (haystack[needle_len] == 0 || /* end-of-line or */ + haystack[needle_len] == sep)) /* separator */ + return haystack; + + haystack = strchr(haystack, sep); + if (haystack) + haystack++; + } + + return NULL; +} + +static int ve_devmnt_check(char *options, char *allowed) +{ + char *p; + char *tmp_options; + + if (!options || !*options) + return 0; + + if (!allowed) + return -EPERM; + + /* strsep() changes provided string: puts '\0' instead of separators */ + tmp_options = kstrdup(options, GFP_KERNEL); + if (!tmp_options) + return -ENOMEM; + + while ((p = strsep(&tmp_options, ",")) != NULL) { + if (!*p) + continue; + + if (!strstr_separated(allowed, p, ',')) { + kfree(tmp_options); + return -EPERM; + } + } + + kfree(tmp_options); + return 0; +} + +static int ve_devmnt_insert(char *options, char *hidden) +{ + int options_len; + int hidden_len; + + if (!hidden) + return 0; + + if (!options) + return -EAGAIN; + + options_len = strlen(options); + hidden_len = strlen(hidden); + + if (hidden_len + options_len + 2 > PAGE_SIZE) + return -EPERM; + + memmove(options + hidden_len + 1, options, options_len); + memcpy(options, hidden, hidden_len); + + options[hidden_len] = ','; + options[hidden_len + options_len + 1] = 0; + + return 0; +} + +int ve_devmnt_process(struct ve_struct *ve, dev_t dev, void **data_pp, int remount) +{ + void *data = *data_pp; + struct ve_devmnt *devmnt; + int err; +again: + err = 1; + mutex_lock(&ve->devmnt_mutex); + list_for_each_entry(devmnt, &ve->devmnt_list, link) { + if (devmnt->dev == dev) { + err = ve_devmnt_check(data, devmnt->allowed_options); + + if (!err && !remount) + err = ve_devmnt_insert(data, devmnt->hidden_options); + + break; + } + } + mutex_unlock(&ve->devmnt_mutex); + + switch (err) { + case -EAGAIN: + if (!(data = (void *)__get_free_page(GFP_KERNEL))) + return -ENOMEM; + *(char *)data = 0; /* the string must be zero-terminated */ + goto again; + case 1: + if (*data_pp) { + ve_printk(VE_LOG_BOTH, KERN_WARNING "VE%s: no allowed " + "mount options found for device %u:%u\n", + ve->ve_name, MAJOR(dev), MINOR(dev)); + err = -EPERM; + } else + err = 0; + break; + case 0: + *data_pp = data; + break; + } + + if (data && data != *data_pp) + free_page((unsigned long)data); + + return err; +} +#endif + +static int ve_prepare_mount_options(struct fs_context *fc, void *data) +{ +#ifdef CONFIG_VE + struct super_block *sb = fc->root->d_sb; + struct ve_struct *ve = get_exec_env(); + + if (sb->s_bdev && data && !ve_is_super(ve)) { + int err; + + err = ve_devmnt_process(ve, sb->s_bdev->bd_dev, &data, 1); + if (err) + return err; + } +#endif + return 0; +} + /* * change filesystem flags. dir should be a physical root of filesystem. * If you've mounted a non-root directory somewhere and want to do remount @@ -2652,6 +2795,11 @@ static int do_remount(struct path *path, int ms_flags, int sb_flags, return PTR_ERR(fc); fc->oldapi = true; + err = ve_prepare_mount_options(fc, data); + if (err) { + put_fs_context(fc); + return err; + } err = parse_monolithic_mount_data(fc, data); if (!err) { down_write(&sb->s_umount); diff --git a/fs/super.c b/fs/super.c index f40b431420f7..9fbb8d6f0628 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1390,10 +1390,28 @@ struct dentry *mount_bdev(struct file_system_type *fs_type, blkdev_put(bdev, mode); down_write(&s->s_umount); } else { +#ifdef CONFIG_VE + void *data_orig = data; + struct ve_struct *ve = get_exec_env(); +#endif + s->s_mode = mode; +#ifdef CONFIG_VE + if (!ve_is_super(ve)) { + error = ve_devmnt_process(ve, bdev->bd_dev, &data, 0); + if (error) { + deactivate_locked_super(s); + goto error; + } + } +#endif snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev); sb_set_blocksize(s, block_size(bdev)); error = fill_super(s, data, flags & SB_SILENT ? 1 : 0); +#ifdef CONFIG_VE + if (data_orig != data) + free_page((unsigned long)data); +#endif if (error) { deactivate_locked_super(s); goto error; diff --git a/include/linux/fs.h b/include/linux/fs.h index 8d86a85187ae..f4f31c29259f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2569,6 +2569,8 @@ extern int super_setup_bdi(struct super_block *sb); extern int current_umask(void); +extern int ve_devmnt_process(struct ve_struct *, dev_t, void **, int); + extern void ihold(struct inode * inode); extern void iput(struct inode *); extern int generic_update_time(struct inode *, struct timespec64 *, int); -- 2.30.2 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel