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