154a88cd2SDeven Bowers // SPDX-License-Identifier: GPL-2.0
254a88cd2SDeven Bowers /*
354a88cd2SDeven Bowers * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved.
454a88cd2SDeven Bowers */
554a88cd2SDeven Bowers
654a88cd2SDeven Bowers #include <linux/err.h>
754a88cd2SDeven Bowers #include <linux/slab.h>
854a88cd2SDeven Bowers #include <linux/parser.h>
954a88cd2SDeven Bowers #include <linux/types.h>
1054a88cd2SDeven Bowers #include <linux/ctype.h>
1154a88cd2SDeven Bowers
1254a88cd2SDeven Bowers #include "policy.h"
1354a88cd2SDeven Bowers #include "policy_parser.h"
14e155858dSDeven Bowers #include "digest.h"
1554a88cd2SDeven Bowers
1654a88cd2SDeven Bowers #define START_COMMENT '#'
1754a88cd2SDeven Bowers #define IPE_POLICY_DELIM " \t"
1854a88cd2SDeven Bowers #define IPE_LINE_DELIM "\n\r"
1954a88cd2SDeven Bowers
2054a88cd2SDeven Bowers /**
2154a88cd2SDeven Bowers * new_parsed_policy() - Allocate and initialize a parsed policy.
2254a88cd2SDeven Bowers *
2354a88cd2SDeven Bowers * Return:
2454a88cd2SDeven Bowers * * a pointer to the ipe_parsed_policy structure - Success
2554a88cd2SDeven Bowers * * %-ENOMEM - Out of memory (OOM)
2654a88cd2SDeven Bowers */
new_parsed_policy(void)2754a88cd2SDeven Bowers static struct ipe_parsed_policy *new_parsed_policy(void)
2854a88cd2SDeven Bowers {
2954a88cd2SDeven Bowers struct ipe_parsed_policy *p = NULL;
3054a88cd2SDeven Bowers struct ipe_op_table *t = NULL;
3154a88cd2SDeven Bowers size_t i = 0;
3254a88cd2SDeven Bowers
3354a88cd2SDeven Bowers p = kzalloc(sizeof(*p), GFP_KERNEL);
3454a88cd2SDeven Bowers if (!p)
3554a88cd2SDeven Bowers return ERR_PTR(-ENOMEM);
3654a88cd2SDeven Bowers
3754a88cd2SDeven Bowers p->global_default_action = IPE_ACTION_INVALID;
3854a88cd2SDeven Bowers
3954a88cd2SDeven Bowers for (i = 0; i < ARRAY_SIZE(p->rules); ++i) {
4054a88cd2SDeven Bowers t = &p->rules[i];
4154a88cd2SDeven Bowers
4254a88cd2SDeven Bowers t->default_action = IPE_ACTION_INVALID;
4354a88cd2SDeven Bowers INIT_LIST_HEAD(&t->rules);
4454a88cd2SDeven Bowers }
4554a88cd2SDeven Bowers
4654a88cd2SDeven Bowers return p;
4754a88cd2SDeven Bowers }
4854a88cd2SDeven Bowers
4954a88cd2SDeven Bowers /**
5054a88cd2SDeven Bowers * remove_comment() - Truncate all chars following START_COMMENT in a string.
5154a88cd2SDeven Bowers *
5254a88cd2SDeven Bowers * @line: Supplies a policy line string for preprocessing.
5354a88cd2SDeven Bowers */
remove_comment(char * line)5454a88cd2SDeven Bowers static void remove_comment(char *line)
5554a88cd2SDeven Bowers {
5654a88cd2SDeven Bowers line = strchr(line, START_COMMENT);
5754a88cd2SDeven Bowers
5854a88cd2SDeven Bowers if (line)
5954a88cd2SDeven Bowers *line = '\0';
6054a88cd2SDeven Bowers }
6154a88cd2SDeven Bowers
6254a88cd2SDeven Bowers /**
6354a88cd2SDeven Bowers * remove_trailing_spaces() - Truncate all trailing spaces in a string.
6454a88cd2SDeven Bowers *
6554a88cd2SDeven Bowers * @line: Supplies a policy line string for preprocessing.
6654a88cd2SDeven Bowers *
6754a88cd2SDeven Bowers * Return: The length of truncated string.
6854a88cd2SDeven Bowers */
remove_trailing_spaces(char * line)6954a88cd2SDeven Bowers static size_t remove_trailing_spaces(char *line)
7054a88cd2SDeven Bowers {
7154a88cd2SDeven Bowers size_t i = 0;
7254a88cd2SDeven Bowers
7354a88cd2SDeven Bowers i = strlen(line);
7454a88cd2SDeven Bowers while (i > 0 && isspace(line[i - 1]))
7554a88cd2SDeven Bowers i--;
7654a88cd2SDeven Bowers
7754a88cd2SDeven Bowers line[i] = '\0';
7854a88cd2SDeven Bowers
7954a88cd2SDeven Bowers return i;
8054a88cd2SDeven Bowers }
8154a88cd2SDeven Bowers
8254a88cd2SDeven Bowers /**
8354a88cd2SDeven Bowers * parse_version() - Parse policy version.
8454a88cd2SDeven Bowers * @ver: Supplies a version string to be parsed.
8554a88cd2SDeven Bowers * @p: Supplies the partial parsed policy.
8654a88cd2SDeven Bowers *
8754a88cd2SDeven Bowers * Return:
8854a88cd2SDeven Bowers * * %0 - Success
8954a88cd2SDeven Bowers * * %-EBADMSG - Version string is invalid
9054a88cd2SDeven Bowers * * %-ERANGE - Version number overflow
9154a88cd2SDeven Bowers * * %-EINVAL - Parsing error
9254a88cd2SDeven Bowers */
parse_version(char * ver,struct ipe_parsed_policy * p)9354a88cd2SDeven Bowers static int parse_version(char *ver, struct ipe_parsed_policy *p)
9454a88cd2SDeven Bowers {
9554a88cd2SDeven Bowers u16 *const cv[] = { &p->version.major, &p->version.minor, &p->version.rev };
9654a88cd2SDeven Bowers size_t sep_count = 0;
9754a88cd2SDeven Bowers char *token;
9854a88cd2SDeven Bowers int rc = 0;
9954a88cd2SDeven Bowers
10054a88cd2SDeven Bowers while ((token = strsep(&ver, ".")) != NULL) {
10154a88cd2SDeven Bowers /* prevent overflow */
10254a88cd2SDeven Bowers if (sep_count >= ARRAY_SIZE(cv))
10354a88cd2SDeven Bowers return -EBADMSG;
10454a88cd2SDeven Bowers
10554a88cd2SDeven Bowers rc = kstrtou16(token, 10, cv[sep_count]);
10654a88cd2SDeven Bowers if (rc)
10754a88cd2SDeven Bowers return rc;
10854a88cd2SDeven Bowers
10954a88cd2SDeven Bowers ++sep_count;
11054a88cd2SDeven Bowers }
11154a88cd2SDeven Bowers
11254a88cd2SDeven Bowers /* prevent underflow */
11354a88cd2SDeven Bowers if (sep_count != ARRAY_SIZE(cv))
11454a88cd2SDeven Bowers return -EBADMSG;
11554a88cd2SDeven Bowers
11654a88cd2SDeven Bowers return 0;
11754a88cd2SDeven Bowers }
11854a88cd2SDeven Bowers
11954a88cd2SDeven Bowers enum header_opt {
12054a88cd2SDeven Bowers IPE_HEADER_POLICY_NAME = 0,
12154a88cd2SDeven Bowers IPE_HEADER_POLICY_VERSION,
12254a88cd2SDeven Bowers __IPE_HEADER_MAX
12354a88cd2SDeven Bowers };
12454a88cd2SDeven Bowers
12554a88cd2SDeven Bowers static const match_table_t header_tokens = {
12654a88cd2SDeven Bowers {IPE_HEADER_POLICY_NAME, "policy_name=%s"},
12754a88cd2SDeven Bowers {IPE_HEADER_POLICY_VERSION, "policy_version=%s"},
12854a88cd2SDeven Bowers {__IPE_HEADER_MAX, NULL}
12954a88cd2SDeven Bowers };
13054a88cd2SDeven Bowers
13154a88cd2SDeven Bowers /**
13254a88cd2SDeven Bowers * parse_header() - Parse policy header information.
13354a88cd2SDeven Bowers * @line: Supplies header line to be parsed.
13454a88cd2SDeven Bowers * @p: Supplies the partial parsed policy.
13554a88cd2SDeven Bowers *
13654a88cd2SDeven Bowers * Return:
13754a88cd2SDeven Bowers * * %0 - Success
13854a88cd2SDeven Bowers * * %-EBADMSG - Header string is invalid
13954a88cd2SDeven Bowers * * %-ENOMEM - Out of memory (OOM)
14054a88cd2SDeven Bowers * * %-ERANGE - Version number overflow
14154a88cd2SDeven Bowers * * %-EINVAL - Version parsing error
14254a88cd2SDeven Bowers */
parse_header(char * line,struct ipe_parsed_policy * p)14354a88cd2SDeven Bowers static int parse_header(char *line, struct ipe_parsed_policy *p)
14454a88cd2SDeven Bowers {
14554a88cd2SDeven Bowers substring_t args[MAX_OPT_ARGS];
14654a88cd2SDeven Bowers char *t, *ver = NULL;
14754a88cd2SDeven Bowers size_t idx = 0;
14854a88cd2SDeven Bowers int rc = 0;
14954a88cd2SDeven Bowers
15054a88cd2SDeven Bowers while ((t = strsep(&line, IPE_POLICY_DELIM)) != NULL) {
15154a88cd2SDeven Bowers int token;
15254a88cd2SDeven Bowers
15354a88cd2SDeven Bowers if (*t == '\0')
15454a88cd2SDeven Bowers continue;
15554a88cd2SDeven Bowers if (idx >= __IPE_HEADER_MAX) {
15654a88cd2SDeven Bowers rc = -EBADMSG;
15754a88cd2SDeven Bowers goto out;
15854a88cd2SDeven Bowers }
15954a88cd2SDeven Bowers
16054a88cd2SDeven Bowers token = match_token(t, header_tokens, args);
16154a88cd2SDeven Bowers if (token != idx) {
16254a88cd2SDeven Bowers rc = -EBADMSG;
16354a88cd2SDeven Bowers goto out;
16454a88cd2SDeven Bowers }
16554a88cd2SDeven Bowers
16654a88cd2SDeven Bowers switch (token) {
16754a88cd2SDeven Bowers case IPE_HEADER_POLICY_NAME:
16854a88cd2SDeven Bowers p->name = match_strdup(&args[0]);
16954a88cd2SDeven Bowers if (!p->name)
17054a88cd2SDeven Bowers rc = -ENOMEM;
17154a88cd2SDeven Bowers break;
17254a88cd2SDeven Bowers case IPE_HEADER_POLICY_VERSION:
17354a88cd2SDeven Bowers ver = match_strdup(&args[0]);
17454a88cd2SDeven Bowers if (!ver) {
17554a88cd2SDeven Bowers rc = -ENOMEM;
17654a88cd2SDeven Bowers break;
17754a88cd2SDeven Bowers }
17854a88cd2SDeven Bowers rc = parse_version(ver, p);
17954a88cd2SDeven Bowers break;
18054a88cd2SDeven Bowers default:
18154a88cd2SDeven Bowers rc = -EBADMSG;
18254a88cd2SDeven Bowers }
18354a88cd2SDeven Bowers if (rc)
18454a88cd2SDeven Bowers goto out;
18554a88cd2SDeven Bowers ++idx;
18654a88cd2SDeven Bowers }
18754a88cd2SDeven Bowers
18854a88cd2SDeven Bowers if (idx != __IPE_HEADER_MAX)
18954a88cd2SDeven Bowers rc = -EBADMSG;
19054a88cd2SDeven Bowers
19154a88cd2SDeven Bowers out:
19254a88cd2SDeven Bowers kfree(ver);
19354a88cd2SDeven Bowers return rc;
19454a88cd2SDeven Bowers }
19554a88cd2SDeven Bowers
19654a88cd2SDeven Bowers /**
19754a88cd2SDeven Bowers * token_default() - Determine if the given token is "DEFAULT".
19854a88cd2SDeven Bowers * @token: Supplies the token string to be compared.
19954a88cd2SDeven Bowers *
20054a88cd2SDeven Bowers * Return:
20154a88cd2SDeven Bowers * * %false - The token is not "DEFAULT"
20254a88cd2SDeven Bowers * * %true - The token is "DEFAULT"
20354a88cd2SDeven Bowers */
token_default(char * token)20454a88cd2SDeven Bowers static bool token_default(char *token)
20554a88cd2SDeven Bowers {
20654a88cd2SDeven Bowers return !strcmp(token, "DEFAULT");
20754a88cd2SDeven Bowers }
20854a88cd2SDeven Bowers
20954a88cd2SDeven Bowers /**
21054a88cd2SDeven Bowers * free_rule() - Free the supplied ipe_rule struct.
21154a88cd2SDeven Bowers * @r: Supplies the ipe_rule struct to be freed.
21254a88cd2SDeven Bowers *
21354a88cd2SDeven Bowers * Free a ipe_rule struct @r. Note @r must be removed from any lists before
21454a88cd2SDeven Bowers * calling this function.
21554a88cd2SDeven Bowers */
free_rule(struct ipe_rule * r)21654a88cd2SDeven Bowers static void free_rule(struct ipe_rule *r)
21754a88cd2SDeven Bowers {
21854a88cd2SDeven Bowers struct ipe_prop *p, *t;
21954a88cd2SDeven Bowers
22054a88cd2SDeven Bowers if (IS_ERR_OR_NULL(r))
22154a88cd2SDeven Bowers return;
22254a88cd2SDeven Bowers
22354a88cd2SDeven Bowers list_for_each_entry_safe(p, t, &r->props, next) {
22454a88cd2SDeven Bowers list_del(&p->next);
225e155858dSDeven Bowers ipe_digest_free(p->value);
22654a88cd2SDeven Bowers kfree(p);
22754a88cd2SDeven Bowers }
22854a88cd2SDeven Bowers
22954a88cd2SDeven Bowers kfree(r);
23054a88cd2SDeven Bowers }
23154a88cd2SDeven Bowers
23254a88cd2SDeven Bowers static const match_table_t operation_tokens = {
23354a88cd2SDeven Bowers {IPE_OP_EXEC, "op=EXECUTE"},
23454a88cd2SDeven Bowers {IPE_OP_FIRMWARE, "op=FIRMWARE"},
23554a88cd2SDeven Bowers {IPE_OP_KERNEL_MODULE, "op=KMODULE"},
23654a88cd2SDeven Bowers {IPE_OP_KEXEC_IMAGE, "op=KEXEC_IMAGE"},
23754a88cd2SDeven Bowers {IPE_OP_KEXEC_INITRAMFS, "op=KEXEC_INITRAMFS"},
23854a88cd2SDeven Bowers {IPE_OP_POLICY, "op=POLICY"},
23954a88cd2SDeven Bowers {IPE_OP_X509, "op=X509_CERT"},
24054a88cd2SDeven Bowers {IPE_OP_INVALID, NULL}
24154a88cd2SDeven Bowers };
24254a88cd2SDeven Bowers
24354a88cd2SDeven Bowers /**
24454a88cd2SDeven Bowers * parse_operation() - Parse the operation type given a token string.
24554a88cd2SDeven Bowers * @t: Supplies the token string to be parsed.
24654a88cd2SDeven Bowers *
24754a88cd2SDeven Bowers * Return: The parsed operation type.
24854a88cd2SDeven Bowers */
parse_operation(char * t)24954a88cd2SDeven Bowers static enum ipe_op_type parse_operation(char *t)
25054a88cd2SDeven Bowers {
25154a88cd2SDeven Bowers substring_t args[MAX_OPT_ARGS];
25254a88cd2SDeven Bowers
25354a88cd2SDeven Bowers return match_token(t, operation_tokens, args);
25454a88cd2SDeven Bowers }
25554a88cd2SDeven Bowers
25654a88cd2SDeven Bowers static const match_table_t action_tokens = {
25754a88cd2SDeven Bowers {IPE_ACTION_ALLOW, "action=ALLOW"},
25854a88cd2SDeven Bowers {IPE_ACTION_DENY, "action=DENY"},
25954a88cd2SDeven Bowers {IPE_ACTION_INVALID, NULL}
26054a88cd2SDeven Bowers };
26154a88cd2SDeven Bowers
26254a88cd2SDeven Bowers /**
26354a88cd2SDeven Bowers * parse_action() - Parse the action type given a token string.
26454a88cd2SDeven Bowers * @t: Supplies the token string to be parsed.
26554a88cd2SDeven Bowers *
26654a88cd2SDeven Bowers * Return: The parsed action type.
26754a88cd2SDeven Bowers */
parse_action(char * t)26854a88cd2SDeven Bowers static enum ipe_action_type parse_action(char *t)
26954a88cd2SDeven Bowers {
27054a88cd2SDeven Bowers substring_t args[MAX_OPT_ARGS];
27154a88cd2SDeven Bowers
27254a88cd2SDeven Bowers return match_token(t, action_tokens, args);
27354a88cd2SDeven Bowers }
27454a88cd2SDeven Bowers
275a8a74df1SFan Wu static const match_table_t property_tokens = {
276a8a74df1SFan Wu {IPE_PROP_BOOT_VERIFIED_FALSE, "boot_verified=FALSE"},
277a8a74df1SFan Wu {IPE_PROP_BOOT_VERIFIED_TRUE, "boot_verified=TRUE"},
278e155858dSDeven Bowers {IPE_PROP_DMV_ROOTHASH, "dmverity_roothash=%s"},
279e155858dSDeven Bowers {IPE_PROP_DMV_SIG_FALSE, "dmverity_signature=FALSE"},
280e155858dSDeven Bowers {IPE_PROP_DMV_SIG_TRUE, "dmverity_signature=TRUE"},
281*31f8c868SFan Wu {IPE_PROP_FSV_DIGEST, "fsverity_digest=%s"},
282*31f8c868SFan Wu {IPE_PROP_FSV_SIG_FALSE, "fsverity_signature=FALSE"},
283*31f8c868SFan Wu {IPE_PROP_FSV_SIG_TRUE, "fsverity_signature=TRUE"},
284a8a74df1SFan Wu {IPE_PROP_INVALID, NULL}
285a8a74df1SFan Wu };
286a8a74df1SFan Wu
28754a88cd2SDeven Bowers /**
28854a88cd2SDeven Bowers * parse_property() - Parse a rule property given a token string.
28954a88cd2SDeven Bowers * @t: Supplies the token string to be parsed.
29054a88cd2SDeven Bowers * @r: Supplies the ipe_rule the parsed property will be associated with.
29154a88cd2SDeven Bowers *
292a8a74df1SFan Wu * This function parses and associates a property with an IPE rule based
293a8a74df1SFan Wu * on a token string.
29454a88cd2SDeven Bowers *
29554a88cd2SDeven Bowers * Return:
29654a88cd2SDeven Bowers * * %0 - Success
29754a88cd2SDeven Bowers * * %-ENOMEM - Out of memory (OOM)
29854a88cd2SDeven Bowers * * %-EBADMSG - The supplied token cannot be parsed
29954a88cd2SDeven Bowers */
parse_property(char * t,struct ipe_rule * r)30054a88cd2SDeven Bowers static int parse_property(char *t, struct ipe_rule *r)
30154a88cd2SDeven Bowers {
302a8a74df1SFan Wu substring_t args[MAX_OPT_ARGS];
303a8a74df1SFan Wu struct ipe_prop *p = NULL;
304a8a74df1SFan Wu int rc = 0;
305a8a74df1SFan Wu int token;
306e155858dSDeven Bowers char *dup = NULL;
307a8a74df1SFan Wu
308a8a74df1SFan Wu p = kzalloc(sizeof(*p), GFP_KERNEL);
309a8a74df1SFan Wu if (!p)
310a8a74df1SFan Wu return -ENOMEM;
311a8a74df1SFan Wu
312a8a74df1SFan Wu token = match_token(t, property_tokens, args);
313a8a74df1SFan Wu
314a8a74df1SFan Wu switch (token) {
315e155858dSDeven Bowers case IPE_PROP_DMV_ROOTHASH:
316*31f8c868SFan Wu case IPE_PROP_FSV_DIGEST:
317e155858dSDeven Bowers dup = match_strdup(&args[0]);
318e155858dSDeven Bowers if (!dup) {
319e155858dSDeven Bowers rc = -ENOMEM;
320e155858dSDeven Bowers goto err;
321e155858dSDeven Bowers }
322e155858dSDeven Bowers p->value = ipe_digest_parse(dup);
323e155858dSDeven Bowers if (IS_ERR(p->value)) {
324e155858dSDeven Bowers rc = PTR_ERR(p->value);
325e155858dSDeven Bowers goto err;
326e155858dSDeven Bowers }
327e155858dSDeven Bowers fallthrough;
328a8a74df1SFan Wu case IPE_PROP_BOOT_VERIFIED_FALSE:
329a8a74df1SFan Wu case IPE_PROP_BOOT_VERIFIED_TRUE:
330e155858dSDeven Bowers case IPE_PROP_DMV_SIG_FALSE:
331e155858dSDeven Bowers case IPE_PROP_DMV_SIG_TRUE:
332*31f8c868SFan Wu case IPE_PROP_FSV_SIG_FALSE:
333*31f8c868SFan Wu case IPE_PROP_FSV_SIG_TRUE:
334a8a74df1SFan Wu p->type = token;
335a8a74df1SFan Wu break;
336a8a74df1SFan Wu default:
337a8a74df1SFan Wu rc = -EBADMSG;
338a8a74df1SFan Wu break;
339a8a74df1SFan Wu }
340a8a74df1SFan Wu if (rc)
341a8a74df1SFan Wu goto err;
342a8a74df1SFan Wu list_add_tail(&p->next, &r->props);
343a8a74df1SFan Wu
344e155858dSDeven Bowers out:
345e155858dSDeven Bowers kfree(dup);
346a8a74df1SFan Wu return rc;
347a8a74df1SFan Wu err:
348a8a74df1SFan Wu kfree(p);
349e155858dSDeven Bowers goto out;
35054a88cd2SDeven Bowers }
35154a88cd2SDeven Bowers
35254a88cd2SDeven Bowers /**
35354a88cd2SDeven Bowers * parse_rule() - parse a policy rule line.
35454a88cd2SDeven Bowers * @line: Supplies rule line to be parsed.
35554a88cd2SDeven Bowers * @p: Supplies the partial parsed policy.
35654a88cd2SDeven Bowers *
35754a88cd2SDeven Bowers * Return:
35854a88cd2SDeven Bowers * * 0 - Success
35954a88cd2SDeven Bowers * * %-ENOMEM - Out of memory (OOM)
36054a88cd2SDeven Bowers * * %-EBADMSG - Policy syntax error
36154a88cd2SDeven Bowers */
parse_rule(char * line,struct ipe_parsed_policy * p)36254a88cd2SDeven Bowers static int parse_rule(char *line, struct ipe_parsed_policy *p)
36354a88cd2SDeven Bowers {
36454a88cd2SDeven Bowers enum ipe_action_type action = IPE_ACTION_INVALID;
36554a88cd2SDeven Bowers enum ipe_op_type op = IPE_OP_INVALID;
36654a88cd2SDeven Bowers bool is_default_rule = false;
36754a88cd2SDeven Bowers struct ipe_rule *r = NULL;
36854a88cd2SDeven Bowers bool first_token = true;
36954a88cd2SDeven Bowers bool op_parsed = false;
37054a88cd2SDeven Bowers int rc = 0;
37154a88cd2SDeven Bowers char *t;
37254a88cd2SDeven Bowers
37354a88cd2SDeven Bowers if (IS_ERR_OR_NULL(line))
37454a88cd2SDeven Bowers return -EBADMSG;
37554a88cd2SDeven Bowers
37654a88cd2SDeven Bowers r = kzalloc(sizeof(*r), GFP_KERNEL);
37754a88cd2SDeven Bowers if (!r)
37854a88cd2SDeven Bowers return -ENOMEM;
37954a88cd2SDeven Bowers
38054a88cd2SDeven Bowers INIT_LIST_HEAD(&r->next);
38154a88cd2SDeven Bowers INIT_LIST_HEAD(&r->props);
38254a88cd2SDeven Bowers
38354a88cd2SDeven Bowers while (t = strsep(&line, IPE_POLICY_DELIM), line) {
38454a88cd2SDeven Bowers if (*t == '\0')
38554a88cd2SDeven Bowers continue;
38654a88cd2SDeven Bowers if (first_token && token_default(t)) {
38754a88cd2SDeven Bowers is_default_rule = true;
38854a88cd2SDeven Bowers } else {
38954a88cd2SDeven Bowers if (!op_parsed) {
39054a88cd2SDeven Bowers op = parse_operation(t);
39154a88cd2SDeven Bowers if (op == IPE_OP_INVALID)
39254a88cd2SDeven Bowers rc = -EBADMSG;
39354a88cd2SDeven Bowers else
39454a88cd2SDeven Bowers op_parsed = true;
39554a88cd2SDeven Bowers } else {
39654a88cd2SDeven Bowers rc = parse_property(t, r);
39754a88cd2SDeven Bowers }
39854a88cd2SDeven Bowers }
39954a88cd2SDeven Bowers
40054a88cd2SDeven Bowers if (rc)
40154a88cd2SDeven Bowers goto err;
40254a88cd2SDeven Bowers first_token = false;
40354a88cd2SDeven Bowers }
40454a88cd2SDeven Bowers
40554a88cd2SDeven Bowers action = parse_action(t);
40654a88cd2SDeven Bowers if (action == IPE_ACTION_INVALID) {
40754a88cd2SDeven Bowers rc = -EBADMSG;
40854a88cd2SDeven Bowers goto err;
40954a88cd2SDeven Bowers }
41054a88cd2SDeven Bowers
41154a88cd2SDeven Bowers if (is_default_rule) {
41254a88cd2SDeven Bowers if (!list_empty(&r->props)) {
41354a88cd2SDeven Bowers rc = -EBADMSG;
41454a88cd2SDeven Bowers } else if (op == IPE_OP_INVALID) {
41554a88cd2SDeven Bowers if (p->global_default_action != IPE_ACTION_INVALID)
41654a88cd2SDeven Bowers rc = -EBADMSG;
41754a88cd2SDeven Bowers else
41854a88cd2SDeven Bowers p->global_default_action = action;
41954a88cd2SDeven Bowers } else {
42054a88cd2SDeven Bowers if (p->rules[op].default_action != IPE_ACTION_INVALID)
42154a88cd2SDeven Bowers rc = -EBADMSG;
42254a88cd2SDeven Bowers else
42354a88cd2SDeven Bowers p->rules[op].default_action = action;
42454a88cd2SDeven Bowers }
42554a88cd2SDeven Bowers } else if (op != IPE_OP_INVALID && action != IPE_ACTION_INVALID) {
42654a88cd2SDeven Bowers r->op = op;
42754a88cd2SDeven Bowers r->action = action;
42854a88cd2SDeven Bowers } else {
42954a88cd2SDeven Bowers rc = -EBADMSG;
43054a88cd2SDeven Bowers }
43154a88cd2SDeven Bowers
43254a88cd2SDeven Bowers if (rc)
43354a88cd2SDeven Bowers goto err;
43454a88cd2SDeven Bowers if (!is_default_rule)
43554a88cd2SDeven Bowers list_add_tail(&r->next, &p->rules[op].rules);
43654a88cd2SDeven Bowers else
43754a88cd2SDeven Bowers free_rule(r);
43854a88cd2SDeven Bowers
43954a88cd2SDeven Bowers return rc;
44054a88cd2SDeven Bowers err:
44154a88cd2SDeven Bowers free_rule(r);
44254a88cd2SDeven Bowers return rc;
44354a88cd2SDeven Bowers }
44454a88cd2SDeven Bowers
44554a88cd2SDeven Bowers /**
44654a88cd2SDeven Bowers * ipe_free_parsed_policy() - free a parsed policy structure.
44754a88cd2SDeven Bowers * @p: Supplies the parsed policy.
44854a88cd2SDeven Bowers */
ipe_free_parsed_policy(struct ipe_parsed_policy * p)44954a88cd2SDeven Bowers void ipe_free_parsed_policy(struct ipe_parsed_policy *p)
45054a88cd2SDeven Bowers {
45154a88cd2SDeven Bowers struct ipe_rule *pp, *t;
45254a88cd2SDeven Bowers size_t i = 0;
45354a88cd2SDeven Bowers
45454a88cd2SDeven Bowers if (IS_ERR_OR_NULL(p))
45554a88cd2SDeven Bowers return;
45654a88cd2SDeven Bowers
45754a88cd2SDeven Bowers for (i = 0; i < ARRAY_SIZE(p->rules); ++i)
45854a88cd2SDeven Bowers list_for_each_entry_safe(pp, t, &p->rules[i].rules, next) {
45954a88cd2SDeven Bowers list_del(&pp->next);
46054a88cd2SDeven Bowers free_rule(pp);
46154a88cd2SDeven Bowers }
46254a88cd2SDeven Bowers
46354a88cd2SDeven Bowers kfree(p->name);
46454a88cd2SDeven Bowers kfree(p);
46554a88cd2SDeven Bowers }
46654a88cd2SDeven Bowers
46754a88cd2SDeven Bowers /**
46854a88cd2SDeven Bowers * validate_policy() - validate a parsed policy.
46954a88cd2SDeven Bowers * @p: Supplies the fully parsed policy.
47054a88cd2SDeven Bowers *
47154a88cd2SDeven Bowers * Given a policy structure that was just parsed, validate that all
47254a88cd2SDeven Bowers * operations have their default rules or a global default rule is set.
47354a88cd2SDeven Bowers *
47454a88cd2SDeven Bowers * Return:
47554a88cd2SDeven Bowers * * %0 - Success
47654a88cd2SDeven Bowers * * %-EBADMSG - Policy is invalid
47754a88cd2SDeven Bowers */
validate_policy(const struct ipe_parsed_policy * p)47854a88cd2SDeven Bowers static int validate_policy(const struct ipe_parsed_policy *p)
47954a88cd2SDeven Bowers {
48054a88cd2SDeven Bowers size_t i = 0;
48154a88cd2SDeven Bowers
48254a88cd2SDeven Bowers if (p->global_default_action != IPE_ACTION_INVALID)
48354a88cd2SDeven Bowers return 0;
48454a88cd2SDeven Bowers
48554a88cd2SDeven Bowers for (i = 0; i < ARRAY_SIZE(p->rules); ++i) {
48654a88cd2SDeven Bowers if (p->rules[i].default_action == IPE_ACTION_INVALID)
48754a88cd2SDeven Bowers return -EBADMSG;
48854a88cd2SDeven Bowers }
48954a88cd2SDeven Bowers
49054a88cd2SDeven Bowers return 0;
49154a88cd2SDeven Bowers }
49254a88cd2SDeven Bowers
49354a88cd2SDeven Bowers /**
49454a88cd2SDeven Bowers * ipe_parse_policy() - Given a string, parse the string into an IPE policy.
49554a88cd2SDeven Bowers * @p: partially filled ipe_policy structure to populate with the result.
49654a88cd2SDeven Bowers * it must have text and textlen set.
49754a88cd2SDeven Bowers *
49854a88cd2SDeven Bowers * Return:
49954a88cd2SDeven Bowers * * %0 - Success
50054a88cd2SDeven Bowers * * %-EBADMSG - Policy is invalid
50154a88cd2SDeven Bowers * * %-ENOMEM - Out of Memory
50254a88cd2SDeven Bowers * * %-ERANGE - Policy version number overflow
50354a88cd2SDeven Bowers * * %-EINVAL - Policy version parsing error
50454a88cd2SDeven Bowers */
ipe_parse_policy(struct ipe_policy * p)50554a88cd2SDeven Bowers int ipe_parse_policy(struct ipe_policy *p)
50654a88cd2SDeven Bowers {
50754a88cd2SDeven Bowers struct ipe_parsed_policy *pp = NULL;
50854a88cd2SDeven Bowers char *policy = NULL, *dup = NULL;
50954a88cd2SDeven Bowers bool header_parsed = false;
51054a88cd2SDeven Bowers char *line = NULL;
51154a88cd2SDeven Bowers size_t len;
51254a88cd2SDeven Bowers int rc = 0;
51354a88cd2SDeven Bowers
51454a88cd2SDeven Bowers if (!p->textlen)
51554a88cd2SDeven Bowers return -EBADMSG;
51654a88cd2SDeven Bowers
51754a88cd2SDeven Bowers policy = kmemdup_nul(p->text, p->textlen, GFP_KERNEL);
51854a88cd2SDeven Bowers if (!policy)
51954a88cd2SDeven Bowers return -ENOMEM;
52054a88cd2SDeven Bowers dup = policy;
52154a88cd2SDeven Bowers
52254a88cd2SDeven Bowers pp = new_parsed_policy();
52354a88cd2SDeven Bowers if (IS_ERR(pp)) {
52454a88cd2SDeven Bowers rc = PTR_ERR(pp);
52554a88cd2SDeven Bowers goto out;
52654a88cd2SDeven Bowers }
52754a88cd2SDeven Bowers
52854a88cd2SDeven Bowers while ((line = strsep(&policy, IPE_LINE_DELIM)) != NULL) {
52954a88cd2SDeven Bowers remove_comment(line);
53054a88cd2SDeven Bowers len = remove_trailing_spaces(line);
53154a88cd2SDeven Bowers if (!len)
53254a88cd2SDeven Bowers continue;
53354a88cd2SDeven Bowers
53454a88cd2SDeven Bowers if (!header_parsed) {
53554a88cd2SDeven Bowers rc = parse_header(line, pp);
53654a88cd2SDeven Bowers if (rc)
53754a88cd2SDeven Bowers goto err;
53854a88cd2SDeven Bowers header_parsed = true;
53954a88cd2SDeven Bowers } else {
54054a88cd2SDeven Bowers rc = parse_rule(line, pp);
54154a88cd2SDeven Bowers if (rc)
54254a88cd2SDeven Bowers goto err;
54354a88cd2SDeven Bowers }
54454a88cd2SDeven Bowers }
54554a88cd2SDeven Bowers
54654a88cd2SDeven Bowers if (!header_parsed || validate_policy(pp)) {
54754a88cd2SDeven Bowers rc = -EBADMSG;
54854a88cd2SDeven Bowers goto err;
54954a88cd2SDeven Bowers }
55054a88cd2SDeven Bowers
55154a88cd2SDeven Bowers p->parsed = pp;
55254a88cd2SDeven Bowers
55354a88cd2SDeven Bowers out:
55454a88cd2SDeven Bowers kfree(dup);
55554a88cd2SDeven Bowers return rc;
55654a88cd2SDeven Bowers err:
55754a88cd2SDeven Bowers ipe_free_parsed_policy(pp);
55854a88cd2SDeven Bowers goto out;
55954a88cd2SDeven Bowers }
560