[Devel] [PATCH rh7 v2 2/2] fs: process mount options
Maxim Patlasov
mpatlasov at openvz.org
Fri May 15 10:58:01 PDT 2015
Acked-by: Maxim Patlasov <mpatlasov at openvz.org>
On 05/14/2015 08:49 AM, Kirill Tkhai wrote:
> 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').
>
> Signed-off-by: Kirill Tkhai <ktkhai at odin.com>
> ---
> fs/namespace.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> fs/super.c | 17 ++++++-
> include/linux/fs.h | 2 +
> 3 files changed, 153 insertions(+), 2 deletions(-)
>
> diff --git a/fs/namespace.c b/fs/namespace.c
> index aff3577..0330418 100644
> --- a/fs/namespace.c
> +++ b/fs/namespace.c
> @@ -23,6 +23,7 @@
> #include <linux/uaccess.h>
> #include <linux/proc_ns.h>
> #include <linux/magic.h>
> +#include <linux/ve.h>
> #include "pnode.h"
> #include "internal.h"
>
> @@ -1790,6 +1791,139 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags)
> return error;
> }
>
> +#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;
> +
> + if (!options || !*options)
> + return 0;
> +
> + if (!allowed)
> + return -EPERM;
> +
> + while ((p = strsep(&options, ",")) != NULL) {
> + if (!*p)
> + continue;
> +
> + if (!strstr_separated(allowed, p, ','))
> + return -EPERM;
> + }
> +
> + 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%u: no allowed "
> + "mount options found for device %u:%u\n",
> + ve->veid, 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 do_check_and_remount_sb(struct super_block *sb, int flags, void *data)
> +{
> +#ifdef CONFIG_VE
> + 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 do_remount_sb(sb, flags, data, 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
> @@ -1818,7 +1952,7 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
> else if (!capable(CAP_SYS_ADMIN))
> err = -EPERM;
> else
> - err = do_remount_sb(sb, flags, data, 0);
> + err = do_check_and_remount_sb(sb, flags, data);
> if (!err) {
> br_write_lock(&vfsmount_lock);
> mnt_flags |= mnt->mnt.mnt_flags & MNT_PROPAGATION_MASK;
> diff --git a/fs/super.c b/fs/super.c
> index 5314868..e3ff0bf 100644
> --- a/fs/super.c
> +++ b/fs/super.c
> @@ -1034,11 +1034,26 @@ struct dentry *mount_bdev(struct file_system_type *fs_type,
> down_write(&s->s_umount);
> } else {
> char b[BDEVNAME_SIZE];
> -
> +#ifdef CONFIG_VE
> + void *data_orig = data;
> + struct ve_struct *ve = get_exec_env();
> +
> + if (!ve_is_super(ve)) {
> + error = ve_devmnt_process(ve, bdev->bd_dev, &data, 0);
> + if (error) {
> + deactivate_locked_super(s);
> + goto error;
> + }
> + }
> +#endif
> s->s_mode = mode;
> strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
> sb_set_blocksize(s, block_size(bdev));
> error = fill_super(s, data, flags & MS_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 9efd253..a2044f6 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -2033,6 +2033,8 @@ extern bool our_mnt(struct vfsmount *mnt);
>
> 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 *);
>
>
More information about the Devel
mailing list