linux-block.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Serge E. Hallyn" <serge@hallyn.com>
To: Fan Wu <wufan@linux.microsoft.com>
Cc: corbet@lwn.net, zohar@linux.ibm.com, jmorris@namei.org,
	serge@hallyn.com, tytso@mit.edu, ebiggers@kernel.org,
	axboe@kernel.dk, agk@redhat.com, snitzer@kernel.org,
	mpatocka@redhat.com, eparis@redhat.com, paul@paul-moore.com,
	linux-doc@vger.kernel.org, linux-integrity@vger.kernel.org,
	linux-security-module@vger.kernel.org, fsverity@lists.linux.dev,
	linux-block@vger.kernel.org, dm-devel@lists.linux.dev,
	audit@vger.kernel.org, linux-kernel@vger.kernel.org,
	Deven Bowers <deven.desai@linux.microsoft.com>
Subject: Re: [PATCH v20 02/20] ipe: add policy parser
Date: Sat, 10 Aug 2024 10:50:00 -0500	[thread overview]
Message-ID: <20240810155000.GA35219@mail.hallyn.com> (raw)
In-Reply-To: <1722665314-21156-3-git-send-email-wufan@linux.microsoft.com>

On Fri, Aug 02, 2024 at 11:08:16PM -0700, Fan Wu wrote:
> From: Deven Bowers <deven.desai@linux.microsoft.com>
> 
> IPE's interpretation of the what the user trusts is accomplished through

nit: "of what the user trusts" (drop the extra 'the')

> its policy. IPE's design is to not provide support for a single trust
> provider, but to support multiple providers to enable the end-user to
> choose the best one to seek their needs.
> 
> This requires the policy to be rather flexible and modular so that
> integrity providers, like fs-verity, dm-verity, or some other system,
> can plug into the policy with minimal code changes.
> 
> Signed-off-by: Deven Bowers <deven.desai@linux.microsoft.com>
> Signed-off-by: Fan Wu <wufan@linux.microsoft.com>

This all looks fine.  Just one comment below.


