0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/export.h>
0009 #include <linux/fs_context.h>
0010 #include <linux/fs_parser.h>
0011 #include <linux/slab.h>
0012 #include <linux/security.h>
0013 #include <linux/namei.h>
0014 #include "internal.h"
0015
0016 static const struct constant_table bool_names[] = {
0017 { "0", false },
0018 { "1", true },
0019 { "false", false },
0020 { "no", false },
0021 { "true", true },
0022 { "yes", true },
0023 { },
0024 };
0025
0026 static const struct constant_table *
0027 __lookup_constant(const struct constant_table *tbl, const char *name)
0028 {
0029 for ( ; tbl->name; tbl++)
0030 if (strcmp(name, tbl->name) == 0)
0031 return tbl;
0032 return NULL;
0033 }
0034
0035
0036
0037
0038
0039
0040
0041 int lookup_constant(const struct constant_table *tbl, const char *name, int not_found)
0042 {
0043 const struct constant_table *p = __lookup_constant(tbl, name);
0044
0045 return p ? p->value : not_found;
0046 }
0047 EXPORT_SYMBOL(lookup_constant);
0048
0049 static inline bool is_flag(const struct fs_parameter_spec *p)
0050 {
0051 return p->type == NULL;
0052 }
0053
0054 static const struct fs_parameter_spec *fs_lookup_key(
0055 const struct fs_parameter_spec *desc,
0056 struct fs_parameter *param, bool *negated)
0057 {
0058 const struct fs_parameter_spec *p, *other = NULL;
0059 const char *name = param->key;
0060 bool want_flag = param->type == fs_value_is_flag;
0061
0062 *negated = false;
0063 for (p = desc; p->name; p++) {
0064 if (strcmp(p->name, name) != 0)
0065 continue;
0066 if (likely(is_flag(p) == want_flag))
0067 return p;
0068 other = p;
0069 }
0070 if (want_flag) {
0071 if (name[0] == 'n' && name[1] == 'o' && name[2]) {
0072 for (p = desc; p->name; p++) {
0073 if (strcmp(p->name, name + 2) != 0)
0074 continue;
0075 if (!(p->flags & fs_param_neg_with_no))
0076 continue;
0077 *negated = true;
0078 return p;
0079 }
0080 }
0081 }
0082 return other;
0083 }
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103 int __fs_parse(struct p_log *log,
0104 const struct fs_parameter_spec *desc,
0105 struct fs_parameter *param,
0106 struct fs_parse_result *result)
0107 {
0108 const struct fs_parameter_spec *p;
0109
0110 result->uint_64 = 0;
0111
0112 p = fs_lookup_key(desc, param, &result->negated);
0113 if (!p)
0114 return -ENOPARAM;
0115
0116 if (p->flags & fs_param_deprecated)
0117 warn_plog(log, "Deprecated parameter '%s'", param->key);
0118
0119
0120
0121
0122 if (is_flag(p)) {
0123 if (param->type != fs_value_is_flag)
0124 return inval_plog(log, "Unexpected value for '%s'",
0125 param->key);
0126 result->boolean = !result->negated;
0127 } else {
0128 int ret = p->type(log, p, param, result);
0129 if (ret)
0130 return ret;
0131 }
0132 return p->opt;
0133 }
0134 EXPORT_SYMBOL(__fs_parse);
0135
0136
0137
0138
0139
0140
0141
0142
0143 int fs_lookup_param(struct fs_context *fc,
0144 struct fs_parameter *param,
0145 bool want_bdev,
0146 struct path *_path)
0147 {
0148 struct filename *f;
0149 unsigned int flags = 0;
0150 bool put_f;
0151 int ret;
0152
0153 switch (param->type) {
0154 case fs_value_is_string:
0155 f = getname_kernel(param->string);
0156 if (IS_ERR(f))
0157 return PTR_ERR(f);
0158 put_f = true;
0159 break;
0160 case fs_value_is_filename:
0161 f = param->name;
0162 put_f = false;
0163 break;
0164 default:
0165 return invalf(fc, "%s: not usable as path", param->key);
0166 }
0167
0168 ret = filename_lookup(param->dirfd, f, flags, _path, NULL);
0169 if (ret < 0) {
0170 errorf(fc, "%s: Lookup failure for '%s'", param->key, f->name);
0171 goto out;
0172 }
0173
0174 if (want_bdev &&
0175 !S_ISBLK(d_backing_inode(_path->dentry)->i_mode)) {
0176 path_put(_path);
0177 _path->dentry = NULL;
0178 _path->mnt = NULL;
0179 errorf(fc, "%s: Non-blockdev passed as '%s'",
0180 param->key, f->name);
0181 ret = -ENOTBLK;
0182 }
0183
0184 out:
0185 if (put_f)
0186 putname(f);
0187 return ret;
0188 }
0189 EXPORT_SYMBOL(fs_lookup_param);
0190
0191 static int fs_param_bad_value(struct p_log *log, struct fs_parameter *param)
0192 {
0193 return inval_plog(log, "Bad value for '%s'", param->key);
0194 }
0195
0196 int fs_param_is_bool(struct p_log *log, const struct fs_parameter_spec *p,
0197 struct fs_parameter *param, struct fs_parse_result *result)
0198 {
0199 int b;
0200 if (param->type != fs_value_is_string)
0201 return fs_param_bad_value(log, param);
0202 if (!*param->string && (p->flags & fs_param_can_be_empty))
0203 return 0;
0204 b = lookup_constant(bool_names, param->string, -1);
0205 if (b == -1)
0206 return fs_param_bad_value(log, param);
0207 result->boolean = b;
0208 return 0;
0209 }
0210 EXPORT_SYMBOL(fs_param_is_bool);
0211
0212 int fs_param_is_u32(struct p_log *log, const struct fs_parameter_spec *p,
0213 struct fs_parameter *param, struct fs_parse_result *result)
0214 {
0215 int base = (unsigned long)p->data;
0216 if (param->type != fs_value_is_string)
0217 return fs_param_bad_value(log, param);
0218 if (!*param->string && (p->flags & fs_param_can_be_empty))
0219 return 0;
0220 if (kstrtouint(param->string, base, &result->uint_32) < 0)
0221 return fs_param_bad_value(log, param);
0222 return 0;
0223 }
0224 EXPORT_SYMBOL(fs_param_is_u32);
0225
0226 int fs_param_is_s32(struct p_log *log, const struct fs_parameter_spec *p,
0227 struct fs_parameter *param, struct fs_parse_result *result)
0228 {
0229 if (param->type != fs_value_is_string)
0230 return fs_param_bad_value(log, param);
0231 if (!*param->string && (p->flags & fs_param_can_be_empty))
0232 return 0;
0233 if (kstrtoint(param->string, 0, &result->int_32) < 0)
0234 return fs_param_bad_value(log, param);
0235 return 0;
0236 }
0237 EXPORT_SYMBOL(fs_param_is_s32);
0238
0239 int fs_param_is_u64(struct p_log *log, const struct fs_parameter_spec *p,
0240 struct fs_parameter *param, struct fs_parse_result *result)
0241 {
0242 if (param->type != fs_value_is_string)
0243 return fs_param_bad_value(log, param);
0244 if (!*param->string && (p->flags & fs_param_can_be_empty))
0245 return 0;
0246 if (kstrtoull(param->string, 0, &result->uint_64) < 0)
0247 return fs_param_bad_value(log, param);
0248 return 0;
0249 }
0250 EXPORT_SYMBOL(fs_param_is_u64);
0251
0252 int fs_param_is_enum(struct p_log *log, const struct fs_parameter_spec *p,
0253 struct fs_parameter *param, struct fs_parse_result *result)
0254 {
0255 const struct constant_table *c;
0256 if (param->type != fs_value_is_string)
0257 return fs_param_bad_value(log, param);
0258 if (!*param->string && (p->flags & fs_param_can_be_empty))
0259 return 0;
0260 c = __lookup_constant(p->data, param->string);
0261 if (!c)
0262 return fs_param_bad_value(log, param);
0263 result->uint_32 = c->value;
0264 return 0;
0265 }
0266 EXPORT_SYMBOL(fs_param_is_enum);
0267
0268 int fs_param_is_string(struct p_log *log, const struct fs_parameter_spec *p,
0269 struct fs_parameter *param, struct fs_parse_result *result)
0270 {
0271 if (param->type != fs_value_is_string ||
0272 (!*param->string && !(p->flags & fs_param_can_be_empty)))
0273 return fs_param_bad_value(log, param);
0274 return 0;
0275 }
0276 EXPORT_SYMBOL(fs_param_is_string);
0277
0278 int fs_param_is_blob(struct p_log *log, const struct fs_parameter_spec *p,
0279 struct fs_parameter *param, struct fs_parse_result *result)
0280 {
0281 if (param->type != fs_value_is_blob)
0282 return fs_param_bad_value(log, param);
0283 return 0;
0284 }
0285 EXPORT_SYMBOL(fs_param_is_blob);
0286
0287 int fs_param_is_fd(struct p_log *log, const struct fs_parameter_spec *p,
0288 struct fs_parameter *param, struct fs_parse_result *result)
0289 {
0290 switch (param->type) {
0291 case fs_value_is_string:
0292 if ((!*param->string && !(p->flags & fs_param_can_be_empty)) ||
0293 kstrtouint(param->string, 0, &result->uint_32) < 0)
0294 break;
0295 if (result->uint_32 <= INT_MAX)
0296 return 0;
0297 break;
0298 case fs_value_is_file:
0299 result->uint_32 = param->dirfd;
0300 if (result->uint_32 <= INT_MAX)
0301 return 0;
0302 break;
0303 default:
0304 break;
0305 }
0306 return fs_param_bad_value(log, param);
0307 }
0308 EXPORT_SYMBOL(fs_param_is_fd);
0309
0310 int fs_param_is_blockdev(struct p_log *log, const struct fs_parameter_spec *p,
0311 struct fs_parameter *param, struct fs_parse_result *result)
0312 {
0313 return 0;
0314 }
0315 EXPORT_SYMBOL(fs_param_is_blockdev);
0316
0317 int fs_param_is_path(struct p_log *log, const struct fs_parameter_spec *p,
0318 struct fs_parameter *param, struct fs_parse_result *result)
0319 {
0320 return 0;
0321 }
0322 EXPORT_SYMBOL(fs_param_is_path);
0323
0324 #ifdef CONFIG_VALIDATE_FS_PARSER
0325
0326
0327
0328
0329
0330
0331
0332
0333 bool validate_constant_table(const struct constant_table *tbl, size_t tbl_size,
0334 int low, int high, int special)
0335 {
0336 size_t i;
0337 bool good = true;
0338
0339 if (tbl_size == 0) {
0340 pr_warn("VALIDATE C-TBL: Empty\n");
0341 return true;
0342 }
0343
0344 for (i = 0; i < tbl_size; i++) {
0345 if (!tbl[i].name) {
0346 pr_err("VALIDATE C-TBL[%zu]: Null\n", i);
0347 good = false;
0348 } else if (i > 0 && tbl[i - 1].name) {
0349 int c = strcmp(tbl[i-1].name, tbl[i].name);
0350
0351 if (c == 0) {
0352 pr_err("VALIDATE C-TBL[%zu]: Duplicate %s\n",
0353 i, tbl[i].name);
0354 good = false;
0355 }
0356 if (c > 0) {
0357 pr_err("VALIDATE C-TBL[%zu]: Missorted %s>=%s\n",
0358 i, tbl[i-1].name, tbl[i].name);
0359 good = false;
0360 }
0361 }
0362
0363 if (tbl[i].value != special &&
0364 (tbl[i].value < low || tbl[i].value > high)) {
0365 pr_err("VALIDATE C-TBL[%zu]: %s->%d const out of range (%d-%d)\n",
0366 i, tbl[i].name, tbl[i].value, low, high);
0367 good = false;
0368 }
0369 }
0370
0371 return good;
0372 }
0373
0374
0375
0376
0377
0378
0379 bool fs_validate_description(const char *name,
0380 const struct fs_parameter_spec *desc)
0381 {
0382 const struct fs_parameter_spec *param, *p2;
0383 bool good = true;
0384
0385 for (param = desc; param->name; param++) {
0386
0387 for (p2 = desc; p2 < param; p2++) {
0388 if (strcmp(param->name, p2->name) == 0) {
0389 if (is_flag(param) != is_flag(p2))
0390 continue;
0391 pr_err("VALIDATE %s: PARAM[%s]: Duplicate\n",
0392 name, param->name);
0393 good = false;
0394 }
0395 }
0396 }
0397 return good;
0398 }
0399 #endif