1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved. 4 */ 5 6 #include <linux/err.h> 7 #include <linux/slab.h> 8 #include <linux/parser.h> 9 #include <linux/types.h> 10 #include <linux/ctype.h> 11 12 #include "policy.h" 13 #include "policy_parser.h" 14 #include "digest.h" 15 16 #define START_COMMENT '#' 17 #define IPE_POLICY_DELIM " \t" 18 #define IPE_LINE_DELIM "\n\r" 19 20 /** 21 * new_parsed_policy() - Allocate and initialize a parsed policy. 22 * 23 * Return: 24 * * a pointer to the ipe_parsed_policy structure - Success 25 * * %-ENOMEM - Out of memory (OOM) 26 */ 27 static struct ipe_parsed_policy *new_parsed_policy(void) 28 { 29 struct ipe_parsed_policy *p = NULL; 30 struct ipe_op_table *t = NULL; 31 size_t i = 0; 32 33 p = kzalloc(sizeof(*p), GFP_KERNEL); 34 if (!p) 35 return ERR_PTR(-ENOMEM); 36 37 p->global_default_action = IPE_ACTION_INVALID; 38 39 for (i = 0; i < ARRAY_SIZE(p->rules); ++i) { 40 t = &p->rules[i]; 41 42 t->default_action = IPE_ACTION_INVALID; 43 INIT_LIST_HEAD(&t->rules); 44 } 45 46 return p; 47 } 48 49 /** 50 * remove_comment() - Truncate all chars following START_COMMENT in a string. 51 * 52 * @line: Supplies a policy line string for preprocessing. 53 */ 54 static void remove_comment(char *line) 55 { 56 line = strchr(line, START_COMMENT); 57 58 if (line) 59 *line = '\0'; 60 } 61 62 /** 63 * remove_trailing_spaces() - Truncate all trailing spaces in a string. 64 * 65 * @line: Supplies a policy line string for preprocessing. 66 * 67 * Return: The length of truncated string. 68 */ 69 static size_t remove_trailing_spaces(char *line) 70 { 71 size_t i = 0; 72 73 i = strlen(line); 74 while (i > 0 && isspace(line[i - 1])) 75 i--; 76 77 line[i] = '\0'; 78 79 return i; 80 } 81 82 /** 83 * parse_version() - Parse policy version. 84 * @ver: Supplies a version string to be parsed. 85 * @p: Supplies the partial parsed policy. 86 * 87 * Return: 88 * * %0 - Success 89 * * %-EBADMSG - Version string is invalid 90 * * %-ERANGE - Version number overflow 91 * * %-EINVAL - Parsing error 92 */ 93 static int parse_version(char *ver, struct ipe_parsed_policy *p) 94 { 95 u16 *const cv[] = { &p->version.major, &p->version.minor, &p->version.rev }; 96 size_t sep_count = 0; 97 char *token; 98 int rc = 0; 99 100 while ((token = strsep(&ver, ".")) != NULL) { 101 /* prevent overflow */ 102 if (sep_count >= ARRAY_SIZE(cv)) 103 return -EBADMSG; 104 105 rc = kstrtou16(token, 10, cv[sep_count]); 106 if (rc) 107 return rc; 108 109 ++sep_count; 110 } 111 112 /* prevent underflow */ 113 if (sep_count != ARRAY_SIZE(cv)) 114 return -EBADMSG; 115 116 return 0; 117 } 118 119 enum header_opt { 120 IPE_HEADER_POLICY_NAME = 0, 121 IPE_HEADER_POLICY_VERSION, 122 __IPE_HEADER_MAX 123 }; 124 125 static const match_table_t header_tokens = { 126 {IPE_HEADER_POLICY_NAME, "policy_name=%s"}, 127 {IPE_HEADER_POLICY_VERSION, "policy_version=%s"}, 128 {__IPE_HEADER_MAX, NULL} 129 }; 130 131 /** 132 * parse_header() - Parse policy header information. 133 * @line: Supplies header line to be parsed. 134 * @p: Supplies the partial parsed policy. 135 * 136 * Return: 137 * * %0 - Success 138 * * %-EBADMSG - Header string is invalid 139 * * %-ENOMEM - Out of memory (OOM) 140 * * %-ERANGE - Version number overflow 141 * * %-EINVAL - Version parsing error 142 */ 143 static int parse_header(char *line, struct ipe_parsed_policy *p) 144 { 145 substring_t args[MAX_OPT_ARGS]; 146 char *t, *ver = NULL; 147 size_t idx = 0; 148 int rc = 0; 149 150 while ((t = strsep(&line, IPE_POLICY_DELIM)) != NULL) { 151 int token; 152 153 if (*t == '\0') 154 continue; 155 if (idx >= __IPE_HEADER_MAX) { 156 rc = -EBADMSG; 157 goto out; 158 } 159 160 token = match_token(t, header_tokens, args); 161 if (token != idx) { 162 rc = -EBADMSG; 163 goto out; 164 } 165 166 switch (token) { 167 case IPE_HEADER_POLICY_NAME: 168 p->name = match_strdup(&args[0]); 169 if (!p->name) 170 rc = -ENOMEM; 171 break; 172 case IPE_HEADER_POLICY_VERSION: 173 ver = match_strdup(&args[0]); 174 if (!ver) { 175 rc = -ENOMEM; 176 break; 177 } 178 rc = parse_version(ver, p); 179 break; 180 default: 181 rc = -EBADMSG; 182 } 183 if (rc) 184 goto out; 185 ++idx; 186 } 187 188 if (idx != __IPE_HEADER_MAX) 189 rc = -EBADMSG; 190 191 out: 192 kfree(ver); 193 return rc; 194 } 195 196 /** 197 * token_default() - Determine if the given token is "DEFAULT". 198 * @token: Supplies the token string to be compared. 199 * 200 * Return: 201 * * %false - The token is not "DEFAULT" 202 * * %true - The token is "DEFAULT" 203 */ 204 static bool token_default(char *token) 205 { 206 return !strcmp(token, "DEFAULT"); 207 } 208 209 /** 210 * free_rule() - Free the supplied ipe_rule struct. 211 * @r: Supplies the ipe_rule struct to be freed. 212 * 213 * Free a ipe_rule struct @r. Note @r must be removed from any lists before 214 * calling this function. 215 */ 216 static void free_rule(struct ipe_rule *r) 217 { 218 struct ipe_prop *p, *t; 219 220 if (IS_ERR_OR_NULL(r)) 221 return; 222 223 list_for_each_entry_safe(p, t, &r->props, next) { 224 list_del(&p->next); 225 ipe_digest_free(p->value); 226 kfree(p); 227 } 228 229 kfree(r); 230 } 231 232 static const match_table_t operation_tokens = { 233 {IPE_OP_EXEC, "op=EXECUTE"}, 234 {IPE_OP_FIRMWARE, "op=FIRMWARE"}, 235 {IPE_OP_KERNEL_MODULE, "op=KMODULE"}, 236 {IPE_OP_KEXEC_IMAGE, "op=KEXEC_IMAGE"}, 237 {IPE_OP_KEXEC_INITRAMFS, "op=KEXEC_INITRAMFS"}, 238 {IPE_OP_POLICY, "op=POLICY"}, 239 {IPE_OP_X509, "op=X509_CERT"}, 240 {IPE_OP_INVALID, NULL} 241 }; 242 243 /** 244 * parse_operation() - Parse the operation type given a token string. 245 * @t: Supplies the token string to be parsed. 246 * 247 * Return: The parsed operation type. 248 */ 249 static enum ipe_op_type parse_operation(char *t) 250 { 251 substring_t args[MAX_OPT_ARGS]; 252 253 return match_token(t, operation_tokens, args); 254 } 255 256 static const match_table_t action_tokens = { 257 {IPE_ACTION_ALLOW, "action=ALLOW"}, 258 {IPE_ACTION_DENY, "action=DENY"}, 259 {IPE_ACTION_INVALID, NULL} 260 }; 261 262 /** 263 * parse_action() - Parse the action type given a token string. 264 * @t: Supplies the token string to be parsed. 265 * 266 * Return: The parsed action type. 267 */ 268 static enum ipe_action_type parse_action(char *t) 269 { 270 substring_t args[MAX_OPT_ARGS]; 271 272 return match_token(t, action_tokens, args); 273 } 274 275 static const match_table_t property_tokens = { 276 {IPE_PROP_BOOT_VERIFIED_FALSE, "boot_verified=FALSE"}, 277 {IPE_PROP_BOOT_VERIFIED_TRUE, "boot_verified=TRUE"}, 278 {IPE_PROP_DMV_ROOTHASH, "dmverity_roothash=%s"}, 279 {IPE_PROP_DMV_SIG_FALSE, "dmverity_signature=FALSE"}, 280 {IPE_PROP_DMV_SIG_TRUE, "dmverity_signature=TRUE"}, 281 {IPE_PROP_INVALID, NULL} 282 }; 283 284 /** 285 * parse_property() - Parse a rule property given a token string. 286 * @t: Supplies the token string to be parsed. 287 * @r: Supplies the ipe_rule the parsed property will be associated with. 288 * 289 * This function parses and associates a property with an IPE rule based 290 * on a token string. 291 * 292 * Return: 293 * * %0 - Success 294 * * %-ENOMEM - Out of memory (OOM) 295 * * %-EBADMSG - The supplied token cannot be parsed 296 */ 297 static int parse_property(char *t, struct ipe_rule *r) 298 { 299 substring_t args[MAX_OPT_ARGS]; 300 struct ipe_prop *p = NULL; 301 int rc = 0; 302 int token; 303 char *dup = NULL; 304 305 p = kzalloc(sizeof(*p), GFP_KERNEL); 306 if (!p) 307 return -ENOMEM; 308 309 token = match_token(t, property_tokens, args); 310 311 switch (token) { 312 case IPE_PROP_DMV_ROOTHASH: 313 dup = match_strdup(&args[0]); 314 if (!dup) { 315 rc = -ENOMEM; 316 goto err; 317 } 318 p->value = ipe_digest_parse(dup); 319 if (IS_ERR(p->value)) { 320 rc = PTR_ERR(p->value); 321 goto err; 322 } 323 fallthrough; 324 case IPE_PROP_BOOT_VERIFIED_FALSE: 325 case IPE_PROP_BOOT_VERIFIED_TRUE: 326 case IPE_PROP_DMV_SIG_FALSE: 327 case IPE_PROP_DMV_SIG_TRUE: 328 p->type = token; 329 break; 330 default: 331 rc = -EBADMSG; 332 break; 333 } 334 if (rc) 335 goto err; 336 list_add_tail(&p->next, &r->props); 337 338 out: 339 kfree(dup); 340 return rc; 341 err: 342 kfree(p); 343 goto out; 344 } 345 346 /** 347 * parse_rule() - parse a policy rule line. 348 * @line: Supplies rule line to be parsed. 349 * @p: Supplies the partial parsed policy. 350 * 351 * Return: 352 * * 0 - Success 353 * * %-ENOMEM - Out of memory (OOM) 354 * * %-EBADMSG - Policy syntax error 355 */ 356 static int parse_rule(char *line, struct ipe_parsed_policy *p) 357 { 358 enum ipe_action_type action = IPE_ACTION_INVALID; 359 enum ipe_op_type op = IPE_OP_INVALID; 360 bool is_default_rule = false; 361 struct ipe_rule *r = NULL; 362 bool first_token = true; 363 bool op_parsed = false; 364 int rc = 0; 365 char *t; 366 367 if (IS_ERR_OR_NULL(line)) 368 return -EBADMSG; 369 370 r = kzalloc(sizeof(*r), GFP_KERNEL); 371 if (!r) 372 return -ENOMEM; 373 374 INIT_LIST_HEAD(&r->next); 375 INIT_LIST_HEAD(&r->props); 376 377 while (t = strsep(&line, IPE_POLICY_DELIM), line) { 378 if (*t == '\0') 379 continue; 380 if (first_token && token_default(t)) { 381 is_default_rule = true; 382 } else { 383 if (!op_parsed) { 384 op = parse_operation(t); 385 if (op == IPE_OP_INVALID) 386 rc = -EBADMSG; 387 else 388 op_parsed = true; 389 } else { 390 rc = parse_property(t, r); 391 } 392 } 393 394 if (rc) 395 goto err; 396 first_token = false; 397 } 398 399 action = parse_action(t); 400 if (action == IPE_ACTION_INVALID) { 401 rc = -EBADMSG; 402 goto err; 403 } 404 405 if (is_default_rule) { 406 if (!list_empty(&r->props)) { 407 rc = -EBADMSG; 408 } else if (op == IPE_OP_INVALID) { 409 if (p->global_default_action != IPE_ACTION_INVALID) 410 rc = -EBADMSG; 411 else 412 p->global_default_action = action; 413 } else { 414 if (p->rules[op].default_action != IPE_ACTION_INVALID) 415 rc = -EBADMSG; 416 else 417 p->rules[op].default_action = action; 418 } 419 } else if (op != IPE_OP_INVALID && action != IPE_ACTION_INVALID) { 420 r->op = op; 421 r->action = action; 422 } else { 423 rc = -EBADMSG; 424 } 425 426 if (rc) 427 goto err; 428 if (!is_default_rule) 429 list_add_tail(&r->next, &p->rules[op].rules); 430 else 431 free_rule(r); 432 433 return rc; 434 err: 435 free_rule(r); 436 return rc; 437 } 438 439 /** 440 * ipe_free_parsed_policy() - free a parsed policy structure. 441 * @p: Supplies the parsed policy. 442 */ 443 void ipe_free_parsed_policy(struct ipe_parsed_policy *p) 444 { 445 struct ipe_rule *pp, *t; 446 size_t i = 0; 447 448 if (IS_ERR_OR_NULL(p)) 449 return; 450 451 for (i = 0; i < ARRAY_SIZE(p->rules); ++i) 452 list_for_each_entry_safe(pp, t, &p->rules[i].rules, next) { 453 list_del(&pp->next); 454 free_rule(pp); 455 } 456 457 kfree(p->name); 458 kfree(p); 459 } 460 461 /** 462 * validate_policy() - validate a parsed policy. 463 * @p: Supplies the fully parsed policy. 464 * 465 * Given a policy structure that was just parsed, validate that all 466 * operations have their default rules or a global default rule is set. 467 * 468 * Return: 469 * * %0 - Success 470 * * %-EBADMSG - Policy is invalid 471 */ 472 static int validate_policy(const struct ipe_parsed_policy *p) 473 { 474 size_t i = 0; 475 476 if (p->global_default_action != IPE_ACTION_INVALID) 477 return 0; 478 479 for (i = 0; i < ARRAY_SIZE(p->rules); ++i) { 480 if (p->rules[i].default_action == IPE_ACTION_INVALID) 481 return -EBADMSG; 482 } 483 484 return 0; 485 } 486 487 /** 488 * ipe_parse_policy() - Given a string, parse the string into an IPE policy. 489 * @p: partially filled ipe_policy structure to populate with the result. 490 * it must have text and textlen set. 491 * 492 * Return: 493 * * %0 - Success 494 * * %-EBADMSG - Policy is invalid 495 * * %-ENOMEM - Out of Memory 496 * * %-ERANGE - Policy version number overflow 497 * * %-EINVAL - Policy version parsing error 498 */ 499 int ipe_parse_policy(struct ipe_policy *p) 500 { 501 struct ipe_parsed_policy *pp = NULL; 502 char *policy = NULL, *dup = NULL; 503 bool header_parsed = false; 504 char *line = NULL; 505 size_t len; 506 int rc = 0; 507 508 if (!p->textlen) 509 return -EBADMSG; 510 511 policy = kmemdup_nul(p->text, p->textlen, GFP_KERNEL); 512 if (!policy) 513 return -ENOMEM; 514 dup = policy; 515 516 pp = new_parsed_policy(); 517 if (IS_ERR(pp)) { 518 rc = PTR_ERR(pp); 519 goto out; 520 } 521 522 while ((line = strsep(&policy, IPE_LINE_DELIM)) != NULL) { 523 remove_comment(line); 524 len = remove_trailing_spaces(line); 525 if (!len) 526 continue; 527 528 if (!header_parsed) { 529 rc = parse_header(line, pp); 530 if (rc) 531 goto err; 532 header_parsed = true; 533 } else { 534 rc = parse_rule(line, pp); 535 if (rc) 536 goto err; 537 } 538 } 539 540 if (!header_parsed || validate_policy(pp)) { 541 rc = -EBADMSG; 542 goto err; 543 } 544 545 p->parsed = pp; 546 547 out: 548 kfree(dup); 549 return rc; 550 err: 551 ipe_free_parsed_policy(pp); 552 goto out; 553 } 554