Received: by 2002:a05:6a10:1d13:0:0:0:0 with SMTP id pp19csp2680807pxb; Tue, 24 Aug 2021 05:15:20 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzCBNfxUQPHWfghS96vQ/7v9zHjLwi7k+s/GZVMdAbeC6avsWqUmn25+hsl9+xEj6y2F42m X-Received: by 2002:a05:6402:354e:: with SMTP id f14mr23078243edd.20.1629807319944; Tue, 24 Aug 2021 05:15:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1629807319; cv=none; d=google.com; s=arc-20160816; b=udARj7tc/FqmQs6KPDJBMTahWMZcsvEI0JdqMe9yhGqBe55yYXqAEdwqG+lK6yu3OC qZSLfwjDmWzxNmVVNBfhV2XfZ+l3CqJ/wbn7Pmg1aklbbWPQE/beGczjOYPk8vi5OsTe 4fPBzwgP8UdpFVvA/ksDmguXT97bJx4BvMEL3r48ItE8mG+6souWboyxUjz5aJC8HvoO EdlsvHgZYaFkHGDydXSWYq7RJYcJIPlgNkFHxsU1vbGzyeJQYtFb5qb4H0bakSQu11cN 7m/c4KZxQEOsiCRM2BD+v5fyL8EJYFuXHwD7F4fClQFFvcT9KMxqIHNyUpYSTT49SW4x kbyw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-language:content-transfer-encoding :in-reply-to:mime-version:user-agent:date:message-id:from:references :cc:to:subject; bh=I0a/N+N+hv1jBfq/1VFgctrg5HX3X2qG3mT7ao61kCo=; b=uVz+JlKxaNtrJi7Z4xN2NkDTDukxyCNzHge/Hr43vACTdDGDhkMgqkU5zZ2vtp+5ZF YnTR1Xjyvr9dIStlkTcFzrmfTq2+9EiLUt8eZ4OtfQbMaKqlASLGISrtXQL/1dU2FLBV NX3sPvER1GUgdPLZHhZhC+W/EuzLsLUyPDq6UUG3IDRw1KnMShJ0/upYT/jdZZuGdLNq IWN4LD3WTf3i3DpDB1LggMQ3ehP3AHX4l4Zq4Z/KzKOiumkBShrl1bXwt9d2f1zqeLbt e5qFUZwA54qB0BuMKQhdQKwwjX6Nexcy1Sd2X65FsFe+fcznZF9z3gs2fseYP5Z/E/Zt OGlg== 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 l1si11323309ejo.68.2021.08.24.05.14.55; Tue, 24 Aug 2021 05:15:19 -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 S237097AbhHXMLC (ORCPT + 99 others); Tue, 24 Aug 2021 08:11:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44844 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234787AbhHXMLB (ORCPT ); Tue, 24 Aug 2021 08:11:01 -0400 Received: from ha0.nfschina.com (unknown [IPv6:2400:dd01:100f:2:d63d:7eff:fe08:eb3f]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 5B76CC061757; Tue, 24 Aug 2021 05:10:16 -0700 (PDT) Received: from localhost (unknown [127.0.0.1]) by ha0.nfschina.com (Postfix) with ESMTP id 559C1AE0DBF; Tue, 24 Aug 2021 20:09:46 +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 bc1O8ZkHRKm7; Tue, 24 Aug 2021 20:09:24 +0800 (CST) Received: from [172.30.18.174] (unknown [180.167.10.98]) (Authenticated sender: liqiong@nfschina.com) by ha0.nfschina.com (Postfix) with ESMTPA id 8F3EDAE058B; Tue, 24 Aug 2021 20:09:23 +0800 (CST) Subject: Re: [PATCH] ima: fix deadlock within "ima_match_policy" function. To: THOBY Simon , "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" References: <20210819101529.28001-1-liqiong@nfschina.com> <20210824085747.23604-1-liqiong@nfschina.com> From: liqiong Message-ID: <3ba4da9d-fa7b-c486-0c48-67cee4d5de6d@nfschina.com> Date: Tue, 24 Aug 2021 20:09:51 +0800 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.2.1 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Content-Language: en-US Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Simon : ima: fix deadlock within RCU list of ima_rules. ima_match_policy() is looping on the policy ruleset while ima_update_policy() updates the variable "ima_rules". This can lead to a situation where ima_match_policy() can't exit the 'list_for_each_entry_rcu' loop, causing RCU stalls ("rcu_sched detected stall on CPU ..."). This problem can happen in practice: updating the IMA policy in the boot process while systemd-services are being checked. In addition to ima_match_policy(), other function with "list_for_each_entry_rcu" should happen too. Fix locking by introducing a duplicate of "ima_rules" for each "list_for_each_entry_rcu". How about this commit message ? I have tested this patch in lab, we can reproduced this error case, have done reboot test many times. This patch should work. 在 2021年08月24日 17:50, THOBY Simon 写道: > Hi liqiong, > > On 8/24/21 10:57 AM, liqiong wrote: >> When "ima_match_policy" is looping while "ima_update_policy" changs > Small typo: "changes"/"updates" > >> the variable "ima_rules", then "ima_match_policy" may can't exit >> loop, Finally cause RCU CPU Stall Warnings: "rcu_sched detected >> stall on CPU ...". > This could perhaps be rephrased to something like: > """ > ima_match_policy() can loop on the policy ruleset while > ima_update_policy() updates the variable "ima_rules". > This can lead to a situation where ima_match_policy() > can't exit the 'list_for_each_entry_rcu' loop, causing > RCU stalls ("rcu_sched detected stall on CPU ..."). > """ > > >> The problem is limited to transitioning from the builtin policy to >> the custom policy. Eg. At boot time, systemd-services are being >> checked within "ima_match_policy", at the same time, the variable >> "ima_rules" is changed by another service. > For the second sentence, consider something in the likes of: > "This problem can happen in practice: updating the IMA policy > in the boot process while systemd-services are being checked > have been observed to trigger this issue.". > > > Your commit message is also supposed to explain what you are doing, > using the imperative form ((see 'Documentation/process/submitting-patches.rst'): > """ > Describe your changes in imperative mood, e.g. "make xyzzy do frotz" > instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy > to do frotz", as if you are giving orders to the codebase to change > its behaviour. > """ > > Maybe add a paragraph with something like "Fix locking by introducing ...."? > > >> Signed-off-by: liqiong >> --- >> security/integrity/ima/ima_policy.c | 17 ++++++++++++----- >> 1 file changed, 12 insertions(+), 5 deletions(-) >> >> diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c >> index fd5d46e511f1..e92b197bfd3c 100644 >> --- a/security/integrity/ima/ima_policy.c >> +++ b/security/integrity/ima/ima_policy.c >> @@ -662,12 +662,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; >> @@ -919,8 +921,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 >> @@ -1649,9 +1651,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; >> @@ -1670,7 +1674,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) >> @@ -1872,6 +1877,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; >> @@ -1879,7 +1885,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; >> >> > I haven't tested the patch myself, but the code diff looks fine to me. > > Thanks, > Simon