1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved.
7 #include <linux/slab.h>
8 #include <linux/parser.h>
9 #include <linux/types.h>
10 #include <linux/ctype.h>
13 #include "policy_parser.h"
16 #define START_COMMENT '#'
17 #define IPE_POLICY_DELIM " \t"
18 #define IPE_LINE_DELIM "\n\r"
21 * new_parsed_policy() - Allocate and initialize a parsed policy.
24 * * a pointer to the ipe_parsed_policy structure - Success
25 * * %-ENOMEM - Out of memory (OOM)
27 static struct ipe_parsed_policy *new_parsed_policy(void)
29 struct ipe_parsed_policy *p = NULL;
30 struct ipe_op_table *t = NULL;
33 p = kzalloc(sizeof(*p), GFP_KERNEL);
35 return ERR_PTR(-ENOMEM);
37 p->global_default_action = IPE_ACTION_INVALID;
39 for (i = 0; i < ARRAY_SIZE(p->rules); ++i) {
42 t->default_action = IPE_ACTION_INVALID;
43 INIT_LIST_HEAD(&t->rules);
50 * remove_comment() - Truncate all chars following START_COMMENT in a string.
52 * @line: Supplies a policy line string for preprocessing.
54 static void remove_comment(char *line)
56 line = strchr(line, START_COMMENT);
63 * remove_trailing_spaces() - Truncate all trailing spaces in a string.
65 * @line: Supplies a policy line string for preprocessing.
67 * Return: The length of truncated string.
69 static size_t remove_trailing_spaces(char *line)
74 while (i > 0 && isspace(line[i - 1]))
83 * parse_version() - Parse policy version.
84 * @ver: Supplies a version string to be parsed.
85 * @p: Supplies the partial parsed policy.
89 * * %-EBADMSG - Version string is invalid
90 * * %-ERANGE - Version number overflow
91 * * %-EINVAL - Parsing error
93 static int parse_version(char *ver, struct ipe_parsed_policy *p)
95 u16 *const cv[] = { &p->version.major, &p->version.minor, &p->version.rev };
100 while ((token = strsep(&ver, ".")) != NULL) {
101 /* prevent overflow */
102 if (sep_count >= ARRAY_SIZE(cv))
105 rc = kstrtou16(token, 10, cv[sep_count]);
112 /* prevent underflow */
113 if (sep_count != ARRAY_SIZE(cv))
120 IPE_HEADER_POLICY_NAME = 0,
121 IPE_HEADER_POLICY_VERSION,
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}
132 * parse_header() - Parse policy header information.
133 * @line: Supplies header line to be parsed.
134 * @p: Supplies the partial parsed policy.
138 * * %-EBADMSG - Header string is invalid
139 * * %-ENOMEM - Out of memory (OOM)
140 * * %-ERANGE - Version number overflow
141 * * %-EINVAL - Version parsing error
143 static int parse_header(char *line, struct ipe_parsed_policy *p)
145 substring_t args[MAX_OPT_ARGS];
146 char *t, *ver = NULL;
150 while ((t = strsep(&line, IPE_POLICY_DELIM)) != NULL) {
155 if (idx >= __IPE_HEADER_MAX) {
160 token = match_token(t, header_tokens, args);
167 case IPE_HEADER_POLICY_NAME:
168 p->name = match_strdup(&args[0]);
172 case IPE_HEADER_POLICY_VERSION:
173 ver = match_strdup(&args[0]);
178 rc = parse_version(ver, p);
188 if (idx != __IPE_HEADER_MAX)
197 * token_default() - Determine if the given token is "DEFAULT".
198 * @token: Supplies the token string to be compared.
201 * * %false - The token is not "DEFAULT"
202 * * %true - The token is "DEFAULT"
204 static bool token_default(char *token)
206 return !strcmp(token, "DEFAULT");
210 * free_rule() - Free the supplied ipe_rule struct.
211 * @r: Supplies the ipe_rule struct to be freed.
213 * Free a ipe_rule struct @r. Note @r must be removed from any lists before
214 * calling this function.
216 static void free_rule(struct ipe_rule *r)
218 struct ipe_prop *p, *t;
220 if (IS_ERR_OR_NULL(r))
223 list_for_each_entry_safe(p, t, &r->props, next) {
225 ipe_digest_free(p->value);
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}
244 * parse_operation() - Parse the operation type given a token string.
245 * @t: Supplies the token string to be parsed.
247 * Return: The parsed operation type.
249 static enum ipe_op_type parse_operation(char *t)
251 substring_t args[MAX_OPT_ARGS];
253 return match_token(t, operation_tokens, args);
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}
263 * parse_action() - Parse the action type given a token string.
264 * @t: Supplies the token string to be parsed.
266 * Return: The parsed action type.
268 static enum ipe_action_type parse_action(char *t)
270 substring_t args[MAX_OPT_ARGS];
272 return match_token(t, action_tokens, args);
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_FSV_DIGEST, "fsverity_digest=%s"},
282 {IPE_PROP_FSV_SIG_FALSE, "fsverity_signature=FALSE"},
283 {IPE_PROP_FSV_SIG_TRUE, "fsverity_signature=TRUE"},
284 {IPE_PROP_INVALID, NULL}
288 * parse_property() - Parse a rule property given a token string.
289 * @t: Supplies the token string to be parsed.
290 * @r: Supplies the ipe_rule the parsed property will be associated with.
292 * This function parses and associates a property with an IPE rule based
297 * * %-ENOMEM - Out of memory (OOM)
298 * * %-EBADMSG - The supplied token cannot be parsed
300 static int parse_property(char *t, struct ipe_rule *r)
302 substring_t args[MAX_OPT_ARGS];
303 struct ipe_prop *p = NULL;
308 p = kzalloc(sizeof(*p), GFP_KERNEL);
312 token = match_token(t, property_tokens, args);
315 case IPE_PROP_DMV_ROOTHASH:
316 case IPE_PROP_FSV_DIGEST:
317 dup = match_strdup(&args[0]);
322 p->value = ipe_digest_parse(dup);
323 if (IS_ERR(p->value)) {
324 rc = PTR_ERR(p->value);
328 case IPE_PROP_BOOT_VERIFIED_FALSE:
329 case IPE_PROP_BOOT_VERIFIED_TRUE:
330 case IPE_PROP_DMV_SIG_FALSE:
331 case IPE_PROP_DMV_SIG_TRUE:
332 case IPE_PROP_FSV_SIG_FALSE:
333 case IPE_PROP_FSV_SIG_TRUE:
342 list_add_tail(&p->next, &r->props);
353 * parse_rule() - parse a policy rule line.
354 * @line: Supplies rule line to be parsed.
355 * @p: Supplies the partial parsed policy.
359 * * %-ENOMEM - Out of memory (OOM)
360 * * %-EBADMSG - Policy syntax error
362 static int parse_rule(char *line, struct ipe_parsed_policy *p)
364 enum ipe_action_type action = IPE_ACTION_INVALID;
365 enum ipe_op_type op = IPE_OP_INVALID;
366 bool is_default_rule = false;
367 struct ipe_rule *r = NULL;
368 bool first_token = true;
369 bool op_parsed = false;
373 if (IS_ERR_OR_NULL(line))
376 r = kzalloc(sizeof(*r), GFP_KERNEL);
380 INIT_LIST_HEAD(&r->next);
381 INIT_LIST_HEAD(&r->props);
383 while (t = strsep(&line, IPE_POLICY_DELIM), line) {
386 if (first_token && token_default(t)) {
387 is_default_rule = true;
390 op = parse_operation(t);
391 if (op == IPE_OP_INVALID)
396 rc = parse_property(t, r);
405 action = parse_action(t);
406 if (action == IPE_ACTION_INVALID) {
411 if (is_default_rule) {
412 if (!list_empty(&r->props)) {
414 } else if (op == IPE_OP_INVALID) {
415 if (p->global_default_action != IPE_ACTION_INVALID)
418 p->global_default_action = action;
420 if (p->rules[op].default_action != IPE_ACTION_INVALID)
423 p->rules[op].default_action = action;
425 } else if (op != IPE_OP_INVALID && action != IPE_ACTION_INVALID) {
434 if (!is_default_rule)
435 list_add_tail(&r->next, &p->rules[op].rules);
446 * ipe_free_parsed_policy() - free a parsed policy structure.
447 * @p: Supplies the parsed policy.
449 void ipe_free_parsed_policy(struct ipe_parsed_policy *p)
451 struct ipe_rule *pp, *t;
454 if (IS_ERR_OR_NULL(p))
457 for (i = 0; i < ARRAY_SIZE(p->rules); ++i)
458 list_for_each_entry_safe(pp, t, &p->rules[i].rules, next) {
468 * validate_policy() - validate a parsed policy.
469 * @p: Supplies the fully parsed policy.
471 * Given a policy structure that was just parsed, validate that all
472 * operations have their default rules or a global default rule is set.
476 * * %-EBADMSG - Policy is invalid
478 static int validate_policy(const struct ipe_parsed_policy *p)
482 if (p->global_default_action != IPE_ACTION_INVALID)
485 for (i = 0; i < ARRAY_SIZE(p->rules); ++i) {
486 if (p->rules[i].default_action == IPE_ACTION_INVALID)
494 * ipe_parse_policy() - Given a string, parse the string into an IPE policy.
495 * @p: partially filled ipe_policy structure to populate with the result.
496 * it must have text and textlen set.
500 * * %-EBADMSG - Policy is invalid
501 * * %-ENOMEM - Out of Memory
502 * * %-ERANGE - Policy version number overflow
503 * * %-EINVAL - Policy version parsing error
505 int ipe_parse_policy(struct ipe_policy *p)
507 struct ipe_parsed_policy *pp = NULL;
508 char *policy = NULL, *dup = NULL;
509 bool header_parsed = false;
517 policy = kmemdup_nul(p->text, p->textlen, GFP_KERNEL);
522 pp = new_parsed_policy();
528 while ((line = strsep(&policy, IPE_LINE_DELIM)) != NULL) {
529 remove_comment(line);
530 len = remove_trailing_spaces(line);
534 if (!header_parsed) {
535 rc = parse_header(line, pp);
538 header_parsed = true;
540 rc = parse_rule(line, pp);
546 if (!header_parsed || validate_policy(pp)) {
557 ipe_free_parsed_policy(pp);