LCOV - code coverage report
Current view: top level - fs - fs_context.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 146 295 49.5 %
Date: 2022-03-28 15:32:58 Functions: 14 21 66.7 %
Branches: 55 168 32.7 %

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

Generated by: LCOV version 1.14