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