LCOV - code coverage report
Current view: top level - fs - fs_context.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 84 275 30.5 %
Date: 2023-08-24 13:40:31 Functions: 10 24 41.7 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /* Provide a way to create a superblock configuration context within the kernel
       3             :  * that allows a superblock to be set up prior to mounting.
       4             :  *
       5             :  * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
       6             :  * Written by David Howells (dhowells@redhat.com)
       7             :  */
       8             : 
       9             : #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      10             : #include <linux/module.h>
      11             : #include <linux/fs_context.h>
      12             : #include <linux/fs_parser.h>
      13             : #include <linux/fs.h>
      14             : #include <linux/mount.h>
      15             : #include <linux/nsproxy.h>
      16             : #include <linux/slab.h>
      17             : #include <linux/magic.h>
      18             : #include <linux/security.h>
      19             : #include <linux/mnt_namespace.h>
      20             : #include <linux/pid_namespace.h>
      21             : #include <linux/user_namespace.h>
      22             : #include <net/net_namespace.h>
      23             : #include <asm/sections.h>
      24             : #include "mount.h"
      25             : #include "internal.h"
      26             : 
      27             : enum legacy_fs_param {
      28             :         LEGACY_FS_UNSET_PARAMS,
      29             :         LEGACY_FS_MONOLITHIC_PARAMS,
      30             :         LEGACY_FS_INDIVIDUAL_PARAMS,
      31             : };
      32             : 
      33             : struct legacy_fs_context {
      34             :         char                    *legacy_data;   /* Data page for legacy filesystems */
      35             :         size_t                  data_size;
      36             :         enum legacy_fs_param    param_type;
      37             : };
      38             : 
      39             : static int legacy_init_fs_context(struct fs_context *fc);
      40             : 
      41             : static const struct constant_table common_set_sb_flag[] = {
      42             :         { "dirsync",  SB_DIRSYNC },
      43             :         { "lazytime", SB_LAZYTIME },
      44             :         { "mand",     SB_MANDLOCK },
      45             :         { "ro",               SB_RDONLY },
      46             :         { "sync",     SB_SYNCHRONOUS },
      47             :         { },
      48             : };
      49             : 
      50             : static const struct constant_table common_clear_sb_flag[] = {
      51             :         { "async",    SB_SYNCHRONOUS },
      52             :         { "nolazytime",       SB_LAZYTIME },
      53             :         { "nomand",   SB_MANDLOCK },
      54             :         { "rw",               SB_RDONLY },
      55             :         { },
      56             : };
      57             : 
      58             : /*
      59             :  * Check for a common mount option that manipulates s_flags.
      60             :  */
      61          15 : static int vfs_parse_sb_flag(struct fs_context *fc, const char *key)
      62             : {
      63             :         unsigned int token;
      64             : 
      65          15 :         token = lookup_constant(common_set_sb_flag, key, 0);
      66          15 :         if (token) {
      67           0 :                 fc->sb_flags |= token;
      68           0 :                 fc->sb_flags_mask |= token;
      69             :                 return 0;
      70             :         }
      71             : 
      72          15 :         token = lookup_constant(common_clear_sb_flag, key, 0);
      73          15 :         if (token) {
      74           0 :                 fc->sb_flags &= ~token;
      75           0 :                 fc->sb_flags_mask |= token;
      76             :                 return 0;
      77             :         }
      78             : 
      79             :         return -ENOPARAM;
      80             : }
      81             : 
      82             : /**
      83             :  * vfs_parse_fs_param_source - Handle setting "source" via parameter
      84             :  * @fc: The filesystem context to modify
      85             :  * @param: The parameter
      86             :  *
      87             :  * This is a simple helper for filesystems to verify that the "source" they
      88             :  * accept is sane.
      89             :  *
      90             :  * Returns 0 on success, -ENOPARAM if this is not  "source" parameter, and
      91             :  * -EINVAL otherwise. In the event of failure, supplementary error information
      92             :  *  is logged.
      93             :  */
      94          15 : int vfs_parse_fs_param_source(struct fs_context *fc, struct fs_parameter *param)
      95             : {
      96          15 :         if (strcmp(param->key, "source") != 0)
      97             :                 return -ENOPARAM;
      98             : 
      99          15 :         if (param->type != fs_value_is_string)
     100           0 :                 return invalf(fc, "Non-string source");
     101             : 
     102          15 :         if (fc->source)
     103           0 :                 return invalf(fc, "Multiple sources");
     104             : 
     105          15 :         fc->source = param->string;
     106          15 :         param->string = NULL;
     107          15 :         return 0;
     108             : }
     109             : EXPORT_SYMBOL(vfs_parse_fs_param_source);
     110             : 
     111             : /**
     112             :  * vfs_parse_fs_param - Add a single parameter to a superblock config
     113             :  * @fc: The filesystem context to modify
     114             :  * @param: The parameter
     115             :  *
     116             :  * A single mount option in string form is applied to the filesystem context
     117             :  * being set up.  Certain standard options (for example "ro") are translated
     118             :  * into flag bits without going to the filesystem.  The active security module
     119             :  * is allowed to observe and poach options.  Any other options are passed over
     120             :  * to the filesystem to parse.
     121             :  *
     122             :  * This may be called multiple times for a context.
     123             :  *
     124             :  * Returns 0 on success and a negative error code on failure.  In the event of
     125             :  * failure, supplementary error information may have been set.
     126             :  */
     127          15 : int vfs_parse_fs_param(struct fs_context *fc, struct fs_parameter *param)
     128             : {
     129             :         int ret;
     130             : 
     131          15 :         if (!param->key)
     132           0 :                 return invalf(fc, "Unnamed parameter\n");
     133             : 
     134          15 :         ret = vfs_parse_sb_flag(fc, param->key);
     135          15 :         if (ret != -ENOPARAM)
     136             :                 return ret;
     137             : 
     138          15 :         ret = security_fs_context_parse_param(fc, param);
     139             :         if (ret != -ENOPARAM)
     140             :                 /* Param belongs to the LSM or is disallowed by the LSM; so
     141             :                  * don't pass to the FS.
     142             :                  */
     143             :                 return ret;
     144             : 
     145          15 :         if (fc->ops->parse_param) {
     146           2 :                 ret = fc->ops->parse_param(fc, param);
     147           2 :                 if (ret != -ENOPARAM)
     148             :                         return ret;
     149             :         }
     150             : 
     151             :         /* If the filesystem doesn't take any arguments, give it the
     152             :          * default handling of source.
     153             :          */
     154          14 :         ret = vfs_parse_fs_param_source(fc, param);
     155          14 :         if (ret != -ENOPARAM)
     156             :                 return ret;
     157             : 
     158           0 :         return invalf(fc, "%s: Unknown parameter '%s'",
     159             :                       fc->fs_type->name, param->key);
     160             : }
     161             : EXPORT_SYMBOL(vfs_parse_fs_param);
     162             : 
     163             : /**
     164             :  * vfs_parse_fs_string - Convenience function to just parse a string.
     165             :  */
     166          15 : int vfs_parse_fs_string(struct fs_context *fc, const char *key,
     167             :                         const char *value, size_t v_size)
     168             : {
     169             :         int ret;
     170             : 
     171          15 :         struct fs_parameter param = {
     172             :                 .key    = key,
     173             :                 .type   = fs_value_is_flag,
     174             :                 .size   = v_size,
     175             :         };
     176             : 
     177          15 :         if (value) {
     178          15 :                 param.string = kmemdup_nul(value, v_size, GFP_KERNEL);
     179          15 :                 if (!param.string)
     180             :                         return -ENOMEM;
     181          15 :                 param.type = fs_value_is_string;
     182             :         }
     183             : 
     184          15 :         ret = vfs_parse_fs_param(fc, &param);
     185          15 :         kfree(param.string);
     186          15 :         return ret;
     187             : }
     188             : EXPORT_SYMBOL(vfs_parse_fs_string);
     189             : 
     190             : /**
     191             :  * generic_parse_monolithic - Parse key[=val][,key[=val]]* mount data
     192             :  * @ctx: The superblock configuration to fill in.
     193             :  * @data: The data to parse
     194             :  *
     195             :  * Parse a blob of data that's in key[=val][,key[=val]]* form.  This can be
     196             :  * called from the ->monolithic_mount_data() fs_context operation.
     197             :  *
     198             :  * Returns 0 on success or the error returned by the ->parse_option() fs_context
     199             :  * operation on failure.
     200             :  */
     201          15 : int generic_parse_monolithic(struct fs_context *fc, void *data)
     202             : {
     203          15 :         char *options = data, *key;
     204          15 :         int ret = 0;
     205             : 
     206          15 :         if (!options)
     207             :                 return 0;
     208             : 
     209             :         ret = security_sb_eat_lsm_opts(options, &fc->security);
     210             :         if (ret)
     211             :                 return ret;
     212             : 
     213           0 :         while ((key = strsep(&options, ",")) != NULL) {
     214           0 :                 if (*key) {
     215           0 :                         size_t v_len = 0;
     216           0 :                         char *value = strchr(key, '=');
     217             : 
     218           0 :                         if (value) {
     219           0 :                                 if (value == key)
     220           0 :                                         continue;
     221           0 :                                 *value++ = 0;
     222             :                                 v_len = strlen(value);
     223             :                         }
     224           0 :                         ret = vfs_parse_fs_string(fc, key, value, v_len);
     225           0 :                         if (ret < 0)
     226             :                                 break;
     227             :                 }
     228             :         }
     229             : 
     230             :         return ret;
     231             : }
     232             : EXPORT_SYMBOL(generic_parse_monolithic);
     233             : 
     234             : /**
     235             :  * alloc_fs_context - Create a filesystem context.
     236             :  * @fs_type: The filesystem type.
     237             :  * @reference: The dentry from which this one derives (or NULL)
     238             :  * @sb_flags: Filesystem/superblock flags (SB_*)
     239             :  * @sb_flags_mask: Applicable members of @sb_flags
     240             :  * @purpose: The purpose that this configuration shall be used for.
     241             :  *
     242             :  * Open a filesystem and create a mount context.  The mount context is
     243             :  * initialised with the supplied flags and, if a submount/automount from
     244             :  * another superblock (referred to by @reference) is supplied, may have
     245             :  * parameters such as namespaces copied across from that superblock.
     246             :  */
     247          15 : static struct fs_context *alloc_fs_context(struct file_system_type *fs_type,
     248             :                                       struct dentry *reference,
     249             :                                       unsigned int sb_flags,
     250             :                                       unsigned int sb_flags_mask,
     251             :                                       enum fs_context_purpose purpose)
     252             : {
     253             :         int (*init_fs_context)(struct fs_context *);
     254             :         struct fs_context *fc;
     255          15 :         int ret = -ENOMEM;
     256             : 
     257          15 :         fc = kzalloc(sizeof(struct fs_context), GFP_KERNEL_ACCOUNT);
     258          15 :         if (!fc)
     259             :                 return ERR_PTR(-ENOMEM);
     260             : 
     261          15 :         fc->purpose  = purpose;
     262          15 :         fc->sb_flags = sb_flags;
     263          15 :         fc->sb_flags_mask = sb_flags_mask;
     264          15 :         fc->fs_type  = get_filesystem(fs_type);
     265          30 :         fc->cred     = get_current_cred();
     266          15 :         fc->net_ns   = get_net(current->nsproxy->net_ns);
     267          15 :         fc->log.prefix       = fs_type->name;
     268             : 
     269          15 :         mutex_init(&fc->uapi_mutex);
     270             : 
     271          15 :         switch (purpose) {
     272             :         case FS_CONTEXT_FOR_MOUNT:
     273          15 :                 fc->user_ns = get_user_ns(fc->cred->user_ns);
     274          15 :                 break;
     275             :         case FS_CONTEXT_FOR_SUBMOUNT:
     276           0 :                 fc->user_ns = get_user_ns(reference->d_sb->s_user_ns);
     277           0 :                 break;
     278             :         case FS_CONTEXT_FOR_RECONFIGURE:
     279           0 :                 atomic_inc(&reference->d_sb->s_active);
     280           0 :                 fc->user_ns = get_user_ns(reference->d_sb->s_user_ns);
     281           0 :                 fc->root = dget(reference);
     282           0 :                 break;
     283             :         }
     284             : 
     285             :         /* TODO: Make all filesystems support this unconditionally */
     286          15 :         init_fs_context = fc->fs_type->init_fs_context;
     287          15 :         if (!init_fs_context)
     288           0 :                 init_fs_context = legacy_init_fs_context;
     289             : 
     290          15 :         ret = init_fs_context(fc);
     291          15 :         if (ret < 0)
     292             :                 goto err_fc;
     293          15 :         fc->need_free = true;
     294          15 :         return fc;
     295             : 
     296             : err_fc:
     297           0 :         put_fs_context(fc);
     298           0 :         return ERR_PTR(ret);
     299             : }
     300             : 
     301          15 : struct fs_context *fs_context_for_mount(struct file_system_type *fs_type,
     302             :                                         unsigned int sb_flags)
     303             : {
     304          15 :         return alloc_fs_context(fs_type, NULL, sb_flags, 0,
     305             :                                         FS_CONTEXT_FOR_MOUNT);
     306             : }
     307             : EXPORT_SYMBOL(fs_context_for_mount);
     308             : 
     309           0 : struct fs_context *fs_context_for_reconfigure(struct dentry *dentry,
     310             :                                         unsigned int sb_flags,
     311             :                                         unsigned int sb_flags_mask)
     312             : {
     313           0 :         return alloc_fs_context(dentry->d_sb->s_type, dentry, sb_flags,
     314             :                                 sb_flags_mask, FS_CONTEXT_FOR_RECONFIGURE);
     315             : }
     316             : EXPORT_SYMBOL(fs_context_for_reconfigure);
     317             : 
     318           0 : struct fs_context *fs_context_for_submount(struct file_system_type *type,
     319             :                                            struct dentry *reference)
     320             : {
     321           0 :         return alloc_fs_context(type, reference, 0, 0, FS_CONTEXT_FOR_SUBMOUNT);
     322             : }
     323             : EXPORT_SYMBOL(fs_context_for_submount);
     324             : 
     325           0 : void fc_drop_locked(struct fs_context *fc)
     326             : {
     327           0 :         struct super_block *sb = fc->root->d_sb;
     328           0 :         dput(fc->root);
     329           0 :         fc->root = NULL;
     330           0 :         deactivate_locked_super(sb);
     331           0 : }
     332             : 
     333             : static void legacy_fs_context_free(struct fs_context *fc);
     334             : 
     335             : /**
     336             :  * vfs_dup_fc_config: Duplicate a filesystem context.
     337             :  * @src_fc: The context to copy.
     338             :  */
     339           0 : struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc)
     340             : {
     341             :         struct fs_context *fc;
     342             :         int ret;
     343             : 
     344           0 :         if (!src_fc->ops->dup)
     345             :                 return ERR_PTR(-EOPNOTSUPP);
     346             : 
     347           0 :         fc = kmemdup(src_fc, sizeof(struct fs_context), GFP_KERNEL);
     348           0 :         if (!fc)
     349             :                 return ERR_PTR(-ENOMEM);
     350             : 
     351           0 :         mutex_init(&fc->uapi_mutex);
     352             : 
     353           0 :         fc->fs_private       = NULL;
     354           0 :         fc->s_fs_info        = NULL;
     355           0 :         fc->source   = NULL;
     356           0 :         fc->security = NULL;
     357           0 :         get_filesystem(fc->fs_type);
     358           0 :         get_net(fc->net_ns);
     359           0 :         get_user_ns(fc->user_ns);
     360           0 :         get_cred(fc->cred);
     361           0 :         if (fc->log.log)
     362           0 :                 refcount_inc(&fc->log.log->usage);
     363             : 
     364             :         /* Can't call put until we've called ->dup */
     365           0 :         ret = fc->ops->dup(fc, src_fc);
     366           0 :         if (ret < 0)
     367             :                 goto err_fc;
     368             : 
     369             :         ret = security_fs_context_dup(fc, src_fc);
     370             :         if (ret < 0)
     371             :                 goto err_fc;
     372             :         return fc;
     373             : 
     374             : err_fc:
     375           0 :         put_fs_context(fc);
     376           0 :         return ERR_PTR(ret);
     377             : }
     378             : EXPORT_SYMBOL(vfs_dup_fs_context);
     379             : 
     380             : /**
     381             :  * logfc - Log a message to a filesystem context
     382             :  * @fc: The filesystem context to log to.
     383             :  * @fmt: The format of the buffer.
     384             :  */
     385           0 : void logfc(struct fc_log *log, const char *prefix, char level, const char *fmt, ...)
     386             : {
     387             :         va_list va;
     388           0 :         struct va_format vaf = {.fmt = fmt, .va = &va};
     389             : 
     390           0 :         va_start(va, fmt);
     391           0 :         if (!log) {
     392           0 :                 switch (level) {
     393             :                 case 'w':
     394           0 :                         printk(KERN_WARNING "%s%s%pV\n", prefix ? prefix : "",
     395             :                                                 prefix ? ": " : "", &vaf);
     396           0 :                         break;
     397             :                 case 'e':
     398           0 :                         printk(KERN_ERR "%s%s%pV\n", prefix ? prefix : "",
     399             :                                                 prefix ? ": " : "", &vaf);
     400           0 :                         break;
     401             :                 default:
     402           0 :                         printk(KERN_NOTICE "%s%s%pV\n", prefix ? prefix : "",
     403             :                                                 prefix ? ": " : "", &vaf);
     404           0 :                         break;
     405             :                 }
     406             :         } else {
     407           0 :                 unsigned int logsize = ARRAY_SIZE(log->buffer);
     408             :                 u8 index;
     409           0 :                 char *q = kasprintf(GFP_KERNEL, "%c %s%s%pV\n", level,
     410             :                                                 prefix ? prefix : "",
     411             :                                                 prefix ? ": " : "", &vaf);
     412             : 
     413           0 :                 index = log->head & (logsize - 1);
     414             :                 BUILD_BUG_ON(sizeof(log->head) != sizeof(u8) ||
     415             :                              sizeof(log->tail) != sizeof(u8));
     416           0 :                 if ((u8)(log->head - log->tail) == logsize) {
     417             :                         /* The buffer is full, discard the oldest message */
     418           0 :                         if (log->need_free & (1 << index))
     419           0 :                                 kfree(log->buffer[index]);
     420           0 :                         log->tail++;
     421             :                 }
     422             : 
     423           0 :                 log->buffer[index] = q ? q : "OOM: Can't store error string";
     424           0 :                 if (q)
     425           0 :                         log->need_free |= 1 << index;
     426             :                 else
     427           0 :                         log->need_free &= ~(1 << index);
     428           0 :                 log->head++;
     429             :         }
     430           0 :         va_end(va);
     431           0 : }
     432             : EXPORT_SYMBOL(logfc);
     433             : 
     434             : /*
     435             :  * Free a logging structure.
     436             :  */
     437          15 : static void put_fc_log(struct fs_context *fc)
     438             : {
     439          15 :         struct fc_log *log = fc->log.log;
     440             :         int i;
     441             : 
     442          15 :         if (log) {
     443           0 :                 if (refcount_dec_and_test(&log->usage)) {
     444           0 :                         fc->log.log = NULL;
     445           0 :                         for (i = 0; i <= 7; i++)
     446           0 :                                 if (log->need_free & (1 << i))
     447           0 :                                         kfree(log->buffer[i]);
     448           0 :                         kfree(log);
     449             :                 }
     450             :         }
     451          15 : }
     452             : 
     453             : /**
     454             :  * put_fs_context - Dispose of a superblock configuration context.
     455             :  * @fc: The context to dispose of.
     456             :  */
     457          15 : void put_fs_context(struct fs_context *fc)
     458             : {
     459             :         struct super_block *sb;
     460             : 
     461          15 :         if (fc->root) {
     462          15 :                 sb = fc->root->d_sb;
     463          15 :                 dput(fc->root);
     464          15 :                 fc->root = NULL;
     465          15 :                 deactivate_super(sb);
     466             :         }
     467             : 
     468          15 :         if (fc->need_free && fc->ops && fc->ops->free)
     469          15 :                 fc->ops->free(fc);
     470             : 
     471          15 :         security_free_mnt_opts(&fc->security);
     472          15 :         put_net(fc->net_ns);
     473          15 :         put_user_ns(fc->user_ns);
     474          30 :         put_cred(fc->cred);
     475          15 :         put_fc_log(fc);
     476          15 :         put_filesystem(fc->fs_type);
     477          15 :         kfree(fc->source);
     478          15 :         kfree(fc);
     479          15 : }
     480             : EXPORT_SYMBOL(put_fs_context);
     481             : 
     482             : /*
     483             :  * Free the config for a filesystem that doesn't support fs_context.
     484             :  */
     485           0 : static void legacy_fs_context_free(struct fs_context *fc)
     486             : {
     487           0 :         struct legacy_fs_context *ctx = fc->fs_private;
     488             : 
     489           0 :         if (ctx) {
     490           0 :                 if (ctx->param_type == LEGACY_FS_INDIVIDUAL_PARAMS)
     491           0 :                         kfree(ctx->legacy_data);
     492           0 :                 kfree(ctx);
     493             :         }
     494           0 : }
     495             : 
     496             : /*
     497             :  * Duplicate a legacy config.
     498             :  */
     499           0 : static int legacy_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc)
     500             : {
     501             :         struct legacy_fs_context *ctx;
     502           0 :         struct legacy_fs_context *src_ctx = src_fc->fs_private;
     503             : 
     504           0 :         ctx = kmemdup(src_ctx, sizeof(*src_ctx), GFP_KERNEL);
     505           0 :         if (!ctx)
     506             :                 return -ENOMEM;
     507             : 
     508           0 :         if (ctx->param_type == LEGACY_FS_INDIVIDUAL_PARAMS) {
     509           0 :                 ctx->legacy_data = kmemdup(src_ctx->legacy_data,
     510             :                                            src_ctx->data_size, GFP_KERNEL);
     511           0 :                 if (!ctx->legacy_data) {
     512           0 :                         kfree(ctx);
     513           0 :                         return -ENOMEM;
     514             :                 }
     515             :         }
     516             : 
     517           0 :         fc->fs_private = ctx;
     518           0 :         return 0;
     519             : }
     520             : 
     521             : /*
     522             :  * Add a parameter to a legacy config.  We build up a comma-separated list of
     523             :  * options.
     524             :  */
     525           0 : static int legacy_parse_param(struct fs_context *fc, struct fs_parameter *param)
     526             : {
     527           0 :         struct legacy_fs_context *ctx = fc->fs_private;
     528           0 :         unsigned int size = ctx->data_size;
     529           0 :         size_t len = 0;
     530             :         int ret;
     531             : 
     532           0 :         ret = vfs_parse_fs_param_source(fc, param);
     533           0 :         if (ret != -ENOPARAM)
     534             :                 return ret;
     535             : 
     536           0 :         if (ctx->param_type == LEGACY_FS_MONOLITHIC_PARAMS)
     537           0 :                 return invalf(fc, "VFS: Legacy: Can't mix monolithic and individual options");
     538             : 
     539           0 :         switch (param->type) {
     540             :         case fs_value_is_string:
     541           0 :                 len = 1 + param->size;
     542             :                 fallthrough;
     543             :         case fs_value_is_flag:
     544           0 :                 len += strlen(param->key);
     545             :                 break;
     546             :         default:
     547           0 :                 return invalf(fc, "VFS: Legacy: Parameter type for '%s' not supported",
     548             :                               param->key);
     549             :         }
     550             : 
     551           0 :         if (size + len + 2 > PAGE_SIZE)
     552           0 :                 return invalf(fc, "VFS: Legacy: Cumulative options too large");
     553           0 :         if (strchr(param->key, ',') ||
     554           0 :             (param->type == fs_value_is_string &&
     555           0 :              memchr(param->string, ',', param->size)))
     556           0 :                 return invalf(fc, "VFS: Legacy: Option '%s' contained comma",
     557             :                               param->key);
     558           0 :         if (!ctx->legacy_data) {
     559           0 :                 ctx->legacy_data = kmalloc(PAGE_SIZE, GFP_KERNEL);
     560           0 :                 if (!ctx->legacy_data)
     561             :                         return -ENOMEM;
     562             :         }
     563             : 
     564           0 :         if (size)
     565           0 :                 ctx->legacy_data[size++] = ',';
     566           0 :         len = strlen(param->key);
     567           0 :         memcpy(ctx->legacy_data + size, param->key, len);
     568           0 :         size += len;
     569           0 :         if (param->type == fs_value_is_string) {
     570           0 :                 ctx->legacy_data[size++] = '=';
     571           0 :                 memcpy(ctx->legacy_data + size, param->string, param->size);
     572           0 :                 size += param->size;
     573             :         }
     574           0 :         ctx->legacy_data[size] = '\0';
     575           0 :         ctx->data_size = size;
     576           0 :         ctx->param_type = LEGACY_FS_INDIVIDUAL_PARAMS;
     577           0 :         return 0;
     578             : }
     579             : 
     580             : /*
     581             :  * Add monolithic mount data.
     582             :  */
     583           0 : static int legacy_parse_monolithic(struct fs_context *fc, void *data)
     584             : {
     585           0 :         struct legacy_fs_context *ctx = fc->fs_private;
     586             : 
     587           0 :         if (ctx->param_type != LEGACY_FS_UNSET_PARAMS) {
     588           0 :                 pr_warn("VFS: Can't mix monolithic and individual options\n");
     589           0 :                 return -EINVAL;
     590             :         }
     591             : 
     592           0 :         ctx->legacy_data = data;
     593           0 :         ctx->param_type = LEGACY_FS_MONOLITHIC_PARAMS;
     594           0 :         if (!ctx->legacy_data)
     595             :                 return 0;
     596             : 
     597           0 :         if (fc->fs_type->fs_flags & FS_BINARY_MOUNTDATA)
     598             :                 return 0;
     599             :         return security_sb_eat_lsm_opts(ctx->legacy_data, &fc->security);
     600             : }
     601             : 
     602             : /*
     603             :  * Get a mountable root with the legacy mount command.
     604             :  */
     605           0 : static int legacy_get_tree(struct fs_context *fc)
     606             : {
     607           0 :         struct legacy_fs_context *ctx = fc->fs_private;
     608             :         struct super_block *sb;
     609             :         struct dentry *root;
     610             : 
     611           0 :         root = fc->fs_type->mount(fc->fs_type, fc->sb_flags,
     612           0 :                                       fc->source, ctx->legacy_data);
     613           0 :         if (IS_ERR(root))
     614           0 :                 return PTR_ERR(root);
     615             : 
     616           0 :         sb = root->d_sb;
     617           0 :         BUG_ON(!sb);
     618             : 
     619           0 :         fc->root = root;
     620           0 :         return 0;
     621             : }
     622             : 
     623             : /*
     624             :  * Handle remount.
     625             :  */
     626           0 : static int legacy_reconfigure(struct fs_context *fc)
     627             : {
     628           0 :         struct legacy_fs_context *ctx = fc->fs_private;
     629           0 :         struct super_block *sb = fc->root->d_sb;
     630             : 
     631           0 :         if (!sb->s_op->remount_fs)
     632             :                 return 0;
     633             : 
     634           0 :         return sb->s_op->remount_fs(sb, &fc->sb_flags,
     635             :                                     ctx ? ctx->legacy_data : NULL);
     636             : }
     637             : 
     638             : const struct fs_context_operations legacy_fs_context_ops = {
     639             :         .free                   = legacy_fs_context_free,
     640             :         .dup                    = legacy_fs_context_dup,
     641             :         .parse_param            = legacy_parse_param,
     642             :         .parse_monolithic       = legacy_parse_monolithic,
     643             :         .get_tree               = legacy_get_tree,
     644             :         .reconfigure            = legacy_reconfigure,
     645             : };
     646             : 
     647             : /*
     648             :  * Initialise a legacy context for a filesystem that doesn't support
     649             :  * fs_context.
     650             :  */
     651           0 : static int legacy_init_fs_context(struct fs_context *fc)
     652             : {
     653           0 :         fc->fs_private = kzalloc(sizeof(struct legacy_fs_context), GFP_KERNEL_ACCOUNT);
     654           0 :         if (!fc->fs_private)
     655             :                 return -ENOMEM;
     656           0 :         fc->ops = &legacy_fs_context_ops;
     657           0 :         return 0;
     658             : }
     659             : 
     660          15 : int parse_monolithic_mount_data(struct fs_context *fc, void *data)
     661             : {
     662             :         int (*monolithic_mount_data)(struct fs_context *, void *);
     663             : 
     664          15 :         monolithic_mount_data = fc->ops->parse_monolithic;
     665          15 :         if (!monolithic_mount_data)
     666          15 :                 monolithic_mount_data = generic_parse_monolithic;
     667             : 
     668          15 :         return monolithic_mount_data(fc, data);
     669             : }
     670             : 
     671             : /*
     672             :  * Clean up a context after performing an action on it and put it into a state
     673             :  * from where it can be used to reconfigure a superblock.
     674             :  *
     675             :  * Note that here we do only the parts that can't fail; the rest is in
     676             :  * finish_clean_context() below and in between those fs_context is marked
     677             :  * FS_CONTEXT_AWAITING_RECONF.  The reason for splitup is that after
     678             :  * successful mount or remount we need to report success to userland.
     679             :  * Trying to do full reinit (for the sake of possible subsequent remount)
     680             :  * and failing to allocate memory would've put us into a nasty situation.
     681             :  * So here we only discard the old state and reinitialization is left
     682             :  * until we actually try to reconfigure.
     683             :  */
     684           0 : void vfs_clean_context(struct fs_context *fc)
     685             : {
     686           0 :         if (fc->need_free && fc->ops && fc->ops->free)
     687           0 :                 fc->ops->free(fc);
     688           0 :         fc->need_free = false;
     689           0 :         fc->fs_private = NULL;
     690           0 :         fc->s_fs_info = NULL;
     691           0 :         fc->sb_flags = 0;
     692           0 :         security_free_mnt_opts(&fc->security);
     693           0 :         kfree(fc->source);
     694           0 :         fc->source = NULL;
     695             : 
     696           0 :         fc->purpose = FS_CONTEXT_FOR_RECONFIGURE;
     697           0 :         fc->phase = FS_CONTEXT_AWAITING_RECONF;
     698           0 : }
     699             : 
     700           0 : int finish_clean_context(struct fs_context *fc)
     701             : {
     702             :         int error;
     703             : 
     704           0 :         if (fc->phase != FS_CONTEXT_AWAITING_RECONF)
     705             :                 return 0;
     706             : 
     707           0 :         if (fc->fs_type->init_fs_context)
     708           0 :                 error = fc->fs_type->init_fs_context(fc);
     709             :         else
     710             :                 error = legacy_init_fs_context(fc);
     711           0 :         if (unlikely(error)) {
     712           0 :                 fc->phase = FS_CONTEXT_FAILED;
     713           0 :                 return error;
     714             :         }
     715           0 :         fc->need_free = true;
     716           0 :         fc->phase = FS_CONTEXT_RECONF_PARAMS;
     717           0 :         return 0;
     718             : }

Generated by: LCOV version 1.14