Received: by 2002:a05:6a11:4021:0:0:0:0 with SMTP id ky33csp365309pxb; Sat, 18 Sep 2021 05:12:24 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwbU26XIB8ZPRIalGHTWu0hdKHkYpjmknjk03QgU9w3vES6dsYzsUUxM3n2mLZLDgPZkQok X-Received: by 2002:a05:6e02:20c2:: with SMTP id 2mr8602492ilq.97.1631967144151; Sat, 18 Sep 2021 05:12:24 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1631967144; cv=none; d=google.com; s=arc-20160816; b=Ala5wV0BqUCsAy/xaMYwAgqwgxgKdYa1DprS2ELaRc1O2fkNvYe4fgO7wF89dn2MDx asFtZoPpC0nOvJlVYY2F18OELqBIdhjXS1+NWyzROkwseAs60QYg+iWB1mUCKH7WUCCS 5uGKImfSoGrPxNT2HMgiVaDCSQSOEtQj38zffdDo4GGi07zsB2e5IfDzQDHdXS/O0nlF QSPidm9yFECI63n450tPtUTft8QB//Ikr8vzB38O/vAxtJ/8oFihBVxqXqIBPoLE5EQa W6cWdDYB1YBpWAFYCLjxWf6+gkuZ1YDFoiSr1CaI64NoD0CF1bG1QULu1RS//SzlIK/l Ib9Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:references:in-reply-to:message-id:date:subject :cc:to:from; bh=wBWP0/PDhjl61sNO/Man9cA78ueRlvaq3bYV0XbhQHE=; b=KY8AWZCS0JKhi3bHWyWunPPj+bjZKM/YGgB9c8jaNBSTxLE5slxMMz9iIPf2jp8Mzw Xlp+EqGmbY6zMzGJgpeVVbdx5XSRZTfcFSH7hnhkeLx78HqfK5KZ8YsX0YViUxGcClf+ vbUCV7ZT/CQ7iSfHnmKA0uL74Q5xXrNewuWASsfzcTZra92kU+MIAerKmPFg4wZ1k/pj 8P54lDsQHvUSfyPqy8OXmhLzpqIESTWyVgB9elBA389syUc62BUaMpvs2sLIS1C/dq8y cAUWQU/Z6iMVStgIY1rOcsKKZkEjK1PfaGhocpSNJUpkykLM9YXNTsFDyWzZafbc0paI /AIQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id v8si4059141ilj.145.2021.09.18.05.12.13; Sat, 18 Sep 2021 05:12:24 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236056AbhIRDPb (ORCPT + 99 others); Fri, 17 Sep 2021 23:15:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38344 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241067AbhIRDOl (ORCPT ); Fri, 17 Sep 2021 23:14:41 -0400 Received: from ha0.nfschina.com (unknown [IPv6:2400:dd01:100f:2:d63d:7eff:fe08:eb3f]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 0E1EDC061574; Fri, 17 Sep 2021 20:13:13 -0700 (PDT) Received: from localhost (unknown [127.0.0.1]) by ha0.nfschina.com (Postfix) with ESMTP id A7171AE0E22; Sat, 18 Sep 2021 11:13:19 +0800 (CST) X-Virus-Scanned: amavisd-new at test.com Received: from ha0.nfschina.com ([127.0.0.1]) by localhost (ha0.nfschina.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 4dTRWk8QdBbU; Sat, 18 Sep 2021 11:12:56 +0800 (CST) Received: from localhost.localdomain (unknown [180.167.10.98]) (Authenticated sender: liqiong@nfschina.com) by ha0.nfschina.com (Postfix) with ESMTPA id 399A5AE0DCF; Sat, 18 Sep 2021 11:12:52 +0800 (CST) From: liqiong To: Simon.THOBY@viveris.fr, zohar@linux.ibm.com Cc: dmitry.kasatkin@gmail.com, jmorris@namei.org, serge@hallyn.com, linux-integrity@vger.kernel.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, liqiong@nfschina.com Subject: [PATCH] ima: fix deadlock when traversing "ima_default_rules". Date: Sat, 18 Sep 2021 11:11:39 +0800 Message-Id: <20210918031139.22674-1-liqiong@nfschina.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20210827103536.4149-1-liqiong@nfschina.com> References: <20210827103536.4149-1-liqiong@nfschina.com> Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The current IMA ruleset is identified by the variable "ima_rules" that default to "&ima_default_rules". When loading a custom policy for the first time, the variable is updated to "&ima_policy_rules" instead. That update isn't RCU-safe, and deadlocks are possible. Indeed, some functions like ima_match_policy() may loop indefinitely when traversing "ima_default_rules" with list_for_each_entry_rcu(). When iterating over the default ruleset back to head, if the list head is "ima_default_rules", and "ima_rules" have been updated to "&ima_policy_rules", the loop condition (&entry->list != ima_rules) stays always true, traversing won't terminate, causing a soft lockup and RCU stalls. Introduce a temporary value for "ima_rules" when iterating over the ruleset to avoid the deadlocks. Signed-off-by: liqiong Reviewed-by: THOBY Simon Fixes: 38d859f991f3 ("IMA: policy can now be updated multiple times") Signed-off-by: Mimi Zohar Reported-by: kernel test robot Fix sparse: incompatible types in comparison expression. --- security/integrity/ima/ima_policy.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 87b9b71cb820..480de75eaf8c 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -228,7 +228,7 @@ static struct ima_rule_entry *arch_policy_entry __ro_after_init; static LIST_HEAD(ima_default_rules); static LIST_HEAD(ima_policy_rules); static LIST_HEAD(ima_temp_rules); -static struct list_head *ima_rules = &ima_default_rules; +static struct list_head __rcu *ima_rules = (struct list_head __rcu *)(&ima_default_rules); static int ima_policy __initdata; @@ -675,12 +675,14 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode, { struct ima_rule_entry *entry; int action = 0, actmask = flags | (flags << 1); + struct list_head *ima_rules_tmp; if (template_desc && !*template_desc) *template_desc = ima_template_desc_current(); rcu_read_lock(); - list_for_each_entry_rcu(entry, ima_rules, list) { + ima_rules_tmp = rcu_dereference(ima_rules); + list_for_each_entry_rcu(entry, ima_rules_tmp, list) { if (!(entry->action & actmask)) continue; @@ -970,8 +972,8 @@ void ima_update_policy(void) if (ima_rules != policy) { ima_policy_flag = 0; - ima_rules = policy; + rcu_assign_pointer(ima_rules, policy); /* * IMA architecture specific policy rules are specified * as strings and converted to an array of ima_entry_rules @@ -1768,9 +1770,11 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos) { loff_t l = *pos; struct ima_rule_entry *entry; + struct list_head *ima_rules_tmp; rcu_read_lock(); - list_for_each_entry_rcu(entry, ima_rules, list) { + ima_rules_tmp = rcu_dereference(ima_rules); + list_for_each_entry_rcu(entry, ima_rules_tmp, list) { if (!l--) { rcu_read_unlock(); return entry; @@ -1789,7 +1793,8 @@ void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos) rcu_read_unlock(); (*pos)++; - return (&entry->list == ima_rules) ? NULL : entry; + return (&entry->list == &ima_default_rules || + &entry->list == &ima_policy_rules) ? NULL : entry; } void ima_policy_stop(struct seq_file *m, void *v) @@ -2014,6 +2019,7 @@ bool ima_appraise_signature(enum kernel_read_file_id id) struct ima_rule_entry *entry; bool found = false; enum ima_hooks func; + struct list_head *ima_rules_tmp; if (id >= READING_MAX_ID) return false; @@ -2021,7 +2027,8 @@ bool ima_appraise_signature(enum kernel_read_file_id id) func = read_idmap[id] ?: FILE_CHECK; rcu_read_lock(); - list_for_each_entry_rcu(entry, ima_rules, list) { + ima_rules_tmp = rcu_dereference(ima_rules); + list_for_each_entry_rcu(entry, ima_rules_tmp, list) { if (entry->action != APPRAISE) continue; -- 2.11.0