> +/**
> + * parse_rule() - parse a policy rule line.
> + * @line: Supplies rule line to be parsed.
> + * @p: Supplies the partial parsed policy.
> + *
> + * Return:
> + * * 0		- Success
> + * * %-ENOMEM	- Out of memory (OOM)
> + * * %-EBADMSG	- Policy syntax error
> + */
> +static int parse_rule(char *line, struct ipe_parsed_policy *p)
> +{
> +	enum ipe_action_type action = IPE_ACTION_INVALID;
> +	enum ipe_op_type op = IPE_OP_INVALID;
> +	bool is_default_rule = false;
> +	struct ipe_rule *r = NULL;
> +	bool first_token = true;
> +	bool op_parsed = false;
> +	int rc = 0;
> +	char *t;
> +
> +	r = kzalloc(sizeof(*r), GFP_KERNEL);
> +	if (!r)
> +		return -ENOMEM;
> +
> +	INIT_LIST_HEAD(&r->next);
> +	INIT_LIST_HEAD(&r->props);
> +
> +	while (t = strsep(&line, IPE_POLICY_DELIM), line) {

If line is passed in as NULL, t will be NULL on the first test.  Then
you'll break out and call parse_action(NULL), which calls
match_token(NULL, ...), which I do not think is safe.

I realize the current caller won't pass in NULL, but it seems worth
checking for here in case some future caller is added by someone
who's unaware.

Or, maybe add 'line must not be null' to the function description.

> +		if (*t == '\0')
> +			continue;
> +		if (first_token && token_default(t)) {
> +			is_default_rule = true;
> +		} else {
> +			if (!op_parsed) {
> +				op = parse_operation(t);
> +				if (op == IPE_OP_INVALID)
> +					rc = -EBADMSG;
> +				else
> +					op_parsed = true;
> +			} else {
> +				rc = parse_property(t, r);
> +			}
> +		}
> +
> +		if (rc)
> +			goto err;
> +		first_token = false;
> +	}
> +
> +	action = parse_action(t);
> +	if (action == IPE_ACTION_INVALID) {
> +		rc = -EBADMSG;
> +		goto err;
> +	}
> +
> +	if (is_default_rule) {
> +		if (!list_empty(&r->props)) {
> +			rc = -EBADMSG;
> +		} else if (op == IPE_OP_INVALID) {
> +			if (p->global_default_action != IPE_ACTION_INVALID)
> +				rc = -EBADMSG;
> +			else
> +				p->global_default_action = action;
> +		} else {
> +			if (p->rules[op].default_action != IPE_ACTION_INVALID)
> +				rc = -EBADMSG;
> +			else
> +				p->rules[op].default_action = action;
> +		}
> +	} else if (op != IPE_OP_INVALID && action != IPE_ACTION_INVALID) {
> +		r->op = op;
> +		r->action = action;
> +	} else {
> +		rc = -EBADMSG;
> +	}
> +
> +	if (rc)
> +		goto err;
> +	if (!is_default_rule)
> +		list_add_tail(&r->next, &p->rules[op].rules);
> +	else
> +		free_rule(r);
> +
> +	return rc;
> +err:
> +	free_rule(r);
> +	return rc;
> +}
> +
> +/**
> + * ipe_free_parsed_policy() - free a parsed policy structure.
> + * @p: Supplies the parsed policy.
> + */
> +void ipe_free_parsed_policy(struct ipe_parsed_policy *p)
> +{
> +	struct ipe_rule *pp, *t;
> +	size_t i = 0;
> +
> +	if (IS_ERR_OR_NULL(p))
> +		return;
> +
> +	for (i = 0; i < ARRAY_SIZE(p->rules); ++i)
> +		list_for_each_entry_safe(pp, t, &p->rules[i].rules, next) {
> +			list_del(&pp->next);
> +			free_rule(pp);
> +		}
> +
> +	kfree(p->name);
> +	kfree(p);
> +}
> +
> +/**
> + * validate_policy() - validate a parsed policy.
> + * @p: Supplies the fully parsed policy.
> + *
> + * Given a policy structure that was just parsed, validate that all
> + * operations have their default rules or a global default rule is set.
> + *
> + * Return:
> + * * %0		- Success
> + * * %-EBADMSG	- Policy is invalid
> + */
> +static int validate_policy(const struct ipe_parsed_policy *p)
> +{
> +	size_t i = 0;
> +
> +	if (p->global_default_action != IPE_ACTION_INVALID)
> +		return 0;
> +
> +	for (i = 0; i < ARRAY_SIZE(p->rules); ++i) {
> +		if (p->rules[i].default_action == IPE_ACTION_INVALID)
> +			return -EBADMSG;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * ipe_parse_policy() - Given a string, parse the string into an IPE policy.
> + * @p: partially filled ipe_policy structure to populate with the result.
> + *     it must have text and textlen set.
> + *
> + * Return:
> + * * %0		- Success
> + * * %-EBADMSG	- Policy is invalid
> + * * %-ENOMEM	- Out of Memory
> + * * %-ERANGE	- Policy version number overflow
> + * * %-EINVAL	- Policy version parsing error
> + */
> +int ipe_parse_policy(struct ipe_policy *p)
> +{
> +	struct ipe_parsed_policy *pp = NULL;
> +	char *policy = NULL, *dup = NULL;
> +	bool header_parsed = false;
> +	char *line = NULL;
> +	size_t len;
> +	int rc = 0;
> +
> +	if (!p->textlen)
> +		return -EBADMSG;
> +
> +	policy = kmemdup_nul(p->text, p->textlen, GFP_KERNEL);
> +	if (!policy)
> +		return -ENOMEM;
> +	dup = policy;
> +
> +	pp = new_parsed_policy();
> +	if (IS_ERR(pp)) {
> +		rc = PTR_ERR(pp);
> +		goto out;
> +	}
> +
> +	while ((line = strsep(&policy, IPE_LINE_DELIM)) != NULL) {
> +		remove_comment(line);
> +		len = remove_trailing_spaces(line);
> +		if (!len)
> +			continue;
> +
> +		if (!header_parsed) {
> +			rc = parse_header(line, pp);
> +			if (rc)
> +				goto err;
> +			header_parsed = true;
> +		} else {
> +			rc = parse_rule(line, pp);
> +			if (rc)
> +				goto err;
> +		}
> +	}
> +
> +	if (!header_parsed || validate_policy(pp)) {
> +		rc = -EBADMSG;
> +		goto err;
> +	}
> +
> +	p->parsed = pp;
> +
> +out:
> +	kfree(dup);
> +	return rc;
> +err:
> +	ipe_free_parsed_policy(pp);
> +	goto out;
> +}
> diff --git a/security/ipe/policy_parser.h b/security/ipe/policy_parser.h
> new file mode 100644
> index 000000000000..62b6209019a2
> --- /dev/null
> +++ b/security/ipe/policy_parser.h
> @@ -0,0 +1,11 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved.
> + */
> +#ifndef _IPE_POLICY_PARSER_H
> +#define _IPE_POLICY_PARSER_H
> +
> +int ipe_parse_policy(struct ipe_policy *p);
> +void ipe_free_parsed_policy(struct ipe_parsed_policy *p);
> +
> +#endif /* _IPE_POLICY_PARSER_H */
> -- 
> 2.44.0

  reply	other threads:[~2024-08-10 15:58 UTC|newest]

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-08-03  6:08 [PATCH v20 00/20] Integrity Policy Enforcement LSM (IPE) Fan Wu
2024-08-03  6:08 ` [PATCH v20 01/20] security: add ipe lsm Fan Wu
2024-08-03  6:08 ` [PATCH v20 02/20] ipe: add policy parser Fan Wu
2024-08-10 15:50   ` Serge E. Hallyn [this message]
2024-08-13 17:54     ` Fan Wu
2024-08-14  1:53       ` Paul Moore
2024-08-14 18:23         ` Fan Wu
2024-08-15 19:11           ` Paul Moore
2024-08-03  6:08 ` [PATCH v20 03/20] ipe: add evaluation loop Fan Wu
2024-08-10 20:05   ` Serge E. Hallyn
2024-08-03  6:08 ` [PATCH v20 04/20] ipe: add LSM hooks on execution and kernel read Fan Wu
2024-08-03  6:08 ` [PATCH v20 05/20] initramfs|security: Add a security hook to do_populate_rootfs() Fan Wu
2024-08-03  6:08 ` [PATCH v20 06/20] ipe: introduce 'boot_verified' as a trust provider Fan Wu
2024-08-03  6:08 ` [PATCH v20 07/20] security: add new securityfs delete function Fan Wu
2024-08-03  6:08 ` [PATCH v20 08/20] ipe: add userspace interface Fan Wu
2024-08-03  6:08 ` [PATCH v20 09/20] uapi|audit|ipe: add ipe auditing support Fan Wu
2024-08-03  6:08 ` [PATCH v20 10/20] ipe: add permissive toggle Fan Wu
2024-08-03  6:08 ` [PATCH v20 11/20] block|lsm: Add LSM blob and new LSM hooks for block devices Fan Wu
2024-08-03  6:08 ` [PATCH v20 12/20] dm verity: expose root hash digest and signature data to LSMs Fan Wu
2024-08-08 22:38   ` Fan Wu
2024-08-15 19:19     ` Paul Moore
2024-08-16 13:35       ` Mikulas Patocka
2024-08-16 19:11         ` Fan Wu
2024-08-18 17:22           ` Paul Moore
2024-08-19 17:47             ` Fan Wu
2024-08-19 19:40               ` Paul Moore
2024-08-03  6:08 ` [PATCH v20 13/20] ipe: add support for dm-verity as a trust provider Fan Wu
2024-08-03  6:08 ` [PATCH v20 14/20] security: add security_inode_setintegrity() hook Fan Wu
2024-08-03  6:08 ` [PATCH v20 15/20] fsverity: expose verified fsverity built-in signatures to LSMs Fan Wu
2024-08-05 18:51   ` Eric Biggers
2024-08-03  6:08 ` [PATCH v20 16/20] ipe: enable support for fs-verity as a trust provider Fan Wu
2024-08-03  6:08 ` [PATCH v20 17/20] scripts: add boot policy generation program Fan Wu
2024-08-03  6:08 ` [PATCH v20 18/20] ipe: kunit test for parser Fan Wu
2024-08-03  6:08 ` [PATCH v20 19/20] Documentation: add ipe documentation Fan Wu
2024-08-03  6:08 ` [PATCH v20 20/20] MAINTAINERS: ipe: add ipe maintainer information Fan Wu
2024-08-03  8:14   ` Paul Menzel
2024-08-06 20:54     ` Paul Moore
2024-08-07  4:48       ` Paul Menzel
2024-08-07 18:01         ` Fan Wu
2024-08-07 19:42           ` Paul Moore
2024-08-06 20:59 ` [PATCH v20 00/20] Integrity Policy Enforcement LSM (IPE) Paul Moore
2024-08-20  2:51   ` Paul Moore

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240810155000.GA35219@mail.hallyn.com \
    --to=serge@hallyn.com \
    --cc=agk@redhat.com \
    --cc=audit@vger.kernel.org \
    --cc=axboe@kernel.dk \
    --cc=corbet@lwn.net \
    --cc=deven.desai@linux.microsoft.com \
    --cc=dm-devel@lists.linux.dev \
    --cc=ebiggers@kernel.org \
    --cc=eparis@redhat.com \
    --cc=fsverity@lists.linux.dev \
    --cc=jmorris@namei.org \
    --cc=linux-block@vger.kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-integrity@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=mpatocka@redhat.com \
    --cc=paul@paul-moore.com \
    --cc=snitzer@kernel.org \
    --cc=tytso@mit.edu \
    --cc=wufan@linux.microsoft.com \
    --cc=zohar@linux.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).