LCOV - code coverage report
Current view: top level - fs - fs_context.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 158 323 48.9 %
Date: 2021-04-22 12:43:58 Functions: 16 23 69.6 %

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

Generated by: LCOV version 1.14