xref: /linux/security/ipe/policy_parser.c (revision 566ab427f827b0256d3e8ce0235d088e6a9c28bd)
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_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}
285 };
286 
287 /**
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.
291  *
292  * This function parses and associates a property with an IPE rule based
293  * on a token string.
294  *
295  * Return:
296  * * %0		- Success
297  * * %-ENOMEM	- Out of memory (OOM)
298  * * %-EBADMSG	- The supplied token cannot be parsed
299  */
300 static int parse_property(char *t, struct ipe_rule *r)
301 {
302 	substring_t args[MAX_OPT_ARGS];
303 	struct ipe_prop *p = NULL;
304 	int rc = 0;
305 	int token;
306 	char *dup = NULL;
307 
308 	p = kzalloc(sizeof(*p), GFP_KERNEL);
309 	if (!p)
310 		return -ENOMEM;
311 
312 	token = match_token(t, property_tokens, args);
313 
314 	switch (token) {
315 	case IPE_PROP_DMV_ROOTHASH:
316 	case IPE_PROP_FSV_DIGEST:
317 		dup = match_strdup(&args[0]);
318 		if (!dup) {
319 			rc = -ENOMEM;
320 			goto err;
321 		}
322 		p->value = ipe_digest_parse(dup);
323 		if (IS_ERR(p->value)) {
324 			rc = PTR_ERR(p->value);
325 			goto err;
326 		}
327 		fallthrough;
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:
334 		p->type = token;
335 		break;
336 	default:
337 		rc = -EBADMSG;
338 		break;
339 	}
340 	if (rc)
341 		goto err;
342 	list_add_tail(&p->next, &r->props);
343 
344 out:
345 	kfree(dup);
346 	return rc;
347 err:
348 	kfree(p);
349 	goto out;
350 }
351 
352 /**
353  * parse_rule() - parse a policy rule line.
354  * @line: Supplies rule line to be parsed.
355  * @p: Supplies the partial parsed policy.
356  *
357  * Return:
358  * * 0		- Success
359  * * %-ENOMEM	- Out of memory (OOM)
360  * * %-EBADMSG	- Policy syntax error
361  */
362 static int parse_rule(char *line, struct ipe_parsed_policy *p)
363 {
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;
370 	int rc = 0;
371 	char *t;
372 
373 	if (IS_ERR_OR_NULL(line))
374 		return -EBADMSG;
375 
376 	r = kzalloc(sizeof(*r), GFP_KERNEL);
377 	if (!r)
378 		return -ENOMEM;
379 
380 	INIT_LIST_HEAD(&r->next);
381 	INIT_LIST_HEAD(&r->props);
382 
383 	while (t = strsep(&line, IPE_POLICY_DELIM), line) {
384 		if (*t == '\0')
385 			continue;
386 		if (first_token && token_default(t)) {
387 			is_default_rule = true;
388 		} else {
389 			if (!op_parsed) {
390 				op = parse_operation(t);
391 				if (op == IPE_OP_INVALID)
392 					rc = -EBADMSG;
393 				else
394 					op_parsed = true;
395 			} else {
396 				rc = parse_property(t, r);
397 			}
398 		}
399 
400 		if (rc)
401 			goto err;
402 		first_token = false;
403 	}
404 
405 	action = parse_action(t);
406 	if (action == IPE_ACTION_INVALID) {
407 		rc = -EBADMSG;
408 		goto err;
409 	}
410 
411 	if (is_default_rule) {
412 		if (!list_empty(&r->props)) {
413 			rc = -EBADMSG;
414 		} else if (op == IPE_OP_INVALID) {
415 			if (p->global_default_action != IPE_ACTION_INVALID)
416 				rc = -EBADMSG;
417 			else
418 				p->global_default_action = action;
419 		} else {
420 			if (p->rules[op].default_action != IPE_ACTION_INVALID)
421 				rc = -EBADMSG;
422 			else
423 				p->rules[op].default_action = action;
424 		}
425 	} else if (op != IPE_OP_INVALID && action != IPE_ACTION_INVALID) {
426 		r->op = op;
427 		r->action = action;
428 	} else {
429 		rc = -EBADMSG;
430 	}
431 
432 	if (rc)
433 		goto err;
434 	if (!is_default_rule)
435 		list_add_tail(&r->next, &p->rules[op].rules);
436 	else
437 		free_rule(r);
438 
439 	return rc;
440 err:
441 	free_rule(r);
442 	return rc;
443 }
444 
445 /**
446  * ipe_free_parsed_policy() - free a parsed policy structure.
447  * @p: Supplies the parsed policy.
448  */
449 void ipe_free_parsed_policy(struct ipe_parsed_policy *p)
450 {
451 	struct ipe_rule *pp, *t;
452 	size_t i = 0;
453 
454 	if (IS_ERR_OR_NULL(p))
455 		return;
456 
457 	for (i = 0; i < ARRAY_SIZE(p->rules); ++i)
458 		list_for_each_entry_safe(pp, t, &p->rules[i].rules, next) {
459 			list_del(&pp->next);
460 			free_rule(pp);
461 		}
462 
463 	kfree(p->name);
464 	kfree(p);
465 }
466 
467 /**
468  * validate_policy() - validate a parsed policy.
469  * @p: Supplies the fully parsed policy.
470  *
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.
473  *
474  * Return:
475  * * %0		- Success
476  * * %-EBADMSG	- Policy is invalid
477  */
478 static int validate_policy(const struct ipe_parsed_policy *p)
479 {
480 	size_t i = 0;
481 
482 	if (p->global_default_action != IPE_ACTION_INVALID)
483 		return 0;
484 
485 	for (i = 0; i < ARRAY_SIZE(p->rules); ++i) {
486 		if (p->rules[i].default_action == IPE_ACTION_INVALID)
487 			return -EBADMSG;
488 	}
489 
490 	return 0;
491 }
492 
493 /**
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.
497  *
498  * Return:
499  * * %0		- Success
500  * * %-EBADMSG	- Policy is invalid
501  * * %-ENOMEM	- Out of Memory
502  * * %-ERANGE	- Policy version number overflow
503  * * %-EINVAL	- Policy version parsing error
504  */
505 int ipe_parse_policy(struct ipe_policy *p)
506 {
507 	struct ipe_parsed_policy *pp = NULL;
508 	char *policy = NULL, *dup = NULL;
509 	bool header_parsed = false;
510 	char *line = NULL;
511 	size_t len;
512 	int rc = 0;
513 
514 	if (!p->textlen)
515 		return -EBADMSG;
516 
517 	policy = kmemdup_nul(p->text, p->textlen, GFP_KERNEL);
518 	if (!policy)
519 		return -ENOMEM;
520 	dup = policy;
521 
522 	pp = new_parsed_policy();
523 	if (IS_ERR(pp)) {
524 		rc = PTR_ERR(pp);
525 		goto out;
526 	}
527 
528 	while ((line = strsep(&policy, IPE_LINE_DELIM)) != NULL) {
529 		remove_comment(line);
530 		len = remove_trailing_spaces(line);
531 		if (!len)
532 			continue;
533 
534 		if (!header_parsed) {
535 			rc = parse_header(line, pp);
536 			if (rc)
537 				goto err;
538 			header_parsed = true;
539 		} else {
540 			rc = parse_rule(line, pp);
541 			if (rc)
542 				goto err;
543 		}
544 	}
545 
546 	if (!header_parsed || validate_policy(pp)) {
547 		rc = -EBADMSG;
548 		goto err;
549 	}
550 
551 	p->parsed = pp;
552 
553 out:
554 	kfree(dup);
555 	return rc;
556 err:
557 	ipe_free_parsed_policy(pp);
558 	goto out;
559 }
560