LCOV - code coverage report
Current view: top level - fs - fs_parser.c (source / functions) Hit Total Coverage
Test: Real Lines: 32 92 34.8 %
Date: 2020-10-17 15:46:43 Functions: 0 4 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                 :            : /* Filesystem parameter parser.
       3                 :            :  *
       4                 :            :  * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
       5                 :            :  * Written by David Howells (dhowells@redhat.com)
       6                 :            :  */
       7                 :            : 
       8                 :            : #include <linux/export.h>
       9                 :            : #include <linux/fs_context.h>
      10                 :            : #include <linux/fs_parser.h>
      11                 :            : #include <linux/slab.h>
      12                 :            : #include <linux/security.h>
      13                 :            : #include <linux/namei.h>
      14                 :            : #include "internal.h"
      15                 :            : 
      16                 :            : static const struct constant_table bool_names[] = {
      17                 :            :         { "0",                false },
      18                 :            :         { "1",                true },
      19                 :            :         { "false",    false },
      20                 :            :         { "no",               false },
      21                 :            :         { "true",     true },
      22                 :            :         { "yes",      true },
      23                 :            : };
      24                 :            : 
      25                 :            : /**
      26                 :            :  * lookup_constant - Look up a constant by name in an ordered table
      27                 :            :  * @tbl: The table of constants to search.
      28                 :            :  * @tbl_size: The size of the table.
      29                 :            :  * @name: The name to look up.
      30                 :            :  * @not_found: The value to return if the name is not found.
      31                 :            :  */
      32                 :          3 : int __lookup_constant(const struct constant_table *tbl, size_t tbl_size,
      33                 :            :                       const char *name, int not_found)
      34                 :            : {
      35                 :            :         unsigned int i;
      36                 :            : 
      37                 :          3 :         for (i = 0; i < tbl_size; i++)
      38                 :          3 :                 if (strcmp(name, tbl[i].name) == 0)
      39                 :          0 :                         return tbl[i].value;
      40                 :            : 
      41                 :            :         return not_found;
      42                 :            : }
      43                 :            : EXPORT_SYMBOL(__lookup_constant);
      44                 :            : 
      45                 :          3 : static const struct fs_parameter_spec *fs_lookup_key(
      46                 :            :         const struct fs_parameter_description *desc,
      47                 :            :         const char *name)
      48                 :            : {
      49                 :            :         const struct fs_parameter_spec *p;
      50                 :            : 
      51                 :          3 :         if (!desc->specs)
      52                 :            :                 return NULL;
      53                 :            : 
      54                 :          3 :         for (p = desc->specs; p->name; p++)
      55                 :          3 :                 if (strcmp(p->name, name) == 0)
      56                 :          3 :                         return p;
      57                 :            : 
      58                 :            :         return NULL;
      59                 :            : }
      60                 :            : 
      61                 :            : /*
      62                 :            :  * fs_parse - Parse a filesystem configuration parameter
      63                 :            :  * @fc: The filesystem context to log errors through.
      64                 :            :  * @desc: The parameter description to use.
      65                 :            :  * @param: The parameter.
      66                 :            :  * @result: Where to place the result of the parse
      67                 :            :  *
      68                 :            :  * Parse a filesystem configuration parameter and attempt a conversion for a
      69                 :            :  * simple parameter for which this is requested.  If successful, the determined
      70                 :            :  * parameter ID is placed into @result->key, the desired type is indicated in
      71                 :            :  * @result->t and any converted value is placed into an appropriate member of
      72                 :            :  * the union in @result.
      73                 :            :  *
      74                 :            :  * The function returns the parameter number if the parameter was matched,
      75                 :            :  * -ENOPARAM if it wasn't matched and @desc->ignore_unknown indicated that
      76                 :            :  * unknown parameters are okay and -EINVAL if there was a conversion issue or
      77                 :            :  * the parameter wasn't recognised and unknowns aren't okay.
      78                 :            :  */
      79                 :          3 : int fs_parse(struct fs_context *fc,
      80                 :            :              const struct fs_parameter_description *desc,
      81                 :            :              struct fs_parameter *param,
      82                 :            :              struct fs_parse_result *result)
      83                 :            : {
      84                 :            :         const struct fs_parameter_spec *p;
      85                 :            :         const struct fs_parameter_enum *e;
      86                 :            :         int ret = -ENOPARAM, b;
      87                 :            : 
      88                 :          3 :         result->has_value = !!param->string;
      89                 :          3 :         result->negated = false;
      90                 :          3 :         result->uint_64 = 0;
      91                 :            : 
      92                 :          3 :         p = fs_lookup_key(desc, param->key);
      93                 :          3 :         if (!p) {
      94                 :            :                 /* If we didn't find something that looks like "noxxx", see if
      95                 :            :                  * "xxx" takes the "no"-form negative - but only if there
      96                 :            :                  * wasn't an value.
      97                 :            :                  */
      98                 :          3 :                 if (result->has_value)
      99                 :            :                         goto unknown_parameter;
     100                 :          3 :                 if (param->key[0] != 'n' || param->key[1] != 'o' || !param->key[2])
     101                 :            :                         goto unknown_parameter;
     102                 :            : 
     103                 :          0 :                 p = fs_lookup_key(desc, param->key + 2);
     104                 :          0 :                 if (!p)
     105                 :            :                         goto unknown_parameter;
     106                 :          0 :                 if (!(p->flags & fs_param_neg_with_no))
     107                 :            :                         goto unknown_parameter;
     108                 :          0 :                 result->boolean = false;
     109                 :          0 :                 result->negated = true;
     110                 :            :         }
     111                 :            : 
     112                 :          3 :         if (p->flags & fs_param_deprecated)
     113                 :          0 :                 warnf(fc, "%s: Deprecated parameter '%s'",
     114                 :            :                       desc->name, param->key);
     115                 :            : 
     116                 :          3 :         if (result->negated)
     117                 :            :                 goto okay;
     118                 :            : 
     119                 :            :         /* Certain parameter types only take a string and convert it. */
     120                 :          3 :         switch (p->type) {
     121                 :            :         case __fs_param_wasnt_defined:
     122                 :            :                 return -EINVAL;
     123                 :            :         case fs_param_is_u32:
     124                 :            :         case fs_param_is_u32_octal:
     125                 :            :         case fs_param_is_u32_hex:
     126                 :            :         case fs_param_is_s32:
     127                 :            :         case fs_param_is_u64:
     128                 :            :         case fs_param_is_enum:
     129                 :            :         case fs_param_is_string:
     130                 :          3 :                 if (param->type != fs_value_is_string)
     131                 :            :                         goto bad_value;
     132                 :          3 :                 if (!result->has_value) {
     133                 :          0 :                         if (p->flags & fs_param_v_optional)
     134                 :            :                                 goto okay;
     135                 :            :                         goto bad_value;
     136                 :            :                 }
     137                 :            :                 /* Fall through */
     138                 :            :         default:
     139                 :            :                 break;
     140                 :            :         }
     141                 :            : 
     142                 :            :         /* Try to turn the type we were given into the type desired by the
     143                 :            :          * parameter and give an error if we can't.
     144                 :            :          */
     145                 :          3 :         switch (p->type) {
     146                 :            :         case fs_param_is_flag:
     147                 :          3 :                 if (param->type != fs_value_is_flag &&
     148                 :          3 :                     (param->type != fs_value_is_string || result->has_value))
     149                 :          0 :                         return invalf(fc, "%s: Unexpected value for '%s'",
     150                 :            :                                       desc->name, param->key);
     151                 :          3 :                 result->boolean = true;
     152                 :          3 :                 goto okay;
     153                 :            : 
     154                 :            :         case fs_param_is_bool:
     155                 :          0 :                 switch (param->type) {
     156                 :            :                 case fs_value_is_flag:
     157                 :          0 :                         result->boolean = true;
     158                 :          0 :                         goto okay;
     159                 :            :                 case fs_value_is_string:
     160                 :          0 :                         if (param->size == 0) {
     161                 :          0 :                                 result->boolean = true;
     162                 :          0 :                                 goto okay;
     163                 :            :                         }
     164                 :          0 :                         b = lookup_constant(bool_names, param->string, -1);
     165                 :          0 :                         if (b == -1)
     166                 :            :                                 goto bad_value;
     167                 :          0 :                         result->boolean = b;
     168                 :          0 :                         goto okay;
     169                 :            :                 default:
     170                 :            :                         goto bad_value;
     171                 :            :                 }
     172                 :            : 
     173                 :            :         case fs_param_is_u32:
     174                 :          3 :                 ret = kstrtouint(param->string, 0, &result->uint_32);
     175                 :          3 :                 goto maybe_okay;
     176                 :            :         case fs_param_is_u32_octal:
     177                 :          3 :                 ret = kstrtouint(param->string, 8, &result->uint_32);
     178                 :          3 :                 goto maybe_okay;
     179                 :            :         case fs_param_is_u32_hex:
     180                 :          0 :                 ret = kstrtouint(param->string, 16, &result->uint_32);
     181                 :          0 :                 goto maybe_okay;
     182                 :            :         case fs_param_is_s32:
     183                 :          0 :                 ret = kstrtoint(param->string, 0, &result->int_32);
     184                 :          0 :                 goto maybe_okay;
     185                 :            :         case fs_param_is_u64:
     186                 :          0 :                 ret = kstrtoull(param->string, 0, &result->uint_64);
     187                 :          0 :                 goto maybe_okay;
     188                 :            : 
     189                 :            :         case fs_param_is_enum:
     190                 :          0 :                 for (e = desc->enums; e->name[0]; e++) {
     191                 :          0 :                         if (e->opt == p->opt &&
     192                 :          0 :                             strcmp(e->name, param->string) == 0) {
     193                 :          0 :                                 result->uint_32 = e->value;
     194                 :          0 :                                 goto okay;
     195                 :            :                         }
     196                 :            :                 }
     197                 :            :                 goto bad_value;
     198                 :            : 
     199                 :            :         case fs_param_is_string:
     200                 :            :                 goto okay;
     201                 :            :         case fs_param_is_blob:
     202                 :          0 :                 if (param->type != fs_value_is_blob)
     203                 :            :                         goto bad_value;
     204                 :            :                 goto okay;
     205                 :            : 
     206                 :            :         case fs_param_is_fd: {
     207                 :          0 :                 switch (param->type) {
     208                 :            :                 case fs_value_is_string:
     209                 :          0 :                         if (!result->has_value)
     210                 :            :                                 goto bad_value;
     211                 :            : 
     212                 :          0 :                         ret = kstrtouint(param->string, 0, &result->uint_32);
     213                 :            :                         break;
     214                 :            :                 case fs_value_is_file:
     215                 :          0 :                         result->uint_32 = param->dirfd;
     216                 :            :                         ret = 0;
     217                 :            :                 default:
     218                 :            :                         goto bad_value;
     219                 :            :                 }
     220                 :            : 
     221                 :          0 :                 if (result->uint_32 > INT_MAX)
     222                 :            :                         goto bad_value;
     223                 :            :                 goto maybe_okay;
     224                 :            :         }
     225                 :            : 
     226                 :            :         case fs_param_is_blockdev:
     227                 :            :         case fs_param_is_path:
     228                 :            :                 goto okay;
     229                 :            :         default:
     230                 :          0 :                 BUG();
     231                 :            :         }
     232                 :            : 
     233                 :            : maybe_okay:
     234                 :          3 :         if (ret < 0)
     235                 :            :                 goto bad_value;
     236                 :            : okay:
     237                 :          3 :         return p->opt;
     238                 :            : 
     239                 :            : bad_value:
     240                 :          0 :         return invalf(fc, "%s: Bad value for '%s'", desc->name, param->key);
     241                 :            : unknown_parameter:
     242                 :            :         return -ENOPARAM;
     243                 :            : }
     244                 :            : EXPORT_SYMBOL(fs_parse);
     245                 :            : 
     246                 :            : /**
     247                 :            :  * fs_lookup_param - Look up a path referred to by a parameter
     248                 :            :  * @fc: The filesystem context to log errors through.
     249                 :            :  * @param: The parameter.
     250                 :            :  * @want_bdev: T if want a blockdev
     251                 :            :  * @_path: The result of the lookup
     252                 :            :  */
     253                 :          0 : int fs_lookup_param(struct fs_context *fc,
     254                 :            :                     struct fs_parameter *param,
     255                 :            :                     bool want_bdev,
     256                 :            :                     struct path *_path)
     257                 :            : {
     258                 :            :         struct filename *f;
     259                 :            :         unsigned int flags = 0;
     260                 :            :         bool put_f;
     261                 :            :         int ret;
     262                 :            : 
     263                 :          0 :         switch (param->type) {
     264                 :            :         case fs_value_is_string:
     265                 :          0 :                 f = getname_kernel(param->string);
     266                 :          0 :                 if (IS_ERR(f))
     267                 :          0 :                         return PTR_ERR(f);
     268                 :            :                 put_f = true;
     269                 :            :                 break;
     270                 :            :         case fs_value_is_filename_empty:
     271                 :            :                 flags = LOOKUP_EMPTY;
     272                 :            :                 /* Fall through */
     273                 :            :         case fs_value_is_filename:
     274                 :          0 :                 f = param->name;
     275                 :            :                 put_f = false;
     276                 :          0 :                 break;
     277                 :            :         default:
     278                 :          0 :                 return invalf(fc, "%s: not usable as path", param->key);
     279                 :            :         }
     280                 :            : 
     281                 :          0 :         f->refcnt++; /* filename_lookup() drops our ref. */
     282                 :          0 :         ret = filename_lookup(param->dirfd, f, flags, _path, NULL);
     283                 :          0 :         if (ret < 0) {
     284                 :          0 :                 errorf(fc, "%s: Lookup failure for '%s'", param->key, f->name);
     285                 :          0 :                 goto out;
     286                 :            :         }
     287                 :            : 
     288                 :          0 :         if (want_bdev &&
     289                 :          0 :             !S_ISBLK(d_backing_inode(_path->dentry)->i_mode)) {
     290                 :          0 :                 path_put(_path);
     291                 :          0 :                 _path->dentry = NULL;
     292                 :          0 :                 _path->mnt = NULL;
     293                 :          0 :                 errorf(fc, "%s: Non-blockdev passed as '%s'",
     294                 :            :                        param->key, f->name);
     295                 :            :                 ret = -ENOTBLK;
     296                 :            :         }
     297                 :            : 
     298                 :            : out:
     299                 :          0 :         if (put_f)
     300                 :          0 :                 putname(f);
     301                 :          0 :         return ret;
     302                 :            : }
     303                 :            : EXPORT_SYMBOL(fs_lookup_param);
     304                 :            : 
     305                 :            : #ifdef CONFIG_VALIDATE_FS_PARSER
     306                 :            : /**
     307                 :            :  * validate_constant_table - Validate a constant table
     308                 :            :  * @name: Name to use in reporting
     309                 :            :  * @tbl: The constant table to validate.
     310                 :            :  * @tbl_size: The size of the table.
     311                 :            :  * @low: The lowest permissible value.
     312                 :            :  * @high: The highest permissible value.
     313                 :            :  * @special: One special permissible value outside of the range.
     314                 :            :  */
     315                 :            : bool validate_constant_table(const struct constant_table *tbl, size_t tbl_size,
     316                 :            :                              int low, int high, int special)
     317                 :            : {
     318                 :            :         size_t i;
     319                 :            :         bool good = true;
     320                 :            : 
     321                 :            :         if (tbl_size == 0) {
     322                 :            :                 pr_warn("VALIDATE C-TBL: Empty\n");
     323                 :            :                 return true;
     324                 :            :         }
     325                 :            : 
     326                 :            :         for (i = 0; i < tbl_size; i++) {
     327                 :            :                 if (!tbl[i].name) {
     328                 :            :                         pr_err("VALIDATE C-TBL[%zu]: Null\n", i);
     329                 :            :                         good = false;
     330                 :            :                 } else if (i > 0 && tbl[i - 1].name) {
     331                 :            :                         int c = strcmp(tbl[i-1].name, tbl[i].name);
     332                 :            : 
     333                 :            :                         if (c == 0) {
     334                 :            :                                 pr_err("VALIDATE C-TBL[%zu]: Duplicate %s\n",
     335                 :            :                                        i, tbl[i].name);
     336                 :            :                                 good = false;
     337                 :            :                         }
     338                 :            :                         if (c > 0) {
     339                 :            :                                 pr_err("VALIDATE C-TBL[%zu]: Missorted %s>=%s\n",
     340                 :            :                                        i, tbl[i-1].name, tbl[i].name);
     341                 :            :                                 good = false;
     342                 :            :                         }
     343                 :            :                 }
     344                 :            : 
     345                 :            :                 if (tbl[i].value != special &&
     346                 :            :                     (tbl[i].value < low || tbl[i].value > high)) {
     347                 :            :                         pr_err("VALIDATE C-TBL[%zu]: %s->%d const out of range (%d-%d)\n",
     348                 :            :                                i, tbl[i].name, tbl[i].value, low, high);
     349                 :            :                         good = false;
     350                 :            :                 }
     351                 :            :         }
     352                 :            : 
     353                 :            :         return good;
     354                 :            : }
     355                 :            : 
     356                 :            : /**
     357                 :            :  * fs_validate_description - Validate a parameter description
     358                 :            :  * @desc: The parameter description to validate.
     359                 :            :  */
     360                 :            : bool fs_validate_description(const struct fs_parameter_description *desc)
     361                 :            : {
     362                 :            :         const struct fs_parameter_spec *param, *p2;
     363                 :            :         const struct fs_parameter_enum *e;
     364                 :            :         const char *name = desc->name;
     365                 :            :         unsigned int nr_params = 0;
     366                 :            :         bool good = true, enums = false;
     367                 :            : 
     368                 :            :         pr_notice("*** VALIDATE %s ***\n", name);
     369                 :            : 
     370                 :            :         if (!name[0]) {
     371                 :            :                 pr_err("VALIDATE Parser: No name\n");
     372                 :            :                 name = "Unknown";
     373                 :            :                 good = false;
     374                 :            :         }
     375                 :            : 
     376                 :            :         if (desc->specs) {
     377                 :            :                 for (param = desc->specs; param->name; param++) {
     378                 :            :                         enum fs_parameter_type t = param->type;
     379                 :            : 
     380                 :            :                         /* Check that the type is in range */
     381                 :            :                         if (t == __fs_param_wasnt_defined ||
     382                 :            :                             t >= nr__fs_parameter_type) {
     383                 :            :                                 pr_err("VALIDATE %s: PARAM[%s] Bad type %u\n",
     384                 :            :                                        name, param->name, t);
     385                 :            :                                 good = false;
     386                 :            :                         } else if (t == fs_param_is_enum) {
     387                 :            :                                 enums = true;
     388                 :            :                         }
     389                 :            : 
     390                 :            :                         /* Check for duplicate parameter names */
     391                 :            :                         for (p2 = desc->specs; p2 < param; p2++) {
     392                 :            :                                 if (strcmp(param->name, p2->name) == 0) {
     393                 :            :                                         pr_err("VALIDATE %s: PARAM[%s]: Duplicate\n",
     394                 :            :                                                name, param->name);
     395                 :            :                                         good = false;
     396                 :            :                                 }
     397                 :            :                         }
     398                 :            :                 }
     399                 :            : 
     400                 :            :                 nr_params = param - desc->specs;
     401                 :            :         }
     402                 :            : 
     403                 :            :         if (desc->enums) {
     404                 :            :                 if (!nr_params) {
     405                 :            :                         pr_err("VALIDATE %s: Enum table but no parameters\n",
     406                 :            :                                name);
     407                 :            :                         good = false;
     408                 :            :                         goto no_enums;
     409                 :            :                 }
     410                 :            :                 if (!enums) {
     411                 :            :                         pr_err("VALIDATE %s: Enum table but no enum-type values\n",
     412                 :            :                                name);
     413                 :            :                         good = false;
     414                 :            :                         goto no_enums;
     415                 :            :                 }
     416                 :            : 
     417                 :            :                 for (e = desc->enums; e->name[0]; e++) {
     418                 :            :                         /* Check that all entries in the enum table have at
     419                 :            :                          * least one parameter that uses them.
     420                 :            :                          */
     421                 :            :                         for (param = desc->specs; param->name; param++) {
     422                 :            :                                 if (param->opt == e->opt &&
     423                 :            :                                     param->type != fs_param_is_enum) {
     424                 :            :                                         pr_err("VALIDATE %s: e[%tu] enum val for %s\n",
     425                 :            :                                                name, e - desc->enums, param->name);
     426                 :            :                                         good = false;
     427                 :            :                                 }
     428                 :            :                         }
     429                 :            :                 }
     430                 :            : 
     431                 :            :                 /* Check that all enum-type parameters have at least one enum
     432                 :            :                  * value in the enum table.
     433                 :            :                  */
     434                 :            :                 for (param = desc->specs; param->name; param++) {
     435                 :            :                         if (param->type != fs_param_is_enum)
     436                 :            :                                 continue;
     437                 :            :                         for (e = desc->enums; e->name[0]; e++)
     438                 :            :                                 if (e->opt == param->opt)
     439                 :            :                                         break;
     440                 :            :                         if (!e->name[0]) {
     441                 :            :                                 pr_err("VALIDATE %s: PARAM[%s] enum with no values\n",
     442                 :            :                                        name, param->name);
     443                 :            :                                 good = false;
     444                 :            :                         }
     445                 :            :                 }
     446                 :            :         } else {
     447                 :            :                 if (enums) {
     448                 :            :                         pr_err("VALIDATE %s: enum-type values, but no enum table\n",
     449                 :            :                                name);
     450                 :            :                         good = false;
     451                 :            :                         goto no_enums;
     452                 :            :                 }
     453                 :            :         }
     454                 :            : 
     455                 :            : no_enums:
     456                 :            :         return good;
     457                 :            : }
     458                 :            : #endif /* CONFIG_VALIDATE_FS_PARSER */
    

Generated by: LCOV version 1.14