xref: /linux/security/ipe/policy_parser.c (revision 6adc404a9867eee83e9555eac36dfd0066fa3839)
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_obj(*p);
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 static_assert(ARRAY_SIZE(header_tokens) == __IPE_HEADER_MAX + 1);
132 
133 /**
134  * parse_header() - Parse policy header information.
135  * @line: Supplies header line to be parsed.
136  * @p: Supplies the partial parsed policy.
137  *
138  * Return:
139  * * %0		- Success
140  * * %-EBADMSG	- Header string is invalid
141  * * %-ENOMEM	- Out of memory (OOM)
142  * * %-ERANGE	- Version number overflow
143  * * %-EINVAL	- Version parsing error
144  */
145 static int parse_header(char *line, struct ipe_parsed_policy *p)
146 {
147 	substring_t args[MAX_OPT_ARGS];
148 	char *t, *ver = NULL;
149 	size_t idx = 0;
150 	int rc = 0;
151 
152 	while ((t = strsep(&line, IPE_POLICY_DELIM)) != NULL) {
153 		int token;
154 
155 		if (*t == '\0')
156 			continue;
157 		if (idx >= __IPE_HEADER_MAX) {
158 			rc = -EBADMSG;
159 			goto out;
160 		}
161 
162 		token = match_token(t, header_tokens, args);
163 		if (token != idx) {
164 			rc = -EBADMSG;
165 			goto out;
166 		}
167 
168 		switch (token) {
169 		case IPE_HEADER_POLICY_NAME:
170 			p->name = match_strdup(&args[0]);
171 			if (!p->name)
172 				rc = -ENOMEM;
173 			break;
174 		case IPE_HEADER_POLICY_VERSION:
175 			ver = match_strdup(&args[0]);
176 			if (!ver) {
177 				rc = -ENOMEM;
178 				break;
179 			}
180 			rc = parse_version(ver, p);
181 			break;
182 		default:
183 			rc = -EBADMSG;
184 		}
185 		if (rc)
186 			goto out;
187 		++idx;
188 	}
189 
190 	if (idx != __IPE_HEADER_MAX)
191 		rc = -EBADMSG;
192 
193 out:
194 	kfree(ver);
195 	return rc;
196 }
197 
198 /**
199  * token_default() - Determine if the given token is "DEFAULT".
200  * @token: Supplies the token string to be compared.
201  *
202  * Return:
203  * * %false	- The token is not "DEFAULT"
204  * * %true	- The token is "DEFAULT"
205  */
206 static bool token_default(const char *token)
207 {
208 	return !strcmp(token, "DEFAULT");
209 }
210 
211 /**
212  * free_rule() - Free the supplied ipe_rule struct.
213  * @r: Supplies the ipe_rule struct to be freed.
214  *
215  * Free a ipe_rule struct @r. Note @r must be removed from any lists before
216  * calling this function.
217  */
218 static void free_rule(struct ipe_rule *r)
219 {
220 	struct ipe_prop *p, *t;
221 
222 	if (IS_ERR_OR_NULL(r))
223 		return;
224 
225 	list_for_each_entry_safe(p, t, &r->props, next) {
226 		list_del(&p->next);
227 		ipe_digest_free(p->value);
228 		kfree(p);
229 	}
230 
231 	kfree(r);
232 }
233 
234 static const match_table_t operation_tokens = {
235 	{IPE_OP_EXEC,			"op=EXECUTE"},
236 	{IPE_OP_FIRMWARE,		"op=FIRMWARE"},
237 	{IPE_OP_KERNEL_MODULE,		"op=KMODULE"},
238 	{IPE_OP_KEXEC_IMAGE,		"op=KEXEC_IMAGE"},
239 	{IPE_OP_KEXEC_INITRAMFS,	"op=KEXEC_INITRAMFS"},
240 	{IPE_OP_POLICY,			"op=POLICY"},
241 	{IPE_OP_X509,			"op=X509_CERT"},
242 	{IPE_OP_INVALID,		NULL}
243 };
244 
245 static_assert(ARRAY_SIZE(operation_tokens) == __IPE_OP_MAX + 1);
246 
247 /**
248  * parse_operation() - Parse the operation type given a token string.
249  * @t: Supplies the token string to be parsed.
250  *
251  * Return: The parsed operation type.
252  */
253 static enum ipe_op_type parse_operation(char *t)
254 {
255 	substring_t args[MAX_OPT_ARGS];
256 
257 	return match_token(t, operation_tokens, args);
258 }
259 
260 static const match_table_t action_tokens = {
261 	{IPE_ACTION_ALLOW,	"action=ALLOW"},
262 	{IPE_ACTION_DENY,	"action=DENY"},
263 	{IPE_ACTION_INVALID,	NULL}
264 };
265 
266 static_assert(ARRAY_SIZE(action_tokens) == __IPE_ACTION_MAX + 1);
267 
268 /**
269  * parse_action() - Parse the action type given a token string.
270  * @t: Supplies the token string to be parsed.
271  *
272  * Return: The parsed action type.
273  */
274 static enum ipe_action_type parse_action(char *t)
275 {
276 	substring_t args[MAX_OPT_ARGS];
277 
278 	return match_token(t, action_tokens, args);
279 }
280 
281 static const match_table_t property_tokens = {
282 	{IPE_PROP_BOOT_VERIFIED_FALSE,	"boot_verified=FALSE"},
283 	{IPE_PROP_BOOT_VERIFIED_TRUE,	"boot_verified=TRUE"},
284 	{IPE_PROP_DMV_ROOTHASH,		"dmverity_roothash=%s"},
285 	{IPE_PROP_DMV_SIG_FALSE,	"dmverity_signature=FALSE"},
286 	{IPE_PROP_DMV_SIG_TRUE,		"dmverity_signature=TRUE"},
287 	{IPE_PROP_FSV_DIGEST,		"fsverity_digest=%s"},
288 	{IPE_PROP_FSV_SIG_FALSE,	"fsverity_signature=FALSE"},
289 	{IPE_PROP_FSV_SIG_TRUE,		"fsverity_signature=TRUE"},
290 	{IPE_PROP_INVALID,		NULL}
291 };
292 
293 static_assert(ARRAY_SIZE(property_tokens) == __IPE_PROP_MAX + 1);
294 
295 /**
296  * parse_property() - Parse a rule property given a token string.
297  * @t: Supplies the token string to be parsed.
298  * @r: Supplies the ipe_rule the parsed property will be associated with.
299  *
300  * This function parses and associates a property with an IPE rule based
301  * on a token string.
302  *
303  * Return:
304  * * %0		- Success
305  * * %-ENOMEM	- Out of memory (OOM)
306  * * %-EBADMSG	- The supplied token cannot be parsed
307  */
308 static int parse_property(char *t, struct ipe_rule *r)
309 {
310 	substring_t args[MAX_OPT_ARGS];
311 	struct ipe_prop *p = NULL;
312 	int rc = 0;
313 	int token;
314 	char *dup = NULL;
315 
316 	p = kzalloc_obj(*p);
317 	if (!p)
318 		return -ENOMEM;
319 
320 	token = match_token(t, property_tokens, args);
321 
322 	switch (token) {
323 	case IPE_PROP_DMV_ROOTHASH:
324 	case IPE_PROP_FSV_DIGEST:
325 		dup = match_strdup(&args[0]);
326 		if (!dup) {
327 			rc = -ENOMEM;
328 			goto err;
329 		}
330 		p->value = ipe_digest_parse(dup);
331 		if (IS_ERR(p->value)) {
332 			rc = PTR_ERR(p->value);
333 			goto err;
334 		}
335 		fallthrough;
336 	case IPE_PROP_BOOT_VERIFIED_FALSE:
337 	case IPE_PROP_BOOT_VERIFIED_TRUE:
338 	case IPE_PROP_DMV_SIG_FALSE:
339 	case IPE_PROP_DMV_SIG_TRUE:
340 	case IPE_PROP_FSV_SIG_FALSE:
341 	case IPE_PROP_FSV_SIG_TRUE:
342 		p->type = token;
343 		break;
344 	default:
345 		rc = -EBADMSG;
346 		break;
347 	}
348 	if (rc)
349 		goto err;
350 	list_add_tail(&p->next, &r->props);
351 
352 out:
353 	kfree(dup);
354 	return rc;
355 err:
356 	kfree(p);
357 	goto out;
358 }
359 
360 /**
361  * parse_rule() - parse a policy rule line.
362  * @line: Supplies rule line to be parsed.
363  * @p: Supplies the partial parsed policy.
364  *
365  * Return:
366  * * 0		- Success
367  * * %-ENOMEM	- Out of memory (OOM)
368  * * %-EBADMSG	- Policy syntax error
369  */
370 static int parse_rule(char *line, struct ipe_parsed_policy *p)
371 {
372 	enum ipe_action_type action = IPE_ACTION_INVALID;
373 	enum ipe_op_type op = IPE_OP_INVALID;
374 	bool is_default_rule = false;
375 	struct ipe_rule *r = NULL;
376 	bool first_token = true;
377 	bool op_parsed = false;
378 	int rc = 0;
379 	char *t;
380 
381 	if (IS_ERR_OR_NULL(line))
382 		return -EBADMSG;
383 
384 	r = kzalloc_obj(*r);
385 	if (!r)
386 		return -ENOMEM;
387 
388 	INIT_LIST_HEAD(&r->next);
389 	INIT_LIST_HEAD(&r->props);
390 
391 	while (t = strsep(&line, IPE_POLICY_DELIM), line) {
392 		if (*t == '\0')
393 			continue;
394 		if (first_token && token_default(t)) {
395 			is_default_rule = true;
396 		} else {
397 			if (!op_parsed) {
398 				op = parse_operation(t);
399 				if (op == IPE_OP_INVALID)
400 					rc = -EBADMSG;
401 				else
402 					op_parsed = true;
403 			} else {
404 				rc = parse_property(t, r);
405 			}
406 		}
407 
408 		if (rc)
409 			goto err;
410 		first_token = false;
411 	}
412 
413 	action = parse_action(t);
414 	if (action == IPE_ACTION_INVALID) {
415 		rc = -EBADMSG;
416 		goto err;
417 	}
418 
419 	if (is_default_rule) {
420 		if (!list_empty(&r->props)) {
421 			rc = -EBADMSG;
422 		} else if (op == IPE_OP_INVALID) {
423 			if (p->global_default_action != IPE_ACTION_INVALID)
424 				rc = -EBADMSG;
425 			else
426 				p->global_default_action = action;
427 		} else {
428 			if (p->rules[op].default_action != IPE_ACTION_INVALID)
429 				rc = -EBADMSG;
430 			else
431 				p->rules[op].default_action = action;
432 		}
433 	} else if (op != IPE_OP_INVALID && action != IPE_ACTION_INVALID) {
434 		r->op = op;
435 		r->action = action;
436 	} else {
437 		rc = -EBADMSG;
438 	}
439 
440 	if (rc)
441 		goto err;
442 	if (!is_default_rule)
443 		list_add_tail(&r->next, &p->rules[op].rules);
444 	else
445 		free_rule(r);
446 
447 	return rc;
448 err:
449 	free_rule(r);
450 	return rc;
451 }
452 
453 /**
454  * ipe_free_parsed_policy() - free a parsed policy structure.
455  * @p: Supplies the parsed policy.
456  */
457 void ipe_free_parsed_policy(struct ipe_parsed_policy *p)
458 {
459 	struct ipe_rule *pp, *t;
460 	size_t i = 0;
461 
462 	if (IS_ERR_OR_NULL(p))
463 		return;
464 
465 	for (i = 0; i < ARRAY_SIZE(p->rules); ++i)
466 		list_for_each_entry_safe(pp, t, &p->rules[i].rules, next) {
467 			list_del(&pp->next);
468 			free_rule(pp);
469 		}
470 
471 	kfree(p->name);
472 	kfree(p);
473 }
474 
475 /**
476  * validate_policy() - validate a parsed policy.
477  * @p: Supplies the fully parsed policy.
478  *
479  * Given a policy structure that was just parsed, validate that all
480  * operations have their default rules or a global default rule is set.
481  *
482  * Return:
483  * * %0		- Success
484  * * %-EBADMSG	- Policy is invalid
485  */
486 static int validate_policy(const struct ipe_parsed_policy *p)
487 {
488 	size_t i = 0;
489 
490 	if (p->global_default_action != IPE_ACTION_INVALID)
491 		return 0;
492 
493 	for (i = 0; i < ARRAY_SIZE(p->rules); ++i) {
494 		if (p->rules[i].default_action == IPE_ACTION_INVALID)
495 			return -EBADMSG;
496 	}
497 
498 	return 0;
499 }
500 
501 /**
502  * ipe_parse_policy() - Given a string, parse the string into an IPE policy.
503  * @p: partially filled ipe_policy structure to populate with the result.
504  *     it must have text and textlen set.
505  *
506  * Return:
507  * * %0		- Success
508  * * %-EBADMSG	- Policy is invalid
509  * * %-ENOMEM	- Out of Memory
510  * * %-ERANGE	- Policy version number overflow
511  * * %-EINVAL	- Policy version parsing error
512  */
513 int ipe_parse_policy(struct ipe_policy *p)
514 {
515 	struct ipe_parsed_policy *pp = NULL;
516 	char *policy = NULL, *dup = NULL;
517 	bool header_parsed = false;
518 	char *line = NULL;
519 	size_t len;
520 	int rc = 0;
521 
522 	if (!p->textlen)
523 		return -EBADMSG;
524 
525 	policy = kmemdup_nul(p->text, p->textlen, GFP_KERNEL);
526 	if (!policy)
527 		return -ENOMEM;
528 	dup = policy;
529 
530 	pp = new_parsed_policy();
531 	if (IS_ERR(pp)) {
532 		rc = PTR_ERR(pp);
533 		goto out;
534 	}
535 
536 	while ((line = strsep(&policy, IPE_LINE_DELIM)) != NULL) {
537 		remove_comment(line);
538 		len = remove_trailing_spaces(line);
539 		if (!len)
540 			continue;
541 
542 		if (!header_parsed) {
543 			rc = parse_header(line, pp);
544 			if (rc)
545 				goto err;
546 			header_parsed = true;
547 		} else {
548 			rc = parse_rule(line, pp);
549 			if (rc)
550 				goto err;
551 		}
552 	}
553 
554 	if (!header_parsed || validate_policy(pp)) {
555 		rc = -EBADMSG;
556 		goto err;
557 	}
558 
559 	p->parsed = pp;
560 
561 out:
562 	kfree(dup);
563 	return rc;
564 err:
565 	ipe_free_parsed_policy(pp);
566 	goto out;
567 }
568