From: Tahera Fahimi <taherafahimi@linux.microsoft.com>
To: zohar@linux.ibm.com, roberto.sassu@huawei.com,
dmitry.kasatkin@gmail.com, eric.snowberg@oracle.com,
paul@paul-moore.com, jmorris@namei.org, serge@hallyn.com,
linux-integrity@vger.kernel.org,
linux-security-module@vger.kernel.org,
linux-kernel@vger.kernel.org, code@tyhicks.com
Cc: Tahera Fahimi <taherafahimi@linux.microsoft.com>
Subject: [Patch V1] ima: avoid duplicate policy rules insertions
Date: Thu, 6 Nov 2025 18:14:04 +0000 [thread overview]
Message-ID: <20251106181404.3429710-1-taherafahimi@linux.microsoft.com> (raw)
Prevent redundant IMA policy rules by checking for duplicates before insertion. This ensures that
rules are not re-added when userspace is restarted (using systemd-soft-reboot) without a full system
reboot. ima_rule_exists() detects duplicates in both temporary and active rule lists.
Signed-off-by: Tahera Fahimi <taherafahimi@linux.microsoft.com>
---
security/integrity/ima/ima_policy.c | 157 +++++++++++++++++++++++++++-
1 file changed, 156 insertions(+), 1 deletion(-)
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 164d62832f8ec..3dd902101dbda 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -1953,6 +1953,153 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
return result;
}
+static bool template_has_field(const char *field_id, const struct ima_template_desc *template2)
+{
+ int j;
+
+ for (int j = 0; j < template2->num_fields; j++)
+ if (strcmp(field_id, template2->fields[j]->field_id) == 0)
+ return true;
+
+ return false;
+}
+
+static bool keyring_has_item(const char *item, const struct ima_rule_opt_list *keyrings)
+{
+ int j;
+
+ for (j = 0; j < keyrings->count; j++) {
+ if (strcmp(item, keyrings->items[j]) == 0)
+ return true;
+ }
+ return false;
+}
+
+static bool labels_has_item(const char *item, const struct ima_rule_opt_list *labels)
+{
+ int j;
+
+ for (j = 0; j < labels->count; j++) {
+ if (strcmp(item, labels->items[j]) == 0)
+ return true;
+ }
+ return false;
+}
+
+static bool ima_rules_equal(const struct ima_rule_entry *rule1, const struct ima_rule_entry *rule2)
+{
+ int i;
+
+ if (rule1->flags != rule2->flags)
+ return false;
+
+ if (rule1->action != rule2->action)
+ return false;
+
+ if (((rule1->flags & IMA_FUNC) && rule1->func != rule2->func) ||
+ ((rule1->flags & (IMA_MASK | IMA_INMASK)) && rule1->mask != rule2->mask) ||
+ ((rule1->flags & IMA_FSMAGIC) && rule1->fsmagic != rule2->fsmagic) ||
+ ((rule1->flags & IMA_FSUUID) && !uuid_equal(&rule1->fsuuid, &rule2->fsuuid)) ||
+ ((rule1->flags & IMA_UID) && !uid_eq(rule1->uid, rule2->uid)) ||
+ ((rule1->flags & IMA_GID) && !gid_eq(rule1->gid, rule2->gid)) ||
+ ((rule1->flags & IMA_FOWNER) && !uid_eq(rule1->fowner, rule2->fowner)) ||
+ ((rule1->flags & IMA_FGROUP) && !gid_eq(rule1->fgroup, rule2->fgroup)) ||
+ ((rule1->flags & IMA_FSNAME) && (strcmp(rule1->fsname, rule2->fsname) != 0)) ||
+ ((rule1->flags & IMA_PCR) && rule1->pcr != rule2->pcr) ||
+ ((rule1->flags & IMA_VALIDATE_ALGOS) &&
+ rule1->allowed_algos != rule2->allowed_algos) ||
+ ((rule1->flags & IMA_EUID) && !uid_eq(rule1->uid, rule2->uid)) ||
+ ((rule1->flags & IMA_EGID) && !gid_eq(rule1->gid, rule2->gid)))
+ return false;
+
+ if (!rule1->template && !rule2->template) {
+ ;
+ } else if (!rule1->template || !rule2->template) {
+ return false;
+ } else if (rule1->template->num_fields != rule2->template->num_fields) {
+ return false;
+ } else if (rule1->template->num_fields != 0) {
+ for (i = 0; i < rule1->template->num_fields; i++) {
+ if (!template_has_field(rule1->template->fields[i]->field_id,
+ rule2->template))
+ return false;
+ }
+ }
+
+ if (rule1->flags & IMA_KEYRINGS) {
+ if (!rule1->keyrings && !rule2->keyrings) {
+ ;
+ } else if (!rule1->keyrings || !rule2->keyrings) {
+ return false;
+ } else if (rule1->keyrings->count != rule2->keyrings->count) {
+ return false;
+ } else if (rule1->keyrings->count != 0) {
+ for (i = 0; i < rule1->keyrings->count; i++) {
+ if (!keyring_has_item(rule1->keyrings->items[i], rule2->keyrings))
+ return false;
+ }
+ }
+ }
+
+ if (rule1->flags & IMA_LABEL) {
+ if (!rule1->label && !rule2->label) {
+ ;
+ } else if (!rule1->label || !rule2->label) {
+ return false;
+ } else if (rule1->label->count != rule2->label->count) {
+ return false;
+ } else if (rule1->label->count != 0) {
+ for (i = 0; i < rule1->label->count; i++) {
+ if (!labels_has_item(rule1->label->items[i], rule2->label))
+ return false;
+ }
+ }
+ }
+
+ for (i = 0; i < MAX_LSM_RULES; i++) {
+ if (!rule1->lsm[i].rule && !rule2->lsm[i].rule)
+ continue;
+
+ if (!rule1->lsm[i].rule || !rule2->lsm[i].rule)
+ return false;
+
+ if (strcmp(rule1->lsm[i].args_p, rule2->lsm[i].args_p) != 0)
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * ima_rule_exists - check if a rule already exists in the policy
+ *
+ * Checking both the active policy and the temporary rules list.
+ */
+static bool ima_rule_exists(struct ima_rule_entry *new_rule)
+{
+ struct ima_rule_entry *entry;
+ struct list_head *ima_rules_tmp;
+
+ if (!list_empty(&ima_temp_rules)) {
+ list_for_each_entry(entry, &ima_temp_rules, list) {
+ if (ima_rules_equal(entry, new_rule))
+ return true;
+ }
+ }
+
+ rcu_read_lock();
+ ima_rules_tmp = rcu_dereference(ima_rules);
+ list_for_each_entry_rcu(entry, ima_rules_tmp, list) {
+ if (ima_rules_equal(entry, new_rule)) {
+ rcu_read_unlock();
+ return true;
+ }
+ }
+ rcu_read_unlock();
+
+ return false;
+}
+
/**
* ima_parse_add_rule - add a rule to ima_policy_rules
* @rule: ima measurement policy rule
@@ -1993,7 +2140,15 @@ ssize_t ima_parse_add_rule(char *rule)
return result;
}
- list_add_tail(&entry->list, &ima_temp_rules);
+ if (!ima_rule_exists(entry)) {
+ list_add_tail(&entry->list, &ima_temp_rules);
+ } else {
+ result = -EEXIST;
+ ima_free_rule(entry);
+ integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
+ NULL, op, "duplicate-policy", result,
+ audit_info);
+ }
return len;
}
--
2.43.0
next reply other threads:[~2025-11-06 18:14 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-06 18:14 Tahera Fahimi [this message]
2025-11-06 20:32 ` Anirudh Venkataramanan
2025-11-10 19:06 ` Tahera Fahimi
2025-11-11 9:46 ` Roberto Sassu
2025-11-07 6:54 ` kernel test robot
2025-11-07 9:44 ` Roberto Sassu
2025-11-07 10:56 ` Lennart Poettering
2025-11-07 11:56 ` Roberto Sassu
2025-11-11 11:40 ` Mimi Zohar
2025-11-20 15:39 ` Mimi Zohar
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=20251106181404.3429710-1-taherafahimi@linux.microsoft.com \
--to=taherafahimi@linux.microsoft.com \
--cc=code@tyhicks.com \
--cc=dmitry.kasatkin@gmail.com \
--cc=eric.snowberg@oracle.com \
--cc=jmorris@namei.org \
--cc=linux-integrity@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=paul@paul-moore.com \
--cc=roberto.sassu@huawei.com \
--cc=serge@hallyn.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
all inboxes | Powered by JetHome®