LCOV - code coverage report
Current view: top level - fs - fs_context.c (source / functions) Hit Total Coverage
Test: Real Lines: 140 291 48.1 %
Date: 2020-10-17 15:46:16 Functions: 0 23 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

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

Generated by: LCOV version 1.14