From patchwork Tue Jan 25 22:46:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724298 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 286FEC4167B for ; Tue, 25 Jan 2022 22:47:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234203AbiAYWri (ORCPT ); Tue, 25 Jan 2022 17:47:38 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:8316 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234196AbiAYWrZ (ORCPT ); Tue, 25 Jan 2022 17:47:25 -0500 Received: from pps.filterd (m0098404.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PMCPo4032314; Tue, 25 Jan 2022 22:47:01 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=/0ECQlcVfubXyc4fP7Ynu2TP0Hf6uUSHNatGiTkNU+o=; b=bYEZsvlLTWFVXvxCGIXMlM1jf8f+RkhQKQ+kxxP9tiSpFG9Ekv+BIzAfslLigLnBFHvM +TIpzBoOk86FYM/+z7JHb8k8XX+VY6DjimtPD1oUUQVM/9wizML+fJpc86w+9Edu+GtR G/Qst40WfPZbHc7gWtBt0ShHtMhPLTg/fP3A0UJbaaZFLU04q/wdt+M8BauAO9lPTVsc 1EKpyVRx85dTvRj6rS5XpRbxL8UOlGWj1Ag0s3jVburI5OqRLiGvrNMwLHkO/oRZ3jUU tT3H0zLfSF+KFNRlh4odZmRFLPxaAOomavD3OKYM+saWvIIeYT+7MjnWr8XQqvP36FdV aw== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtssp0hv9-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:01 +0000 Received: from m0098404.ppops.net (m0098404.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMTtZm019705; Tue, 25 Jan 2022 22:47:00 GMT Received: from ppma02dal.us.ibm.com (a.bd.3ea9.ip4.static.sl-reverse.com [169.62.189.10]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtssp0huv-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:00 +0000 Received: from pps.filterd (ppma02dal.us.ibm.com [127.0.0.1]) by ppma02dal.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMh2bC011206; Tue, 25 Jan 2022 22:46:59 GMT Received: from b01cxnp22034.gho.pok.ibm.com (b01cxnp22034.gho.pok.ibm.com [9.57.198.24]) by ppma02dal.us.ibm.com with ESMTP id 3dt1x9rg84-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:46:59 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp22034.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkuXa31261096 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:56 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 817CAAC05B; Tue, 25 Jan 2022 22:46:56 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 65EF3AC065; Tue, 25 Jan 2022 22:46:56 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:56 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger Subject: [PATCH v9 01/23] ima: Remove ima_policy file before directory Date: Tue, 25 Jan 2022 17:46:23 -0500 Message-Id: <20220125224645.79319-2-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: b2Bf-G0i0rgFpgC0nprJUqvxdQDL2EU3 X-Proofpoint-ORIG-GUID: 1gk_JMukCptggD_jRLkAJWE7S_ts_bFo X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_05,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 bulkscore=0 phishscore=0 adultscore=0 malwarescore=0 suspectscore=0 spamscore=0 mlxscore=0 mlxlogscore=999 impostorscore=0 clxscore=1015 priorityscore=1501 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger The removal of ima_dir currently fails since ima_policy still exists, so remove the ima_policy file before removing the directory. Fixes: 4af4662fa4a9 ("integrity: IMA policy") Signed-off-by: Stefan Berger Acked-by: Christian Brauner --- security/integrity/ima/ima_fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 3d8e9d5db5aa..3ad8f7734208 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -496,12 +496,12 @@ int __init ima_fs_init(void) return 0; out: + securityfs_remove(ima_policy); securityfs_remove(violations); securityfs_remove(runtime_measurements_count); securityfs_remove(ascii_runtime_measurements); securityfs_remove(binary_runtime_measurements); securityfs_remove(ima_symlink); securityfs_remove(ima_dir); - securityfs_remove(ima_policy); return -1; } From patchwork Tue Jan 25 22:46:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724297 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E8CF3C4332F for ; Tue, 25 Jan 2022 22:47:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234181AbiAYWrg (ORCPT ); Tue, 25 Jan 2022 17:47:36 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:7460 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234193AbiAYWrZ (ORCPT ); Tue, 25 Jan 2022 17:47:25 -0500 Received: from pps.filterd (m0098410.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PMkiFp004562; Tue, 25 Jan 2022 22:47:03 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=d0w2KVQWpiRmupZTVZ5yd6yW0pQMhRPOXS1919LCwZA=; b=njHetPoSod1i91urgtS0UGQ3tvfrtK7Ib4RD3vMoC7lboNCz/FOvD4CYh7QIrIqFC5Ep A+Y5OetJjlenqUi4nhFjRSUDPgrlbhHDdJkpDDoF4LZUbTPeZtuI9vLepwblh/xlrDUi 5yq42TlyZQ3baRiC8OYbWkY3sMKmWkJAk1z2KYivgd2HohuII4YVCgAiGizP6wKFP2lm NtSKo7v7aRK549bFPTusBYwJnGlp2LC13zy0X2uR6Cn06rfQ73eICT4tbHh5k5Sd/oeR YbOdV7rn3UHSZDo8E7yleOO6gnIlnmeOYOo7EYJZbrOvl2Dut7HvBNVp19VM2ZtPCTGS Zg== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtta2007e-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:03 +0000 Received: from m0098410.ppops.net (m0098410.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMl2bd005268; Tue, 25 Jan 2022 22:47:02 GMT Received: from ppma02wdc.us.ibm.com (aa.5b.37a9.ip4.static.sl-reverse.com [169.55.91.170]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtta20072-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:02 +0000 Received: from pps.filterd (ppma02wdc.us.ibm.com [127.0.0.1]) by ppma02wdc.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMhu2q025231; Tue, 25 Jan 2022 22:47:01 GMT Received: from b01cxnp22034.gho.pok.ibm.com (b01cxnp22034.gho.pok.ibm.com [9.57.198.24]) by ppma02wdc.us.ibm.com with ESMTP id 3dr9ja734r-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:00 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp22034.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkuZX31261098 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:56 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id A2955AC05B; Tue, 25 Jan 2022 22:46:56 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 85E78AC062; Tue, 25 Jan 2022 22:46:56 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:56 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger Subject: [PATCH v9 02/23] ima: Do not print policy rule with inactive LSM labels Date: Tue, 25 Jan 2022 17:46:24 -0500 Message-Id: <20220125224645.79319-3-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: 60RwSpArJtszf20Iw9uFgJzUYY7-xW6Q X-Proofpoint-ORIG-GUID: H3SWkM1tJ7ojU375fB_05aEDt7KoS5NR X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_05,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 mlxscore=0 malwarescore=0 impostorscore=0 phishscore=0 bulkscore=0 suspectscore=0 adultscore=0 mlxlogscore=999 lowpriorityscore=0 priorityscore=1501 clxscore=1015 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger Before printing a policy rule scan for inactive LSM labels in the policy rule. Inactive LSM labels are identified by args_p != NULL and rule == NULL. Fixes: b16942455193 ("ima: use the lsm policy update notifier") Signed-off-by: Stefan Berger --- security/integrity/ima/ima_policy.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 320ca80aacab..2a1f6418b10a 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -1967,6 +1967,14 @@ int ima_policy_show(struct seq_file *m, void *v) rcu_read_lock(); + /* Do not print rules with inactive LSM labels */ + for (i = 0; i < MAX_LSM_RULES; i++) { + if (entry->lsm[i].args_p && !entry->lsm[i].rule) { + rcu_read_unlock(); + return 0; + } + } + if (entry->action & MEASURE) seq_puts(m, pt(Opt_measure)); if (entry->action & DONT_MEASURE) From patchwork Tue Jan 25 22:46:25 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724309 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2DFA6C35278 for ; Tue, 25 Jan 2022 22:47:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234344AbiAYWrr (ORCPT ); Tue, 25 Jan 2022 17:47:47 -0500 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:21076 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S234208AbiAYWr2 (ORCPT ); Tue, 25 Jan 2022 17:47:28 -0500 Received: from pps.filterd (m0098413.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PLGbdR031386; Tue, 25 Jan 2022 22:47:00 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=d4vmynSK4tTwTieXLkMdi3BgOmjeWvPlbFcB3Ng1q6s=; b=gmrbUFG0l3UbFfGUup1Gw4c7bYdr66IzLUnFWO4fG0GNRHgeDQ7BnoVODCDDHQz8mQHV JtDNsT26KA6t1q/8b6NQku9GqQvuKGVKPRRYKGG16J4xZqzeocEwGctbeFpmip8RuHvV bf9RKCY1h4A27Uh/Ubg3eQ48tA3fiNQXxySC9WYEIZ7cR1/G1FF5q7/CcCzPaS4UVKAP rT4ZeQMj7IKR8p20gWFL0Oe/qb9bojQ987tOAzObN1SeyXyujD30+S4wJi89PLuw7dG9 3tOAsTOGSGWZMpbawdBt95EbRFua8d/SPXeT8ZHt89NJPV9Khv0Bze9Uskkiy+S7KXIr +A== Received: from pps.reinject (localhost [127.0.0.1]) by mx0b-001b2d01.pphosted.com with ESMTP id 3dtryvsftg-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:00 +0000 Received: from m0098413.ppops.net (m0098413.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PM5Iw5011912; Tue, 25 Jan 2022 22:46:59 GMT Received: from ppma04dal.us.ibm.com (7a.29.35a9.ip4.static.sl-reverse.com [169.53.41.122]) by mx0b-001b2d01.pphosted.com with ESMTP id 3dtryvsftd-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:46:59 +0000 Received: from pps.filterd (ppma04dal.us.ibm.com [127.0.0.1]) by ppma04dal.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMhDTW008672; Tue, 25 Jan 2022 22:46:59 GMT Received: from b01cxnp22034.gho.pok.ibm.com (b01cxnp22034.gho.pok.ibm.com [9.57.198.24]) by ppma04dal.us.ibm.com with ESMTP id 3dr9japd5q-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:46:58 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp22034.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMku0t40108504 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:56 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C2D8FAC05B; Tue, 25 Jan 2022 22:46:56 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id A6F2BAC05F; Tue, 25 Jan 2022 22:46:56 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:56 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Christian Brauner Subject: [PATCH v9 03/23] securityfs: rework dentry creation Date: Tue, 25 Jan 2022 17:46:25 -0500 Message-Id: <20220125224645.79319-4-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: F_JPw6yKVB5Qq8YzKRvqBwtkMU88DZyq X-Proofpoint-ORIG-GUID: 4gYolXMWKJJ4xaBu_KeLF2QxjgKdfIyd X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_05,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 clxscore=1011 lowpriorityscore=0 bulkscore=0 impostorscore=0 adultscore=0 malwarescore=0 priorityscore=1501 mlxlogscore=999 suspectscore=0 mlxscore=0 phishscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Christian Brauner When securityfs creates a new file or directory via securityfs_create_dentry() it will take an additional reference on the newly created dentry after it has attached the new inode to the new dentry and added it to the hashqueues. If we contrast this with debugfs which has the same underlying logic as securityfs. It uses a similar pairing as securityfs. Where securityfs has the securityfs_create_dentry() and securityfs_remove() pairing, debugfs has the __debugfs_create_file() and debugfs_remove() pairing. In contrast to securityfs, debugfs doesn't take an additional reference on the newly created dentry in __debugfs_create_file() which would need to be put in debugfs_remove(). The additional dget() isn't a problem per se. In the current implementation of securityfs each created dentry pins the filesystem via until it is removed. Since it is virtually guaranteed that there is at least one user of securityfs that has created dentries the initial securityfs mount cannot go away until all dentries have been removed. Since most of the users of the initial securityfs mount don't go away until the system is shutdown the initial securityfs won't go away when unmounted. Instead a mount will usually surface the same superblock as before. The additional dget() doesn't matter in this scenario since it is required that all dentries have been cleaned up by the respective users before the superblock can be destroyed, i.e. superblock shutdown is tied to the lifetime of the associated dentries. However, in order to support ima namespaces we need to extend securityfs to support being mounted outside of the initial user namespace. For namespaced users the pinning logic doesn't make sense. Whereas in the initial namespace the securityfs instance and the associated data structures of its users can't go away for reason explained earlier users of non-initial securityfs instances do go away when the last users of the namespace are gone. So for those users we neither want to duplicate the pinning logic nor make the global securityfs instance display different information based on the namespace. Both options would be really messy and hacky. Instead we will simply give each namespace its own securityfs instance similar to how each ipc namespace has its own mqueue instance and all entries in there are cleaned up on umount or when the last user of the associated namespace is gone. This means that the superblock's lifetime isn't tied to the dentries. Instead the last umount, without any fds kept open, will trigger a clean shutdown. But now the additional dget() gets in the way. Instead of being able to rely on the generic superblock shutdown logic we would need to drop the additional dentry reference during superblock shutdown for all associated users. That would force the use of a generic coordination mechanism for current and future users of securityfs which is unnecessary. Simply remove the additional dget() in securityfs_dentry_create(). In securityfs_remove() we will call dget() to take an additional reference on the dentry about to be removed. After simple_unlink() or simple_rmdir() have dropped the dentry refcount we can call d_delete() which will either turn the dentry into negative dentry if our earlier dget() is the only reference to the dentry, i.e. it has no other users, or remove it from the hashqueues in case there are additional users. All of these changes should not have any effect on the userspace semantics of the initial securityfs mount. Signed-off-by: Christian Brauner --- security/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/security/inode.c b/security/inode.c index 6c326939750d..13e6780c4444 100644 --- a/security/inode.c +++ b/security/inode.c @@ -159,7 +159,6 @@ static struct dentry *securityfs_create_dentry(const char *name, umode_t mode, inode->i_fop = fops; } d_instantiate(dentry, inode); - dget(dentry); inode_unlock(dir); return dentry; @@ -302,10 +301,12 @@ void securityfs_remove(struct dentry *dentry) dir = d_inode(dentry->d_parent); inode_lock(dir); if (simple_positive(dentry)) { + dget(dentry); if (d_is_dir(dentry)) simple_rmdir(dir, dentry); else simple_unlink(dir, dentry); + d_delete(dentry); dput(dentry); } inode_unlock(dir); From patchwork Tue Jan 25 22:46:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724295 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 94E04C4332F for ; Tue, 25 Jan 2022 22:47:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234141AbiAYWrd (ORCPT ); Tue, 25 Jan 2022 17:47:33 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:33032 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234202AbiAYWr0 (ORCPT ); Tue, 25 Jan 2022 17:47:26 -0500 Received: from pps.filterd (m0098409.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PMflNm011095; Tue, 25 Jan 2022 22:47:13 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=65fhBGRDSwpujvZ4xXpsSjgZqAWmpm0wPo18a5HqDvU=; b=nmjHRD0k08w9bjlLlSrGpFLspyH3tL8tb9k9EEy3urchSR3JITG/nJYYHmbkXgrCRVz6 G3i0/GuhNjgKUlGqbBAVD8fLA1O7AhH0hQ4BgpXlfFXwresPSNCO8tu8zlBRwh+m1R0S NEYQKWHR+/Rs2Lmjh1RSjzLFo9fFCqHkDIQhT6qpSD+doYSWoBzj0Jsj7aEv3cttU1F2 dIJtrf6+2quNCIT/NB+gPsF1GeNfAM6KZbck7/NS417jK/kVaPH8xJ7B2zzmm4sDDyVn t2zSioNU6MB+XuAnzxftAgNhLI00YbJdygH2Zbn0FcS2DT+xf0tFHRJjENDZM4ZVQbPN 8A== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtt7ng2jk-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:12 +0000 Received: from m0098409.ppops.net (m0098409.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMh2V3016165; Tue, 25 Jan 2022 22:47:12 GMT Received: from ppma05wdc.us.ibm.com (1b.90.2fa9.ip4.static.sl-reverse.com [169.47.144.27]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtt7ng2ja-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:12 +0000 Received: from pps.filterd (ppma05wdc.us.ibm.com [127.0.0.1]) by ppma05wdc.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMho9Z010517; Tue, 25 Jan 2022 22:47:10 GMT Received: from b01cxnp23032.gho.pok.ibm.com (b01cxnp23032.gho.pok.ibm.com [9.57.198.27]) by ppma05wdc.us.ibm.com with ESMTP id 3dtbch8rkf-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:10 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23032.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkvUq35848526 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:57 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id E68E5AC059; Tue, 25 Jan 2022 22:46:56 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C7EF7AC065; Tue, 25 Jan 2022 22:46:56 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:56 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger , James Bottomley , Christian Brauner Subject: [PATCH v9 04/23] securityfs: Extend securityfs with namespacing support Date: Tue, 25 Jan 2022 17:46:26 -0500 Message-Id: <20220125224645.79319-5-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: G2UliTMicESmkwNc88np_8GSRYihczgf X-Proofpoint-ORIG-GUID: Zn1d921sXtPx2bgeQDfZp1VvJ83fd1Aw X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_06,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 suspectscore=0 phishscore=0 impostorscore=0 bulkscore=0 priorityscore=1501 lowpriorityscore=0 mlxscore=0 spamscore=0 clxscore=1015 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger Enable multiple instances of securityfs by keying each instance with a pointer to the user namespace it belongs to. Since we do not need the pinning of the filesystem for the virtualization case, limit the usage of simple_pin_fs() and simpe_release_fs() to the case when the init_user_ns is active. This simplifies the cleanup for the virtualization case where usage of securityfs_remove() to free dentries is not needed anymore. For the initial securityfs, i.e. the one mounted in the host userns mount, nothing changes. The rules for securityfs_remove() are as before and it is still paired with securityfs_create(). Specifically, a file created via securityfs_create_dentry() in the initial securityfs mount still needs to be removed by a call to securityfs_remove(). Creating a new dentry in the initial securityfs mount still pins the filesystem like it always did. Consequently, the initial securityfs mount is not destroyed on umount/shutdown as long as at least one user of it still has dentries that it hasn't removed with a call to securityfs_remove(). Prevent mounting of an instance of securityfs in another user namespace than it belongs to. Also, prevent accesses to files and directories by a user namespace that is neither the user namespace it belongs to nor an ancestor of the user namespace that the instance of securityfs belongs to. Do not prevent access if securityfs was bind-mounted and therefore the init_user_ns is the owning user namespace. Signed-off-by: Stefan Berger Signed-off-by: James Bottomley Suggested-by: Christian Brauner Reviewed-by: Mimi Zohar --- security/inode.c | 72 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/security/inode.c b/security/inode.c index 13e6780c4444..e525ba960063 100644 --- a/security/inode.c +++ b/security/inode.c @@ -21,9 +21,37 @@ #include #include #include +#include -static struct vfsmount *mount; -static int mount_count; +static struct vfsmount *init_securityfs_mount; +static int init_securityfs_mount_count; + +static int securityfs_permission(struct user_namespace *mnt_userns, + struct inode *inode, int mask) +{ + int err; + + err = generic_permission(&init_user_ns, inode, mask); + if (!err) { + /* Unless bind-mounted, deny access if current_user_ns() is not + * ancestor. + */ + if (inode->i_sb->s_user_ns != &init_user_ns && + !in_userns(current_user_ns(), inode->i_sb->s_user_ns)) + err = -EACCES; + } + + return err; +} + +static const struct inode_operations securityfs_dir_inode_operations = { + .permission = securityfs_permission, + .lookup = simple_lookup, +}; + +static const struct inode_operations securityfs_file_inode_operations = { + .permission = securityfs_permission, +}; static void securityfs_free_inode(struct inode *inode) { @@ -40,20 +68,25 @@ static const struct super_operations securityfs_super_operations = { static int securityfs_fill_super(struct super_block *sb, struct fs_context *fc) { static const struct tree_descr files[] = {{""}}; + struct user_namespace *ns = fc->user_ns; int error; + if (WARN_ON(ns != current_user_ns())) + return -EINVAL; + error = simple_fill_super(sb, SECURITYFS_MAGIC, files); if (error) return error; sb->s_op = &securityfs_super_operations; + sb->s_root->d_inode->i_op = &securityfs_dir_inode_operations; return 0; } static int securityfs_get_tree(struct fs_context *fc) { - return get_tree_single(fc, securityfs_fill_super); + return get_tree_keyed(fc, securityfs_fill_super, fc->user_ns); } static const struct fs_context_operations securityfs_context_ops = { @@ -71,6 +104,7 @@ static struct file_system_type fs_type = { .name = "securityfs", .init_fs_context = securityfs_init_fs_context, .kill_sb = kill_litter_super, + .fs_flags = FS_USERNS_MOUNT, }; /** @@ -109,6 +143,7 @@ static struct dentry *securityfs_create_dentry(const char *name, umode_t mode, const struct file_operations *fops, const struct inode_operations *iops) { + struct user_namespace *ns = current_user_ns(); struct dentry *dentry; struct inode *dir, *inode; int error; @@ -118,12 +153,19 @@ static struct dentry *securityfs_create_dentry(const char *name, umode_t mode, pr_debug("securityfs: creating file '%s'\n",name); - error = simple_pin_fs(&fs_type, &mount, &mount_count); - if (error) - return ERR_PTR(error); + if (ns == &init_user_ns) { + error = simple_pin_fs(&fs_type, &init_securityfs_mount, + &init_securityfs_mount_count); + if (error) + return ERR_PTR(error); + } - if (!parent) - parent = mount->mnt_root; + if (!parent) { + if (ns == &init_user_ns) + parent = init_securityfs_mount->mnt_root; + else + return ERR_PTR(-EINVAL); + } dir = d_inode(parent); @@ -148,7 +190,7 @@ static struct dentry *securityfs_create_dentry(const char *name, umode_t mode, inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode); inode->i_private = data; if (S_ISDIR(mode)) { - inode->i_op = &simple_dir_inode_operations; + inode->i_op = &securityfs_dir_inode_operations; inode->i_fop = &simple_dir_operations; inc_nlink(inode); inc_nlink(dir); @@ -156,6 +198,7 @@ static struct dentry *securityfs_create_dentry(const char *name, umode_t mode, inode->i_op = iops ? iops : &simple_symlink_inode_operations; inode->i_link = data; } else { + inode->i_op = &securityfs_file_inode_operations; inode->i_fop = fops; } d_instantiate(dentry, inode); @@ -167,7 +210,9 @@ static struct dentry *securityfs_create_dentry(const char *name, umode_t mode, dentry = ERR_PTR(error); out: inode_unlock(dir); - simple_release_fs(&mount, &mount_count); + if (ns == &init_user_ns) + simple_release_fs(&init_securityfs_mount, + &init_securityfs_mount_count); return dentry; } @@ -293,11 +338,14 @@ EXPORT_SYMBOL_GPL(securityfs_create_symlink); */ void securityfs_remove(struct dentry *dentry) { + struct user_namespace *ns; struct inode *dir; if (!dentry || IS_ERR(dentry)) return; + ns = dentry->d_sb->s_user_ns; + dir = d_inode(dentry->d_parent); inode_lock(dir); if (simple_positive(dentry)) { @@ -310,7 +358,9 @@ void securityfs_remove(struct dentry *dentry) dput(dentry); } inode_unlock(dir); - simple_release_fs(&mount, &mount_count); + if (ns == &init_user_ns) + simple_release_fs(&init_securityfs_mount, + &init_securityfs_mount_count); } EXPORT_SYMBOL_GPL(securityfs_remove); From patchwork Tue Jan 25 22:46:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724313 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D3A75C4332F for ; Tue, 25 Jan 2022 22:47:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234370AbiAYWru (ORCPT ); Tue, 25 Jan 2022 17:47:50 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:32454 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234231AbiAYWra (ORCPT ); Tue, 25 Jan 2022 17:47:30 -0500 Received: from pps.filterd (m0187473.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PLg82J032491; Tue, 25 Jan 2022 22:47:07 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=zs161j0mYASsUyHnOqHcx8MFJ2kDqYdiE0b8lQ6V+wM=; b=ZtFtChFsVNIvSCOamGc6la8uDfkln2ukjzWj0lTw7/wQ1dR2+rN5FtjJQO3rw28L07Tp mvg1bpxjWnGpGRE44r1XskRq/2ohDrWY4QWP6VrU7yGqDka1H3GBjpawVhKmMGKsSjwY I/u2LeDywVtuqMGNcLoQW99D+egDMWXJK6m0w1aNegnRczKsjR9idjjYrNSZSq5Y4Dxs tYvmWMTJbx627VGRW38cFH9Gmeplu2ZFZkYbWwbSZr77W3muWnIjQ42G2O/inhjr8KJs PjZ/e3+lJS5GehxxqKZsxaENzrBsSnTyM4h5CdP4Br+uLvLkklzb2SxIHU5gmME8KgP+ 7Q== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtsbch550-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:06 +0000 Received: from m0187473.ppops.net (m0187473.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMVdZ7032206; Tue, 25 Jan 2022 22:47:06 GMT Received: from ppma05wdc.us.ibm.com (1b.90.2fa9.ip4.static.sl-reverse.com [169.47.144.27]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtsbch54s-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:06 +0000 Received: from pps.filterd (ppma05wdc.us.ibm.com [127.0.0.1]) by ppma05wdc.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMhnnd010370; Tue, 25 Jan 2022 22:47:04 GMT Received: from b01cxnp23032.gho.pok.ibm.com (b01cxnp23032.gho.pok.ibm.com [9.57.198.27]) by ppma05wdc.us.ibm.com with ESMTP id 3dtbch8rh6-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:04 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23032.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkvCV23986552 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:57 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 2C6C2AC064; Tue, 25 Jan 2022 22:46:57 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id ED8ECAC05B; Tue, 25 Jan 2022 22:46:56 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:56 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger Subject: [PATCH v9 05/23] ima: Define ima_namespace struct and start moving variables into it Date: Tue, 25 Jan 2022 17:46:27 -0500 Message-Id: <20220125224645.79319-6-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: O0Fxsv-H6rBESdawqT-lZQhoEuw2Ko5J X-Proofpoint-ORIG-GUID: rhcOe-pTmjizo3MNn44XOGJxdQm-_zV9 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_06,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 spamscore=0 clxscore=1015 adultscore=0 lowpriorityscore=0 mlxscore=0 phishscore=0 mlxlogscore=999 suspectscore=0 impostorscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger Define the ima_namespace structure and the ima_namespace variable init_ima_ns for the host's IMA namespace. Implement basic functions for namespacing support. Move variables related to the IMA policy into the ima_namespace. This way the IMA policy of an IMA namespace can be set and displayed using a front-end like securityfs. Implement ima_ns_from_file() to get the IMA namespace via the user namespace of the securityfs superblock that a file belongs to. To get the current ima_namespace use &init_ima_ns when a function that is related to a policy rule is called. Signed-off-by: Stefan Berger Acked-by: Christian Brauner --- v9: - squashed patched 2 and 3 of v8 - ima_post_read_file: only access ima_appraise in case of init_ima_ns --- security/integrity/ima/Makefile | 2 +- security/integrity/ima/ima.h | 53 ++++--- security/integrity/ima/ima_api.c | 8 +- security/integrity/ima/ima_appraise.c | 28 ++-- security/integrity/ima/ima_asymmetric_keys.c | 4 +- security/integrity/ima/ima_fs.c | 16 ++- security/integrity/ima/ima_init.c | 12 +- security/integrity/ima/ima_init_ima_ns.c | 29 ++++ security/integrity/ima/ima_main.c | 87 +++++++----- security/integrity/ima/ima_policy.c | 142 ++++++++++--------- security/integrity/ima/ima_queue_keys.c | 11 +- 11 files changed, 248 insertions(+), 144 deletions(-) create mode 100644 security/integrity/ima/ima_init_ima_ns.c diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile index 2499f2485c04..f8a5e5f3975d 100644 --- a/security/integrity/ima/Makefile +++ b/security/integrity/ima/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_IMA) += ima.o ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ - ima_policy.o ima_template.o ima_template_lib.o + ima_policy.o ima_template.o ima_template_lib.o ima_init_ima_ns.o ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o ima-$(CONFIG_IMA_APPRAISE_MODSIG) += ima_modsig.o ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index be965a8715e4..5b44fa6f27c4 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "../integrity.h" @@ -43,9 +44,6 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 }; #define NR_BANKS(chip) ((chip != NULL) ? chip->nr_allocated_banks : 0) -/* current content of the policy */ -extern int ima_policy_flag; - /* bitset of digests algorithms allowed in the setxattr hook */ extern atomic_t ima_setxattr_allowed_hash_algorithms; @@ -119,6 +117,17 @@ struct ima_kexec_hdr { u64 count; }; +struct ima_namespace { + /* policy rules */ + struct list_head ima_default_rules; + struct list_head ima_policy_rules; + struct list_head ima_temp_rules; + + struct list_head __rcu *ima_rules; /* current policy */ + int ima_policy_flag; +} __randomize_layout; +extern struct ima_namespace init_ima_ns; + extern const int read_idmap[]; #ifdef CONFIG_HAVE_IMA_KEXEC @@ -136,6 +145,7 @@ extern bool ima_canonical_fmt; /* Internal IMA function definitions */ int ima_init(void); int ima_fs_init(void); +int ima_ns_init(void); int ima_add_template_entry(struct ima_template_entry *entry, int violation, const char *op, struct inode *inode, const unsigned char *filename); @@ -243,18 +253,19 @@ void ima_init_key_queue(void); bool ima_should_queue_key(void); bool ima_queue_key(struct key *keyring, const void *payload, size_t payload_len); -void ima_process_queued_keys(void); +void ima_process_queued_keys(struct ima_namespace *ns); #else static inline void ima_init_key_queue(void) {} static inline bool ima_should_queue_key(void) { return false; } static inline bool ima_queue_key(struct key *keyring, const void *payload, size_t payload_len) { return false; } -static inline void ima_process_queued_keys(void) {} +static inline void ima_process_queued_keys(struct ima_namespace *ns) {} #endif /* CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS */ /* LIM API function definitions */ -int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode, +int ima_get_action(struct ima_namespace *ns, + struct user_namespace *mnt_userns, struct inode *inode, const struct cred *cred, u32 secid, int mask, enum ima_hooks func, int *pcr, struct ima_template_desc **template_desc, @@ -268,7 +279,8 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, struct evm_ima_xattr_data *xattr_value, int xattr_len, const struct modsig *modsig, int pcr, struct ima_template_desc *template_desc); -int process_buffer_measurement(struct user_namespace *mnt_userns, +int process_buffer_measurement(struct ima_namespace *ns, + struct user_namespace *mnt_userns, struct inode *inode, const void *buf, int size, const char *eventname, enum ima_hooks func, int pcr, const char *func_data, @@ -285,17 +297,18 @@ void ima_free_template_entry(struct ima_template_entry *entry); const char *ima_d_path(const struct path *path, char **pathbuf, char *filename); /* IMA policy related functions */ -int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode, +int ima_match_policy(struct ima_namespace *ns, + struct user_namespace *mnt_userns, struct inode *inode, const struct cred *cred, u32 secid, enum ima_hooks func, int mask, int flags, int *pcr, struct ima_template_desc **template_desc, const char *func_data, unsigned int *allowed_algos); -void ima_init_policy(void); -void ima_update_policy(void); -void ima_update_policy_flags(void); -ssize_t ima_parse_add_rule(char *); -void ima_delete_rules(void); -int ima_check_policy(void); +void ima_init_policy(struct ima_namespace *ns); +void ima_update_policy(struct ima_namespace *ns); +void ima_update_policy_flags(struct ima_namespace *ns); +ssize_t ima_parse_add_rule(struct ima_namespace *ns, char *rule); +void ima_delete_rules(struct ima_namespace *ns); +int ima_check_policy(struct ima_namespace *ns); void *ima_policy_start(struct seq_file *m, loff_t *pos); void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos); void ima_policy_stop(struct seq_file *m, void *v); @@ -311,14 +324,16 @@ int ima_policy_show(struct seq_file *m, void *v); #define IMA_APPRAISE_KEXEC 0x40 #ifdef CONFIG_IMA_APPRAISE -int ima_check_blacklist(struct integrity_iint_cache *iint, +int ima_check_blacklist(struct ima_namespace *ns, + struct integrity_iint_cache *iint, const struct modsig *modsig, int pcr); int ima_appraise_measurement(enum ima_hooks func, struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, const struct modsig *modsig); -int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode, +int ima_must_appraise(struct ima_namespace *ns, + struct user_namespace *mnt_userns, struct inode *inode, int mask, enum ima_hooks func); void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, @@ -329,7 +344,8 @@ int ima_read_xattr(struct dentry *dentry, struct evm_ima_xattr_data **xattr_value); #else -static inline int ima_check_blacklist(struct integrity_iint_cache *iint, +static inline int ima_check_blacklist(struct ima_namespace *ns, + struct integrity_iint_cache *iint, const struct modsig *modsig, int pcr) { return 0; @@ -346,7 +362,8 @@ static inline int ima_appraise_measurement(enum ima_hooks func, return INTEGRITY_UNKNOWN; } -static inline int ima_must_appraise(struct user_namespace *mnt_userns, +static inline int ima_must_appraise(struct ima_namespace *ns, + struct user_namespace *mnt_userns, struct inode *inode, int mask, enum ima_hooks func) { diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index a64fb0130b01..2df0d8549c13 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -162,6 +162,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename, /** * ima_get_action - appraise & measure decision based on policy. + * @ns: IMA namespace that has the policy * @mnt_userns: user namespace of the mount the inode was found from * @inode: pointer to the inode associated with the object being validated * @cred: pointer to credentials structure to validate @@ -185,7 +186,8 @@ void ima_add_violation(struct file *file, const unsigned char *filename, * Returns IMA_MEASURE, IMA_APPRAISE mask. * */ -int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode, +int ima_get_action(struct ima_namespace *ns, + struct user_namespace *mnt_userns, struct inode *inode, const struct cred *cred, u32 secid, int mask, enum ima_hooks func, int *pcr, struct ima_template_desc **template_desc, @@ -193,9 +195,9 @@ int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode, { int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH; - flags &= ima_policy_flag; + flags &= ns->ima_policy_flag; - return ima_match_policy(mnt_userns, inode, cred, secid, func, mask, + return ima_match_policy(ns, mnt_userns, inode, cred, secid, func, mask, flags, pcr, template_desc, func_data, allowed_algos); } diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index dbba51583e7c..3461025f671b 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -68,7 +68,8 @@ bool is_ima_appraise_enabled(void) * * Return 1 to appraise or hash */ -int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode, +int ima_must_appraise(struct ima_namespace *ns, + struct user_namespace *mnt_userns, struct inode *inode, int mask, enum ima_hooks func) { u32 secid; @@ -77,7 +78,7 @@ int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode, return 0; security_task_getsecid_subj(current, &secid); - return ima_match_policy(mnt_userns, inode, current_cred(), secid, + return ima_match_policy(ns, mnt_userns, inode, current_cred(), secid, func, mask, IMA_APPRAISE | IMA_HASH, NULL, NULL, NULL, NULL); } @@ -341,7 +342,8 @@ static int modsig_verify(enum ima_hooks func, const struct modsig *modsig, * * Returns -EPERM if the hash is blacklisted. */ -int ima_check_blacklist(struct integrity_iint_cache *iint, +int ima_check_blacklist(struct ima_namespace *ns, + struct integrity_iint_cache *iint, const struct modsig *modsig, int pcr) { enum hash_algo hash_algo; @@ -357,7 +359,8 @@ int ima_check_blacklist(struct integrity_iint_cache *iint, rc = is_binary_blacklisted(digest, digestsize); if ((rc == -EPERM) && (iint->flags & IMA_MEASURE)) - process_buffer_measurement(&init_user_ns, NULL, digest, digestsize, + process_buffer_measurement(ns, &init_user_ns, NULL, + digest, digestsize, "blacklisted-hash", NONE, pcr, NULL, false, NULL, 0); } @@ -527,14 +530,16 @@ void ima_inode_post_setattr(struct user_namespace *mnt_userns, struct dentry *dentry) { struct inode *inode = d_backing_inode(dentry); + struct ima_namespace *ns = &init_ima_ns; struct integrity_iint_cache *iint; int action; - if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode) + if (!(ns->ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode) || !(inode->i_opflags & IOP_XATTR)) return; - action = ima_must_appraise(mnt_userns, inode, MAY_ACCESS, POST_SETATTR); + action = ima_must_appraise(ns, mnt_userns, inode, MAY_ACCESS, + POST_SETATTR); iint = integrity_iint_find(inode); if (iint) { set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags); @@ -559,11 +564,12 @@ static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name, return 0; } -static void ima_reset_appraise_flags(struct inode *inode, int digsig) +static void ima_reset_appraise_flags(struct ima_namespace *ns, + struct inode *inode, int digsig) { struct integrity_iint_cache *iint; - if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)) + if (!(ns->ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)) return; iint = integrity_iint_find(inode); @@ -641,6 +647,7 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, const void *xattr_value, size_t xattr_value_len) { const struct evm_ima_xattr_data *xvalue = xattr_value; + struct ima_namespace *ns = &init_ima_ns; int digsig = 0; int result; @@ -658,18 +665,19 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, if (result) return result; - ima_reset_appraise_flags(d_backing_inode(dentry), digsig); + ima_reset_appraise_flags(ns, d_backing_inode(dentry), digsig); } return result; } int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) { + struct ima_namespace *ns = &init_ima_ns; int result; result = ima_protect_xattr(dentry, xattr_name, NULL, 0); if (result == 1 || evm_revalidate_status(xattr_name)) { - ima_reset_appraise_flags(d_backing_inode(dentry), 0); + ima_reset_appraise_flags(ns, d_backing_inode(dentry), 0); if (result == 1) result = 0; } diff --git a/security/integrity/ima/ima_asymmetric_keys.c b/security/integrity/ima/ima_asymmetric_keys.c index f6aa0b47a772..70d87df26068 100644 --- a/security/integrity/ima/ima_asymmetric_keys.c +++ b/security/integrity/ima/ima_asymmetric_keys.c @@ -30,6 +30,7 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key, const void *payload, size_t payload_len, unsigned long flags, bool create) { + struct ima_namespace *ns = &init_ima_ns; bool queued = false; /* Only asymmetric keys are handled by this hook. */ @@ -60,7 +61,8 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key, * if the IMA policy is configured to measure a key linked * to the given keyring. */ - process_buffer_measurement(&init_user_ns, NULL, payload, payload_len, + process_buffer_measurement(ns, &init_user_ns, NULL, + payload, payload_len, keyring->description, KEY_CHECK, 0, keyring->description, false, NULL, 0); } diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 3ad8f7734208..f4477de87416 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -271,7 +271,7 @@ static const struct file_operations ima_ascii_measurements_ops = { .release = seq_release, }; -static ssize_t ima_read_policy(char *path) +static ssize_t ima_read_policy(struct ima_namespace *ns, char *path) { void *data = NULL; char *datap; @@ -296,7 +296,7 @@ static ssize_t ima_read_policy(char *path) datap = data; while (size > 0 && (p = strsep(&datap, "\n"))) { pr_debug("rule: %s\n", p); - rc = ima_parse_add_rule(p); + rc = ima_parse_add_rule(ns, p); if (rc < 0) break; size -= rc; @@ -314,6 +314,7 @@ static ssize_t ima_read_policy(char *path) static ssize_t ima_write_policy(struct file *file, const char __user *buf, size_t datalen, loff_t *ppos) { + struct ima_namespace *ns = &init_ima_ns; char *data; ssize_t result; @@ -336,7 +337,7 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf, goto out_free; if (data[0] == '/') { - result = ima_read_policy(data); + result = ima_read_policy(ns, data); } else if (ima_appraise & IMA_APPRAISE_POLICY) { pr_err("signed policy file (specified as an absolute pathname) required\n"); integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, @@ -344,7 +345,7 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf, 1, 0); result = -EACCES; } else { - result = ima_parse_add_rule(data); + result = ima_parse_add_rule(ns, data); } mutex_unlock(&ima_write_mutex); out_free: @@ -410,11 +411,12 @@ static int ima_open_policy(struct inode *inode, struct file *filp) static int ima_release_policy(struct inode *inode, struct file *file) { const char *cause = valid_policy ? "completed" : "failed"; + struct ima_namespace *ns = &init_ima_ns; if ((file->f_flags & O_ACCMODE) == O_RDONLY) return seq_release(inode, file); - if (valid_policy && ima_check_policy() < 0) { + if (valid_policy && ima_check_policy(ns) < 0) { cause = "failed"; valid_policy = 0; } @@ -424,13 +426,13 @@ static int ima_release_policy(struct inode *inode, struct file *file) "policy_update", cause, !valid_policy, 0); if (!valid_policy) { - ima_delete_rules(); + ima_delete_rules(ns); valid_policy = 1; clear_bit(IMA_FS_BUSY, &ima_fs_flags); return 0; } - ima_update_policy(); + ima_update_policy(ns); #if !defined(CONFIG_IMA_WRITE_POLICY) && !defined(CONFIG_IMA_READ_POLICY) securityfs_remove(ima_policy); ima_policy = NULL; diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index b26fa67476b4..d6b829c360d7 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -104,15 +104,15 @@ static int __init ima_add_boot_aggregate(void) #ifdef CONFIG_IMA_LOAD_X509 void __init ima_load_x509(void) { - int unset_flags = ima_policy_flag & IMA_APPRAISE; + int unset_flags = init_ima_ns.ima_policy_flag & IMA_APPRAISE; - ima_policy_flag &= ~unset_flags; + init_ima_ns.ima_policy_flag &= ~unset_flags; integrity_load_x509(INTEGRITY_KEYRING_IMA, CONFIG_IMA_X509_PATH); /* load also EVM key to avoid appraisal */ evm_load_x509(); - ima_policy_flag |= unset_flags; + init_ima_ns.ima_policy_flag |= unset_flags; } #endif @@ -120,6 +120,10 @@ int __init ima_init(void) { int rc; + rc = ima_ns_init(); + if (rc) + return rc; + ima_tpm_chip = tpm_default_chip(); if (!ima_tpm_chip) pr_info("No TPM chip found, activating TPM-bypass!\n"); @@ -145,7 +149,7 @@ int __init ima_init(void) if (rc != 0) return rc; - ima_init_policy(); + ima_init_policy(&init_ima_ns); rc = ima_fs_init(); if (rc != 0) diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c new file mode 100644 index 000000000000..c919a456b525 --- /dev/null +++ b/security/integrity/ima/ima_init_ima_ns.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2016-2022 IBM Corporation + * Author: + * Yuqiong Sun + * Stefan Berger + */ + +#include "ima.h" + +static int ima_init_namespace(struct ima_namespace *ns) +{ + INIT_LIST_HEAD(&ns->ima_default_rules); + INIT_LIST_HEAD(&ns->ima_policy_rules); + INIT_LIST_HEAD(&ns->ima_temp_rules); + ns->ima_rules = (struct list_head __rcu *)(&ns->ima_default_rules); + ns->ima_policy_flag = 0; + + return 0; +} + +int __init ima_ns_init(void) +{ + return ima_init_namespace(&init_ima_ns); +} + +struct ima_namespace init_ima_ns = { +}; +EXPORT_SYMBOL(init_ima_ns); diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 465865412100..4940f8dda580 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -185,10 +185,11 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint, */ void ima_file_free(struct file *file) { + struct ima_namespace *ns = &init_ima_ns; struct inode *inode = file_inode(file); struct integrity_iint_cache *iint; - if (!ima_policy_flag || !S_ISREG(inode->i_mode)) + if (!ns->ima_policy_flag || !S_ISREG(inode->i_mode)) return; iint = integrity_iint_find(inode); @@ -198,7 +199,8 @@ void ima_file_free(struct file *file) ima_check_last_writer(iint, inode, file); } -static int process_measurement(struct file *file, const struct cred *cred, +static int process_measurement(struct ima_namespace *ns, + struct file *file, const struct cred *cred, u32 secid, char *buf, loff_t size, int mask, enum ima_hooks func) { @@ -217,18 +219,18 @@ static int process_measurement(struct file *file, const struct cred *cred, enum hash_algo hash_algo; unsigned int allowed_algos = 0; - if (!ima_policy_flag || !S_ISREG(inode->i_mode)) + if (!ns->ima_policy_flag || !S_ISREG(inode->i_mode)) return 0; /* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action * bitmask based on the appraise/audit/measurement policy. * Included is the appraise submask. */ - action = ima_get_action(file_mnt_user_ns(file), inode, cred, secid, + action = ima_get_action(ns, file_mnt_user_ns(file), inode, cred, secid, mask, func, &pcr, &template_desc, NULL, &allowed_algos); violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) && - (ima_policy_flag & IMA_MEASURE)); + (ns->ima_policy_flag & IMA_MEASURE)); if (!action && !violation_check) return 0; @@ -346,7 +348,7 @@ static int process_measurement(struct file *file, const struct cred *cred, xattr_value, xattr_len, modsig, pcr, template_desc); if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) { - rc = ima_check_blacklist(iint, modsig, pcr); + rc = ima_check_blacklist(ns, iint, modsig, pcr); if (rc != -EPERM) { inode_lock(inode); rc = ima_appraise_measurement(func, iint, file, @@ -405,12 +407,13 @@ static int process_measurement(struct file *file, const struct cred *cred, */ int ima_file_mmap(struct file *file, unsigned long prot) { + struct ima_namespace *ns = &init_ima_ns; u32 secid; if (file && (prot & PROT_EXEC)) { security_task_getsecid_subj(current, &secid); - return process_measurement(file, current_cred(), secid, NULL, - 0, MAY_EXEC, MMAP_CHECK); + return process_measurement(ns, file, current_cred(), secid, + NULL, 0, MAY_EXEC, MMAP_CHECK); } return 0; @@ -430,6 +433,7 @@ int ima_file_mmap(struct file *file, unsigned long prot) */ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot) { + struct ima_namespace *ns = &init_ima_ns; struct ima_template_desc *template = NULL; struct file *file = vma->vm_file; char filename[NAME_MAX]; @@ -442,13 +446,13 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot) int pcr; /* Is mprotect making an mmap'ed file executable? */ - if (!(ima_policy_flag & IMA_APPRAISE) || !vma->vm_file || + if (!(ns->ima_policy_flag & IMA_APPRAISE) || !vma->vm_file || !(prot & PROT_EXEC) || (vma->vm_flags & VM_EXEC)) return 0; security_task_getsecid_subj(current, &secid); inode = file_inode(vma->vm_file); - action = ima_get_action(file_mnt_user_ns(vma->vm_file), inode, + action = ima_get_action(ns, file_mnt_user_ns(vma->vm_file), inode, current_cred(), secid, MAY_EXEC, MMAP_CHECK, &pcr, &template, NULL, NULL); @@ -484,17 +488,18 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot) */ int ima_bprm_check(struct linux_binprm *bprm) { + struct ima_namespace *ns = &init_ima_ns; int ret; u32 secid; security_task_getsecid_subj(current, &secid); - ret = process_measurement(bprm->file, current_cred(), secid, NULL, 0, - MAY_EXEC, BPRM_CHECK); + ret = process_measurement(ns, bprm->file, current_cred(), secid, NULL, + 0, MAY_EXEC, BPRM_CHECK); if (ret) return ret; security_cred_getsecid(bprm->cred, &secid); - return process_measurement(bprm->file, bprm->cred, secid, NULL, 0, + return process_measurement(ns, bprm->file, bprm->cred, secid, NULL, 0, MAY_EXEC, CREDS_CHECK); } @@ -510,21 +515,23 @@ int ima_bprm_check(struct linux_binprm *bprm) */ int ima_file_check(struct file *file, int mask) { + struct ima_namespace *ns = &init_ima_ns; u32 secid; security_task_getsecid_subj(current, &secid); - return process_measurement(file, current_cred(), secid, NULL, 0, + return process_measurement(ns, file, current_cred(), secid, NULL, 0, mask & (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND), FILE_CHECK); } EXPORT_SYMBOL_GPL(ima_file_check); -static int __ima_inode_hash(struct inode *inode, char *buf, size_t buf_size) +static int __ima_inode_hash(struct ima_namespace *ns, + struct inode *inode, char *buf, size_t buf_size) { struct integrity_iint_cache *iint; int hash_algo; - if (!ima_policy_flag) + if (!ns->ima_policy_flag) return -EOPNOTSUPP; iint = integrity_iint_find(inode); @@ -574,10 +581,12 @@ static int __ima_inode_hash(struct inode *inode, char *buf, size_t buf_size) */ int ima_file_hash(struct file *file, char *buf, size_t buf_size) { + struct ima_namespace *ns = &init_ima_ns; + if (!file) return -EINVAL; - return __ima_inode_hash(file_inode(file), buf, buf_size); + return __ima_inode_hash(ns, file_inode(file), buf, buf_size); } EXPORT_SYMBOL_GPL(ima_file_hash); @@ -601,10 +610,12 @@ EXPORT_SYMBOL_GPL(ima_file_hash); */ int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size) { + struct ima_namespace *ns = &init_ima_ns; + if (!inode) return -EINVAL; - return __ima_inode_hash(inode, buf, buf_size); + return __ima_inode_hash(ns, inode, buf, buf_size); } EXPORT_SYMBOL_GPL(ima_inode_hash); @@ -620,13 +631,14 @@ EXPORT_SYMBOL_GPL(ima_inode_hash); void ima_post_create_tmpfile(struct user_namespace *mnt_userns, struct inode *inode) { + struct ima_namespace *ns = &init_ima_ns; struct integrity_iint_cache *iint; int must_appraise; - if (!ima_policy_flag || !S_ISREG(inode->i_mode)) + if (!ns->ima_policy_flag || !S_ISREG(inode->i_mode)) return; - must_appraise = ima_must_appraise(mnt_userns, inode, MAY_ACCESS, + must_appraise = ima_must_appraise(ns, mnt_userns, inode, MAY_ACCESS, FILE_CHECK); if (!must_appraise) return; @@ -652,14 +664,15 @@ void ima_post_create_tmpfile(struct user_namespace *mnt_userns, void ima_post_path_mknod(struct user_namespace *mnt_userns, struct dentry *dentry) { + struct ima_namespace *ns = &init_ima_ns; struct integrity_iint_cache *iint; struct inode *inode = dentry->d_inode; int must_appraise; - if (!ima_policy_flag || !S_ISREG(inode->i_mode)) + if (!ns->ima_policy_flag || !S_ISREG(inode->i_mode)) return; - must_appraise = ima_must_appraise(mnt_userns, inode, MAY_ACCESS, + must_appraise = ima_must_appraise(ns, mnt_userns, inode, MAY_ACCESS, FILE_CHECK); if (!must_appraise) return; @@ -688,6 +701,7 @@ void ima_post_path_mknod(struct user_namespace *mnt_userns, int ima_read_file(struct file *file, enum kernel_read_file_id read_id, bool contents) { + struct ima_namespace *ns = &init_ima_ns; enum ima_hooks func; u32 secid; @@ -710,7 +724,7 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id, /* Read entire file for all partial reads. */ func = read_idmap[read_id] ?: FILE_CHECK; security_task_getsecid_subj(current, &secid); - return process_measurement(file, current_cred(), secid, NULL, + return process_measurement(ns, file, current_cred(), secid, NULL, 0, MAY_READ, func); } @@ -738,6 +752,7 @@ const int read_idmap[READING_MAX_ID] = { int ima_post_read_file(struct file *file, void *buf, loff_t size, enum kernel_read_file_id read_id) { + struct ima_namespace *ns = &init_ima_ns; enum ima_hooks func; u32 secid; @@ -746,14 +761,15 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, return 0; if (!file || !buf || size == 0) { /* should never happen */ - if (ima_appraise & IMA_APPRAISE_ENFORCE) + if (ns == &init_ima_ns && + (ima_appraise & IMA_APPRAISE_ENFORCE)) return -EACCES; return 0; } func = read_idmap[read_id] ?: FILE_CHECK; security_task_getsecid_subj(current, &secid); - return process_measurement(file, current_cred(), secid, buf, size, + return process_measurement(ns, file, current_cred(), secid, buf, size, MAY_READ, func); } @@ -841,6 +857,7 @@ int ima_post_load_data(char *buf, loff_t size, /** * process_buffer_measurement - Measure the buffer or the buffer data hash + * @ns: IMA namespace that has the policy * @mnt_userns: user namespace of the mount the inode was found from * @inode: inode associated with the object being measured (NULL for KEY_CHECK) * @buf: pointer to the buffer that needs to be added to the log. @@ -859,7 +876,8 @@ int ima_post_load_data(char *buf, loff_t size, * has been written to the passed location but not added to a measurement entry, * a negative value otherwise. */ -int process_buffer_measurement(struct user_namespace *mnt_userns, +int process_buffer_measurement(struct ima_namespace *ns, + struct user_namespace *mnt_userns, struct inode *inode, const void *buf, int size, const char *eventname, enum ima_hooks func, int pcr, const char *func_data, @@ -887,7 +905,7 @@ int process_buffer_measurement(struct user_namespace *mnt_userns, if (digest && digest_len < digest_hash_len) return -EINVAL; - if (!ima_policy_flag && !digest) + if (!ns->ima_policy_flag && !digest) return -ENOENT; template = ima_template_desc_buf(); @@ -906,7 +924,7 @@ int process_buffer_measurement(struct user_namespace *mnt_userns, */ if (func) { security_task_getsecid_subj(current, &secid); - action = ima_get_action(mnt_userns, inode, current_cred(), + action = ima_get_action(ns, mnt_userns, inode, current_cred(), secid, 0, func, &pcr, &template, func_data, NULL); if (!(action & IMA_MEASURE) && !digest) @@ -943,7 +961,7 @@ int process_buffer_measurement(struct user_namespace *mnt_userns, if (digest) memcpy(digest, iint.ima_hash->digest, digest_hash_len); - if (!ima_policy_flag || (func && !(action & IMA_MEASURE))) + if (!ns->ima_policy_flag || (func && !(action & IMA_MEASURE))) return 1; ret = ima_alloc_init_template(&event_data, &entry, template); @@ -977,6 +995,7 @@ int process_buffer_measurement(struct user_namespace *mnt_userns, */ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) { + struct ima_namespace *ns = &init_ima_ns; struct fd f; if (!buf || !size) @@ -986,7 +1005,8 @@ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) if (!f.file) return; - process_buffer_measurement(file_mnt_user_ns(f.file), file_inode(f.file), + process_buffer_measurement(ns, + file_mnt_user_ns(f.file), file_inode(f.file), buf, size, "kexec-cmdline", KEXEC_CMDLINE, 0, NULL, false, NULL, 0); fdput(f); @@ -1016,10 +1036,12 @@ int ima_measure_critical_data(const char *event_label, const void *buf, size_t buf_len, bool hash, u8 *digest, size_t digest_len) { + struct ima_namespace *ns = &init_ima_ns; + if (!event_name || !event_label || !buf || !buf_len) return -ENOPARAM; - return process_buffer_measurement(&init_user_ns, NULL, buf, buf_len, + return process_buffer_measurement(ns, &init_user_ns, NULL, buf, buf_len, event_name, CRITICAL_DATA, 0, event_label, hash, digest, digest_len); @@ -1028,6 +1050,7 @@ EXPORT_SYMBOL_GPL(ima_measure_critical_data); static int __init init_ima(void) { + struct ima_namespace *ns = &init_ima_ns; int error; ima_appraise_parse_cmdline(); @@ -1052,7 +1075,7 @@ static int __init init_ima(void) pr_warn("Couldn't register LSM notifier, error %d\n", error); if (!error) - ima_update_policy_flags(); + ima_update_policy_flags(ns); return error; } diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 2a1f6418b10a..b0e1c16b7f37 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -52,7 +52,6 @@ #define INVALID_PCR(a) (((a) < 0) || \ (a) >= (sizeof_field(struct integrity_iint_cache, measured_pcrs) * 8)) -int ima_policy_flag; static int temp_ima_appraise; static int build_ima_appraise __ro_after_init; @@ -233,11 +232,6 @@ static struct ima_rule_entry critical_data_rules[] __ro_after_init = { /* An array of architecture specific rules */ 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 __rcu *ima_rules = (struct list_head __rcu *)(&ima_default_rules); - static int ima_policy __initdata; static int __init default_measure_policy_setup(char *str) @@ -454,12 +448,12 @@ static bool ima_rule_contains_lsm_cond(struct ima_rule_entry *entry) * to the old, stale LSM policy. Update the IMA LSM based rules to reflect * the reloaded LSM policy. */ -static void ima_lsm_update_rules(void) +static void ima_lsm_update_rules(struct ima_namespace *ns) { struct ima_rule_entry *entry, *e; int result; - list_for_each_entry_safe(entry, e, &ima_policy_rules, list) { + list_for_each_entry_safe(entry, e, &ns->ima_policy_rules, list) { if (!ima_rule_contains_lsm_cond(entry)) continue; @@ -474,10 +468,12 @@ static void ima_lsm_update_rules(void) int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event, void *lsm_data) { + struct ima_namespace *ns = &init_ima_ns; + if (event != LSM_POLICY_CHANGE) return NOTIFY_DONE; - ima_lsm_update_rules(); + ima_lsm_update_rules(ns); return NOTIFY_OK; } @@ -669,6 +665,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) /** * ima_match_policy - decision based on LSM and other conditions + * @ns: IMA namespace that has the policy * @mnt_userns: user namespace of the mount the inode was found from * @inode: pointer to an inode for which the policy decision is being made * @cred: pointer to a credentials structure for which the policy decision is @@ -688,7 +685,8 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) * list when walking it. Reads are many orders of magnitude more numerous * than writes so ima_match_policy() is classical RCU candidate. */ -int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode, +int ima_match_policy(struct ima_namespace *ns, + struct user_namespace *mnt_userns, struct inode *inode, const struct cred *cred, u32 secid, enum ima_hooks func, int mask, int flags, int *pcr, struct ima_template_desc **template_desc, @@ -702,7 +700,7 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode, *template_desc = ima_template_desc_current(); rcu_read_lock(); - ima_rules_tmp = rcu_dereference(ima_rules); + ima_rules_tmp = rcu_dereference(ns->ima_rules); list_for_each_entry_rcu(entry, ima_rules_tmp, list) { if (!(entry->action & actmask)) @@ -746,8 +744,8 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode, } /** - * ima_update_policy_flags() - Update global IMA variables - * + * ima_update_policy_flags() - Update namespaced IMA variables + * @ns: IMA namespace that has the policy * Update ima_policy_flag and ima_setxattr_allowed_hash_algorithms * based on the currently loaded policy. * @@ -760,14 +758,14 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode, * * Context: called after a policy update and at system initialization. */ -void ima_update_policy_flags(void) +void ima_update_policy_flags(struct ima_namespace *ns) { struct ima_rule_entry *entry; int new_policy_flag = 0; struct list_head *ima_rules_tmp; rcu_read_lock(); - ima_rules_tmp = rcu_dereference(ima_rules); + ima_rules_tmp = rcu_dereference(ns->ima_rules); list_for_each_entry_rcu(entry, ima_rules_tmp, list) { /* * SETXATTR_CHECK rules do not implement a full policy check @@ -797,7 +795,7 @@ void ima_update_policy_flags(void) if (!ima_appraise) new_policy_flag &= ~IMA_APPRAISE; - ima_policy_flag = new_policy_flag; + ns->ima_policy_flag = new_policy_flag; } static int ima_appraise_flag(enum ima_hooks func) @@ -813,7 +811,8 @@ static int ima_appraise_flag(enum ima_hooks func) return 0; } -static void add_rules(struct ima_rule_entry *entries, int count, +static void add_rules(struct ima_namespace *ns, + struct ima_rule_entry *entries, int count, enum policy_rule_list policy_rule) { int i = 0; @@ -822,7 +821,7 @@ static void add_rules(struct ima_rule_entry *entries, int count, struct ima_rule_entry *entry; if (policy_rule & IMA_DEFAULT_POLICY) - list_add_tail(&entries[i].list, &ima_default_rules); + list_add_tail(&entries[i].list, &ns->ima_default_rules); if (policy_rule & IMA_CUSTOM_POLICY) { entry = kmemdup(&entries[i], sizeof(*entry), @@ -830,7 +829,7 @@ static void add_rules(struct ima_rule_entry *entries, int count, if (!entry) continue; - list_add_tail(&entry->list, &ima_policy_rules); + list_add_tail(&entry->list, &ns->ima_policy_rules); } if (entries[i].action == APPRAISE) { if (entries != build_appraise_rules) @@ -843,9 +842,10 @@ static void add_rules(struct ima_rule_entry *entries, int count, } } -static int ima_parse_rule(char *rule, struct ima_rule_entry *entry); +static int ima_parse_rule(struct ima_namespace *ns, + char *rule, struct ima_rule_entry *entry); -static int __init ima_init_arch_policy(void) +static int __init ima_init_arch_policy(struct ima_namespace *ns) { const char * const *arch_rules; const char * const *rules; @@ -873,7 +873,7 @@ static int __init ima_init_arch_policy(void) result = strscpy(rule, *rules, sizeof(rule)); INIT_LIST_HEAD(&arch_policy_entry[i].list); - result = ima_parse_rule(rule, &arch_policy_entry[i]); + result = ima_parse_rule(ns, rule, &arch_policy_entry[i]); if (result) { pr_warn("Skipping unknown architecture policy rule: %s\n", rule); @@ -888,26 +888,27 @@ static int __init ima_init_arch_policy(void) /** * ima_init_policy - initialize the default measure rules. - * + * @ns: IMA namespace to which the policy belongs to * ima_rules points to either the ima_default_rules or the new ima_policy_rules. */ -void __init ima_init_policy(void) +void __init ima_init_policy(struct ima_namespace *ns) { int build_appraise_entries, arch_entries; /* if !ima_policy, we load NO default rules */ if (ima_policy) - add_rules(dont_measure_rules, ARRAY_SIZE(dont_measure_rules), + add_rules(ns, dont_measure_rules, + ARRAY_SIZE(dont_measure_rules), IMA_DEFAULT_POLICY); switch (ima_policy) { case ORIGINAL_TCB: - add_rules(original_measurement_rules, + add_rules(ns, original_measurement_rules, ARRAY_SIZE(original_measurement_rules), IMA_DEFAULT_POLICY); break; case DEFAULT_TCB: - add_rules(default_measurement_rules, + add_rules(ns, default_measurement_rules, ARRAY_SIZE(default_measurement_rules), IMA_DEFAULT_POLICY); break; @@ -921,11 +922,11 @@ void __init ima_init_policy(void) * and custom policies, prior to other appraise rules. * (Highest priority) */ - arch_entries = ima_init_arch_policy(); + arch_entries = ima_init_arch_policy(ns); if (!arch_entries) pr_info("No architecture policies found\n"); else - add_rules(arch_policy_entry, arch_entries, + add_rules(ns, arch_policy_entry, arch_entries, IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY); /* @@ -933,7 +934,7 @@ void __init ima_init_policy(void) * signatures, prior to other appraise rules. */ if (ima_use_secure_boot) - add_rules(secure_boot_rules, ARRAY_SIZE(secure_boot_rules), + add_rules(ns, secure_boot_rules, ARRAY_SIZE(secure_boot_rules), IMA_DEFAULT_POLICY); /* @@ -945,39 +946,41 @@ void __init ima_init_policy(void) build_appraise_entries = ARRAY_SIZE(build_appraise_rules); if (build_appraise_entries) { if (ima_use_secure_boot) - add_rules(build_appraise_rules, build_appraise_entries, + add_rules(ns, build_appraise_rules, + build_appraise_entries, IMA_CUSTOM_POLICY); else - add_rules(build_appraise_rules, build_appraise_entries, + add_rules(ns, build_appraise_rules, + build_appraise_entries, IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY); } if (ima_use_appraise_tcb) - add_rules(default_appraise_rules, + add_rules(ns, default_appraise_rules, ARRAY_SIZE(default_appraise_rules), IMA_DEFAULT_POLICY); if (ima_use_critical_data) - add_rules(critical_data_rules, + add_rules(ns, critical_data_rules, ARRAY_SIZE(critical_data_rules), IMA_DEFAULT_POLICY); atomic_set(&ima_setxattr_allowed_hash_algorithms, 0); - ima_update_policy_flags(); + ima_update_policy_flags(ns); } /* Make sure we have a valid policy, at least containing some rules. */ -int ima_check_policy(void) +int ima_check_policy(struct ima_namespace *ns) { - if (list_empty(&ima_temp_rules)) + if (list_empty(&ns->ima_temp_rules)) return -EINVAL; return 0; } /** * ima_update_policy - update default_rules with new measure rules - * + * @ns: IMA namespace that has the policy * Called on file .release to update the default rules with a complete new * policy. What we do here is to splice ima_policy_rules and ima_temp_rules so * they make a queue. The policy may be updated multiple times and this is the @@ -986,16 +989,17 @@ int ima_check_policy(void) * Policy rules are never deleted so ima_policy_flag gets zeroed only once when * we switch from the default policy to user defined. */ -void ima_update_policy(void) +void ima_update_policy(struct ima_namespace *ns) { - struct list_head *policy = &ima_policy_rules; + struct list_head *policy = &ns->ima_policy_rules; - list_splice_tail_init_rcu(&ima_temp_rules, policy, synchronize_rcu); + list_splice_tail_init_rcu(&ns->ima_temp_rules, policy, + synchronize_rcu); - if (ima_rules != (struct list_head __rcu *)policy) { - ima_policy_flag = 0; + if (ns->ima_rules != (struct list_head __rcu *)policy) { + ns->ima_policy_flag = 0; - rcu_assign_pointer(ima_rules, policy); + rcu_assign_pointer(ns->ima_rules, policy); /* * IMA architecture specific policy rules are specified * as strings and converted to an array of ima_entry_rules @@ -1004,10 +1008,10 @@ void ima_update_policy(void) */ kfree(arch_policy_entry); } - ima_update_policy_flags(); + ima_update_policy_flags(ns); /* Custom IMA policy has been loaded */ - ima_process_queued_keys(); + ima_process_queued_keys(ns); } /* Keep the enumeration in sync with the policy_tokens! */ @@ -1077,7 +1081,8 @@ static const match_table_t policy_tokens = { {Opt_err, NULL} }; -static int ima_lsm_rule_init(struct ima_rule_entry *entry, +static int ima_lsm_rule_init(struct ima_namespace *ns, + struct ima_rule_entry *entry, substring_t *args, int lsm_rule, int audit_type) { int result; @@ -1097,7 +1102,8 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry, pr_warn("rule for LSM \'%s\' is undefined\n", entry->lsm[lsm_rule].args_p); - if (ima_rules == (struct list_head __rcu *)(&ima_default_rules)) { + if (ns->ima_rules == + (struct list_head __rcu *)&ns->ima_default_rules) { kfree(entry->lsm[lsm_rule].args_p); entry->lsm[lsm_rule].args_p = NULL; result = -EINVAL; @@ -1324,7 +1330,8 @@ static unsigned int ima_parse_appraise_algos(char *arg) return res; } -static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) +static int ima_parse_rule(struct ima_namespace *ns, + char *rule, struct ima_rule_entry *entry) { struct audit_buffer *ab; char *from; @@ -1674,37 +1681,37 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) break; case Opt_obj_user: ima_log_string(ab, "obj_user", args[0].from); - result = ima_lsm_rule_init(entry, args, + result = ima_lsm_rule_init(ns, entry, args, LSM_OBJ_USER, AUDIT_OBJ_USER); break; case Opt_obj_role: ima_log_string(ab, "obj_role", args[0].from); - result = ima_lsm_rule_init(entry, args, + result = ima_lsm_rule_init(ns, entry, args, LSM_OBJ_ROLE, AUDIT_OBJ_ROLE); break; case Opt_obj_type: ima_log_string(ab, "obj_type", args[0].from); - result = ima_lsm_rule_init(entry, args, + result = ima_lsm_rule_init(ns, entry, args, LSM_OBJ_TYPE, AUDIT_OBJ_TYPE); break; case Opt_subj_user: ima_log_string(ab, "subj_user", args[0].from); - result = ima_lsm_rule_init(entry, args, + result = ima_lsm_rule_init(ns, entry, args, LSM_SUBJ_USER, AUDIT_SUBJ_USER); break; case Opt_subj_role: ima_log_string(ab, "subj_role", args[0].from); - result = ima_lsm_rule_init(entry, args, + result = ima_lsm_rule_init(ns, entry, args, LSM_SUBJ_ROLE, AUDIT_SUBJ_ROLE); break; case Opt_subj_type: ima_log_string(ab, "subj_type", args[0].from); - result = ima_lsm_rule_init(entry, args, + result = ima_lsm_rule_init(ns, entry, args, LSM_SUBJ_TYPE, AUDIT_SUBJ_TYPE); break; @@ -1805,12 +1812,13 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) /** * ima_parse_add_rule - add a rule to ima_policy_rules + * @ns: IMA namespace that has the policy * @rule - ima measurement policy rule * * Avoid locking by allowing just one writer at a time in ima_write_policy() * Returns the length of the rule parsed, an error code on failure */ -ssize_t ima_parse_add_rule(char *rule) +ssize_t ima_parse_add_rule(struct ima_namespace *ns, char *rule) { static const char op[] = "update_policy"; char *p; @@ -1834,7 +1842,7 @@ ssize_t ima_parse_add_rule(char *rule) INIT_LIST_HEAD(&entry->list); - result = ima_parse_rule(p, entry); + result = ima_parse_rule(ns, p, entry); if (result) { ima_free_rule(entry); integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, @@ -1843,23 +1851,24 @@ ssize_t ima_parse_add_rule(char *rule) return result; } - list_add_tail(&entry->list, &ima_temp_rules); + list_add_tail(&entry->list, &ns->ima_temp_rules); return len; } /** - * ima_delete_rules() called to cleanup invalid in-flight policy. + * ima_delete_rules - called to cleanup invalid in-flight policy. + * @ns: IMA namespace that has the policy * We don't need locking as we operate on the temp list, which is * different from the active one. There is also only one user of * ima_delete_rules() at a time. */ -void ima_delete_rules(void) +void ima_delete_rules(struct ima_namespace *ns) { struct ima_rule_entry *entry, *tmp; temp_ima_appraise = 0; - list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) { + list_for_each_entry_safe(entry, tmp, &ns->ima_temp_rules, list) { list_del(&entry->list); ima_free_rule(entry); } @@ -1885,12 +1894,13 @@ static const char *const mask_tokens[] = { void *ima_policy_start(struct seq_file *m, loff_t *pos) { + struct ima_namespace *ns = &init_ima_ns; loff_t l = *pos; struct ima_rule_entry *entry; struct list_head *ima_rules_tmp; rcu_read_lock(); - ima_rules_tmp = rcu_dereference(ima_rules); + ima_rules_tmp = rcu_dereference(ns->ima_rules); list_for_each_entry_rcu(entry, ima_rules_tmp, list) { if (!l--) { rcu_read_unlock(); @@ -1903,6 +1913,7 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos) void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos) { + struct ima_namespace *ns = &init_ima_ns; struct ima_rule_entry *entry = v; rcu_read_lock(); @@ -1910,8 +1921,8 @@ void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos) rcu_read_unlock(); (*pos)++; - return (&entry->list == &ima_default_rules || - &entry->list == &ima_policy_rules) ? NULL : entry; + return (&entry->list == &ns->ima_default_rules || + &entry->list == &ns->ima_policy_rules) ? NULL : entry; } void ima_policy_stop(struct seq_file *m, void *v) @@ -2174,6 +2185,7 @@ int ima_policy_show(struct seq_file *m, void *v) */ bool ima_appraise_signature(enum kernel_read_file_id id) { + struct ima_namespace *ns = &init_ima_ns; struct ima_rule_entry *entry; bool found = false; enum ima_hooks func; @@ -2185,7 +2197,7 @@ bool ima_appraise_signature(enum kernel_read_file_id id) func = read_idmap[id] ?: FILE_CHECK; rcu_read_lock(); - ima_rules_tmp = rcu_dereference(ima_rules); + ima_rules_tmp = rcu_dereference(ns->ima_rules); list_for_each_entry_rcu(entry, ima_rules_tmp, list) { if (entry->action != APPRAISE) continue; diff --git a/security/integrity/ima/ima_queue_keys.c b/security/integrity/ima/ima_queue_keys.c index 93056c03bf5a..e366a21dd8be 100644 --- a/security/integrity/ima/ima_queue_keys.c +++ b/security/integrity/ima/ima_queue_keys.c @@ -10,6 +10,7 @@ #include #include +#include #include #include "ima.h" @@ -42,7 +43,7 @@ static bool timer_expired; static void ima_keys_handler(struct work_struct *work) { timer_expired = true; - ima_process_queued_keys(); + ima_process_queued_keys(&init_ima_ns); } /* @@ -130,11 +131,15 @@ bool ima_queue_key(struct key *keyring, const void *payload, * This function sets ima_process_keys to true and processes queued keys. * From here on keys will be processed right away (not queued). */ -void ima_process_queued_keys(void) +void ima_process_queued_keys(struct ima_namespace *ns) { struct ima_key_entry *entry, *tmp; bool process = false; + /* only applies to init_ima_ns */ + if (ns != &init_ima_ns) + return; + if (ima_process_keys) return; @@ -159,7 +164,7 @@ void ima_process_queued_keys(void) list_for_each_entry_safe(entry, tmp, &ima_keys, list) { if (!timer_expired) - process_buffer_measurement(&init_user_ns, NULL, + process_buffer_measurement(ns, &init_user_ns, NULL, entry->payload, entry->payload_len, entry->keyring_name, From patchwork Tue Jan 25 22:46:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724302 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4E6FBC3526E for ; Tue, 25 Jan 2022 22:47:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234255AbiAYWrl (ORCPT ); Tue, 25 Jan 2022 17:47:41 -0500 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:42676 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S234224AbiAYWr3 (ORCPT ); Tue, 25 Jan 2022 17:47:29 -0500 Received: from pps.filterd (m0098414.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PM68Hl002480; Tue, 25 Jan 2022 22:47:00 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=KijHy903UMH2XLgL8VnGJFey6CestvpIRiHVW5YG8YA=; b=jCffWbfJ5xltTsQRui3vkfViDb8fILuCHyMvTdi/Y1alF/Yd003q2wg93nism29wrr21 bbMjG0EebtNfcRqBJag9qqY8xbjbqA6bU0NNYb/O8v1U63UfGDiJ8AUqsJ8cTNb/f/wP 1OaHmpQrRiLV9XivDy51wtm6CwNayCq2r6FosmXwsFhmW/eUQfTvcOYpf+838qcyoXI3 KPT09GVwAAoVCux/SNh5kjnGpuD8JQ7DAJv0PsPJRHj/JBLjb92O5omPNuj9FIVMtTEe dWWu3sC6PtKAnB59+2/swPOzaPZ7SWFusCgmkXJBIqKF8L0iZXqd7QxkB2ZXssHONzFY hA== Received: from pps.reinject (localhost [127.0.0.1]) by mx0b-001b2d01.pphosted.com with ESMTP id 3dtryw1cba-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:00 +0000 Received: from m0098414.ppops.net (m0098414.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMZYxa001673; Tue, 25 Jan 2022 22:46:59 GMT Received: from ppma05wdc.us.ibm.com (1b.90.2fa9.ip4.static.sl-reverse.com [169.47.144.27]) by mx0b-001b2d01.pphosted.com with ESMTP id 3dtryw1cb4-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:46:59 +0000 Received: from pps.filterd (ppma05wdc.us.ibm.com [127.0.0.1]) by ppma05wdc.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMhnr1010313; Tue, 25 Jan 2022 22:46:58 GMT Received: from b01cxnp23032.gho.pok.ibm.com (b01cxnp23032.gho.pok.ibm.com [9.57.198.27]) by ppma05wdc.us.ibm.com with ESMTP id 3dtbch8rfr-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:46:58 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23032.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkvc123986554 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:57 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 4575CAC062; Tue, 25 Jan 2022 22:46:57 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 2FB28AC067; Tue, 25 Jan 2022 22:46:57 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:57 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger Subject: [PATCH v9 06/23] ima: Move arch_policy_entry into ima_namespace Date: Tue, 25 Jan 2022 17:46:28 -0500 Message-Id: <20220125224645.79319-7-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: 1fEdqweKj6hy-Kniz9FVWXEPsbDzGOlW X-Proofpoint-ORIG-GUID: gLa-yLtgaLCeu3VtdAzZA9TQEkJYGqGc X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_06,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxscore=0 lowpriorityscore=0 clxscore=1011 mlxlogscore=999 phishscore=0 suspectscore=0 spamscore=0 impostorscore=0 priorityscore=1501 bulkscore=0 adultscore=0 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger Move the arch_policy_entry pointer into ima_namespace. When freeing the memory set the pointer to NULL. Signed-off-by: Stefan Berger Acked-by: Christian Brauner Reviewed-by: Mimi Zohar --- security/integrity/ima/ima.h | 3 +++ security/integrity/ima/ima_init_ima_ns.c | 1 + security/integrity/ima/ima_policy.c | 23 +++++++++++------------ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 5b44fa6f27c4..a4669b55c2e0 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -125,6 +125,9 @@ struct ima_namespace { struct list_head __rcu *ima_rules; /* current policy */ int ima_policy_flag; + + /* An array of architecture specific rules */ + struct ima_rule_entry *arch_policy_entry; } __randomize_layout; extern struct ima_namespace init_ima_ns; diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c index c919a456b525..ae33621c3955 100644 --- a/security/integrity/ima/ima_init_ima_ns.c +++ b/security/integrity/ima/ima_init_ima_ns.c @@ -15,6 +15,7 @@ static int ima_init_namespace(struct ima_namespace *ns) INIT_LIST_HEAD(&ns->ima_temp_rules); ns->ima_rules = (struct list_head __rcu *)(&ns->ima_default_rules); ns->ima_policy_flag = 0; + ns->arch_policy_entry = NULL; return 0; } diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index b0e1c16b7f37..05b2bc06ab0c 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -229,9 +229,6 @@ static struct ima_rule_entry critical_data_rules[] __ro_after_init = { {.action = MEASURE, .func = CRITICAL_DATA, .flags = IMA_FUNC}, }; -/* An array of architecture specific rules */ -static struct ima_rule_entry *arch_policy_entry __ro_after_init; - static int ima_policy __initdata; static int __init default_measure_policy_setup(char *str) @@ -860,9 +857,10 @@ static int __init ima_init_arch_policy(struct ima_namespace *ns) for (rules = arch_rules; *rules != NULL; rules++) arch_entries++; - arch_policy_entry = kcalloc(arch_entries + 1, - sizeof(*arch_policy_entry), GFP_KERNEL); - if (!arch_policy_entry) + ns->arch_policy_entry = kcalloc(arch_entries + 1, + sizeof(*ns->arch_policy_entry), + GFP_KERNEL); + if (!ns->arch_policy_entry) return 0; /* Convert each policy string rules to struct ima_rule_entry format */ @@ -872,13 +870,13 @@ static int __init ima_init_arch_policy(struct ima_namespace *ns) result = strscpy(rule, *rules, sizeof(rule)); - INIT_LIST_HEAD(&arch_policy_entry[i].list); - result = ima_parse_rule(ns, rule, &arch_policy_entry[i]); + INIT_LIST_HEAD(&ns->arch_policy_entry[i].list); + result = ima_parse_rule(ns, rule, &ns->arch_policy_entry[i]); if (result) { pr_warn("Skipping unknown architecture policy rule: %s\n", rule); - memset(&arch_policy_entry[i], 0, - sizeof(*arch_policy_entry)); + memset(&ns->arch_policy_entry[i], 0, + sizeof(ns->arch_policy_entry[i])); continue; } i++; @@ -926,7 +924,7 @@ void __init ima_init_policy(struct ima_namespace *ns) if (!arch_entries) pr_info("No architecture policies found\n"); else - add_rules(ns, arch_policy_entry, arch_entries, + add_rules(ns, ns->arch_policy_entry, arch_entries, IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY); /* @@ -1006,7 +1004,8 @@ void ima_update_policy(struct ima_namespace *ns) * on boot. After loading a custom policy, free the * architecture specific rules stored as an array. */ - kfree(arch_policy_entry); + kfree(ns->arch_policy_entry); + ns->arch_policy_entry = NULL; } ima_update_policy_flags(ns); From patchwork Tue Jan 25 22:46:29 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724307 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8081CC4707A for ; Tue, 25 Jan 2022 22:47:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234297AbiAYWrn (ORCPT ); Tue, 25 Jan 2022 17:47:43 -0500 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:30350 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S234212AbiAYWr2 (ORCPT ); Tue, 25 Jan 2022 17:47:28 -0500 Received: from pps.filterd (m0098416.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PMh3G1012432; Tue, 25 Jan 2022 22:47:01 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=Z4VzH2dWRazuDvP1FQdqkVIa/PMZae4NDMUZUDGB1FY=; b=gzGxPXsJXRknyJXsaSpjoq59RC84WtpyEoRewFxpPB/a628xaqz/AnKu59Jxa5Jw+Sy2 yLQpXLIawf/heJym0KFr2ARqlaeJ1iwlilQE/y+Nv8DdYwo9AOuN372Z+9Q5fjUJJAGv VzDz72Ej+cNSba3ITZSAyxuTqQ/tHBKogqjQg4FY19C1+PIG3itEg/fw4S6oHBLeoRmX RRFDmaR5F3BC3td/k+oUzxqNTf8+mAsSU1I7DtEZkB9VbtgnD4U42A70C9o9MxEVnDed djHnOgWprqjYZPy7BHKkpzh+kWQH2GTkqlljXggj2W3Wl51mA1l5l5zc+VHJH0/CunIR aA== Received: from pps.reinject (localhost [127.0.0.1]) by mx0b-001b2d01.pphosted.com with ESMTP id 3dtt83g1u5-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:01 +0000 Received: from m0098416.ppops.net (m0098416.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMiPr0016936; Tue, 25 Jan 2022 22:47:00 GMT Received: from ppma03wdc.us.ibm.com (ba.79.3fa9.ip4.static.sl-reverse.com [169.63.121.186]) by mx0b-001b2d01.pphosted.com with ESMTP id 3dtt83g1tm-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:00 +0000 Received: from pps.filterd (ppma03wdc.us.ibm.com [127.0.0.1]) by ppma03wdc.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMhb7h016426; Tue, 25 Jan 2022 22:46:59 GMT Received: from b01cxnp23032.gho.pok.ibm.com (b01cxnp23032.gho.pok.ibm.com [9.57.198.27]) by ppma03wdc.us.ibm.com with ESMTP id 3dr9jaf1dj-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:46:59 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23032.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkvew30867712 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:57 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 73AB3AC05F; Tue, 25 Jan 2022 22:46:57 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 54D76AC059; Tue, 25 Jan 2022 22:46:57 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:57 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger Subject: [PATCH v9 07/23] ima: Move ima_htable into ima_namespace Date: Tue, 25 Jan 2022 17:46:29 -0500 Message-Id: <20220125224645.79319-8-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: G2lABTZB41UGJ6NmkzttmMtP32tlq_4A X-Proofpoint-GUID: VSwo97Uv4ZlXp47278DTLeA3qao3VO8N X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_06,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 mlxscore=0 phishscore=0 lowpriorityscore=0 spamscore=0 malwarescore=0 adultscore=0 priorityscore=1501 clxscore=1015 bulkscore=0 impostorscore=0 mlxlogscore=999 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger Move ima_htable into ima_namespace. This way a front-end like securityfs can show the number of violations of an IMA namespace. Signed-off-by: Stefan Berger Acked-by: Christian Brauner --- security/integrity/ima/ima.h | 33 +++++++++++++--------- security/integrity/ima/ima_api.c | 18 +++++++----- security/integrity/ima/ima_fs.c | 8 ++++-- security/integrity/ima/ima_init.c | 7 +++-- security/integrity/ima/ima_init_ima_ns.c | 4 +++ security/integrity/ima/ima_kexec.c | 3 +- security/integrity/ima/ima_main.c | 14 +++++---- security/integrity/ima/ima_queue.c | 36 ++++++++++++------------ security/integrity/ima/ima_template.c | 5 ++-- 9 files changed, 76 insertions(+), 52 deletions(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index a4669b55c2e0..340a59174670 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -117,6 +117,12 @@ struct ima_kexec_hdr { u64 count; }; +struct ima_h_table { + atomic_long_t len; /* number of stored measurements in the list */ + atomic_long_t violations; + struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE]; +}; + struct ima_namespace { /* policy rules */ struct list_head ima_default_rules; @@ -128,6 +134,8 @@ struct ima_namespace { /* An array of architecture specific rules */ struct ima_rule_entry *arch_policy_entry; + + struct ima_h_table ima_htable; } __randomize_layout; extern struct ima_namespace init_ima_ns; @@ -149,7 +157,8 @@ extern bool ima_canonical_fmt; int ima_init(void); int ima_fs_init(void); int ima_ns_init(void); -int ima_add_template_entry(struct ima_template_entry *entry, int violation, +int ima_add_template_entry(struct ima_namespace *ns, + struct ima_template_entry *entry, int violation, const char *op, struct inode *inode, const unsigned char *filename); int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash); @@ -158,7 +167,8 @@ int ima_calc_buffer_hash(const void *buf, loff_t len, int ima_calc_field_array_hash(struct ima_field_data *field_data, struct ima_template_entry *entry); int ima_calc_boot_aggregate(struct ima_digest_data *hash); -void ima_add_violation(struct file *file, const unsigned char *filename, +void ima_add_violation(struct ima_namespace *ns, + struct file *file, const unsigned char *filename, struct integrity_iint_cache *iint, const char *op, const char *cause); int ima_init_crypto(void); @@ -171,8 +181,10 @@ struct ima_template_desc *ima_template_desc_current(void); struct ima_template_desc *ima_template_desc_buf(void); struct ima_template_desc *lookup_template_desc(const char *name); bool ima_template_has_modsig(const struct ima_template_desc *ima_template); -int ima_restore_measurement_entry(struct ima_template_entry *entry); -int ima_restore_measurement_list(loff_t bufsize, void *buf); +int ima_restore_measurement_entry(struct ima_namespace *ns, + struct ima_template_entry *entry); +int ima_restore_measurement_list(struct ima_namespace *ns, + loff_t bufsize, void *buf); int ima_measurements_show(struct seq_file *m, void *v); unsigned long ima_get_binary_runtime_size(void); int ima_init_template(void); @@ -186,13 +198,6 @@ int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event, */ extern spinlock_t ima_queue_lock; -struct ima_h_table { - atomic_long_t len; /* number of stored measurements in the list */ - atomic_long_t violations; - struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE]; -}; -extern struct ima_h_table ima_htable; - static inline unsigned int ima_hash_key(u8 *digest) { /* there is no point in taking a hash of part of a digest */ @@ -277,7 +282,8 @@ int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func); int ima_collect_measurement(struct integrity_iint_cache *iint, struct file *file, void *buf, loff_t size, enum hash_algo algo, struct modsig *modsig); -void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, +void ima_store_measurement(struct ima_namespace *ns, + struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, const struct modsig *modsig, int pcr, @@ -293,7 +299,8 @@ void ima_audit_measurement(struct integrity_iint_cache *iint, int ima_alloc_init_template(struct ima_event_data *event_data, struct ima_template_entry **entry, struct ima_template_desc *template_desc); -int ima_store_template(struct ima_template_entry *entry, int violation, +int ima_store_template(struct ima_namespace *ns, + struct ima_template_entry *entry, int violation, struct inode *inode, const unsigned char *filename, int pcr); void ima_free_template_entry(struct ima_template_entry *entry); diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 2df0d8549c13..bee35ebb3a38 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -99,7 +99,8 @@ int ima_alloc_init_template(struct ima_event_data *event_data, * * Returns 0 on success, error code otherwise */ -int ima_store_template(struct ima_template_entry *entry, +int ima_store_template(struct ima_namespace *ns, + struct ima_template_entry *entry, int violation, struct inode *inode, const unsigned char *filename, int pcr) { @@ -119,7 +120,8 @@ int ima_store_template(struct ima_template_entry *entry, } } entry->pcr = pcr; - result = ima_add_template_entry(entry, violation, op, inode, filename); + result = ima_add_template_entry(ns, entry, violation, op, inode, + filename); return result; } @@ -130,7 +132,8 @@ int ima_store_template(struct ima_template_entry *entry, * By extending the PCR with 0xFF's instead of with zeroes, the PCR * value is invalidated. */ -void ima_add_violation(struct file *file, const unsigned char *filename, +void ima_add_violation(struct ima_namespace *ns, + struct file *file, const unsigned char *filename, struct integrity_iint_cache *iint, const char *op, const char *cause) { @@ -144,14 +147,14 @@ void ima_add_violation(struct file *file, const unsigned char *filename, int result; /* can overflow, only indicator */ - atomic_long_inc(&ima_htable.violations); + atomic_long_inc(&ns->ima_htable.violations); result = ima_alloc_init_template(&event_data, &entry, NULL); if (result < 0) { result = -ENOMEM; goto err_out; } - result = ima_store_template(entry, violation, inode, + result = ima_store_template(ns, entry, violation, inode, filename, CONFIG_IMA_MEASURE_PCR_IDX); if (result < 0) ima_free_template_entry(entry); @@ -299,7 +302,8 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, * * Must be called with iint->mutex held. */ -void ima_store_measurement(struct integrity_iint_cache *iint, +void ima_store_measurement(struct ima_namespace *ns, + struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, const struct modsig *modsig, int pcr, @@ -334,7 +338,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint, return; } - result = ima_store_template(entry, violation, inode, filename, pcr); + result = ima_store_template(ns, entry, violation, inode, filename, pcr); if ((!result || result == -EEXIST) && !(file->f_flags & O_DIRECT)) { iint->flags |= IMA_MEASURED; iint->measured_pcrs |= (0x1 << pcr); diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index f4477de87416..9b4dce57c1a6 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -52,7 +52,10 @@ static ssize_t ima_show_htable_violations(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { - return ima_show_htable_value(buf, count, ppos, &ima_htable.violations); + struct ima_namespace *ns = &init_ima_ns; + + return ima_show_htable_value(buf, count, ppos, + &ns->ima_htable.violations); } static const struct file_operations ima_htable_violations_ops = { @@ -64,8 +67,9 @@ static ssize_t ima_show_measurements_count(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { - return ima_show_htable_value(buf, count, ppos, &ima_htable.len); + struct ima_namespace *ns = &init_ima_ns; + return ima_show_htable_value(buf, count, ppos, &ns->ima_htable.len); } static const struct file_operations ima_measurements_count_ops = { diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index d6b829c360d7..22ca5d872be0 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -39,7 +39,7 @@ struct tpm_chip *ima_tpm_chip; * a different value.) Violations add a zero entry to the measurement * list and extend the aggregate PCR value with ff...ff's. */ -static int __init ima_add_boot_aggregate(void) +static int __init ima_add_boot_aggregate(struct ima_namespace *ns) { static const char op[] = "add_boot_aggregate"; const char *audit_cause = "ENOMEM"; @@ -86,7 +86,7 @@ static int __init ima_add_boot_aggregate(void) goto err_out; } - result = ima_store_template(entry, violation, NULL, + result = ima_store_template(ns, entry, violation, NULL, boot_aggregate_name, CONFIG_IMA_MEASURE_PCR_IDX); if (result < 0) { @@ -145,7 +145,8 @@ int __init ima_init(void) rc = ima_init_digests(); if (rc != 0) return rc; - rc = ima_add_boot_aggregate(); /* boot aggregate must be first entry */ + /* boot aggregate must be first entry */ + rc = ima_add_boot_aggregate(&init_ima_ns); if (rc != 0) return rc; diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c index ae33621c3955..1945fa8cfc4d 100644 --- a/security/integrity/ima/ima_init_ima_ns.c +++ b/security/integrity/ima/ima_init_ima_ns.c @@ -17,6 +17,10 @@ static int ima_init_namespace(struct ima_namespace *ns) ns->ima_policy_flag = 0; ns->arch_policy_entry = NULL; + atomic_long_set(&ns->ima_htable.len, 0); + atomic_long_set(&ns->ima_htable.violations, 0); + memset(&ns->ima_htable.queue, 0, sizeof(ns->ima_htable.queue)); + return 0; } diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index f799cc278a9a..f3ef8a0df992 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -146,7 +146,8 @@ void ima_load_kexec_buffer(void) rc = ima_get_kexec_buffer(&kexec_buffer, &kexec_buffer_size); switch (rc) { case 0: - rc = ima_restore_measurement_list(kexec_buffer_size, + rc = ima_restore_measurement_list(&init_ima_ns, + kexec_buffer_size, kexec_buffer); if (rc != 0) pr_err("Failed to restore the measurement list: %d\n", diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 4940f8dda580..2cd5cc90ab79 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -112,7 +112,8 @@ static int mmap_violation_check(enum ima_hooks func, struct file *file, * could result in a file measurement error. * */ -static void ima_rdwr_violation_check(struct file *file, +static void ima_rdwr_violation_check(struct ima_namespace *ns, + struct file *file, struct integrity_iint_cache *iint, int must_measure, char **pathbuf, @@ -145,10 +146,10 @@ static void ima_rdwr_violation_check(struct file *file, *pathname = ima_d_path(&file->f_path, pathbuf, filename); if (send_tomtou) - ima_add_violation(file, *pathname, iint, + ima_add_violation(ns, file, *pathname, iint, "invalid_pcr", "ToMToU"); if (send_writers) - ima_add_violation(file, *pathname, iint, + ima_add_violation(ns, file, *pathname, iint, "invalid_pcr", "open_writers"); } @@ -249,7 +250,7 @@ static int process_measurement(struct ima_namespace *ns, } if (!rc && violation_check) - ima_rdwr_violation_check(file, iint, action & IMA_MEASURE, + ima_rdwr_violation_check(ns, file, iint, action & IMA_MEASURE, &pathbuf, &pathname, filename); inode_unlock(inode); @@ -344,7 +345,7 @@ static int process_measurement(struct ima_namespace *ns, pathname = ima_d_path(&file->f_path, &pathbuf, filename); if (action & IMA_MEASURE) - ima_store_measurement(iint, file, pathname, + ima_store_measurement(ns, iint, file, pathname, xattr_value, xattr_len, modsig, pcr, template_desc); if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) { @@ -970,7 +971,8 @@ int process_buffer_measurement(struct ima_namespace *ns, goto out; } - ret = ima_store_template(entry, violation, NULL, event_data.buf, pcr); + ret = ima_store_template(ns, entry, violation, NULL, event_data.buf, + pcr); if (ret < 0) { audit_cause = "store_entry"; ima_free_template_entry(entry); diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 532da87ce519..43961d5cd2ef 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -31,13 +31,6 @@ static unsigned long binary_runtime_size; static unsigned long binary_runtime_size = ULONG_MAX; #endif -/* key: inode (before secure-hashing a file) */ -struct ima_h_table ima_htable = { - .len = ATOMIC_LONG_INIT(0), - .violations = ATOMIC_LONG_INIT(0), - .queue[0 ... IMA_MEASURE_HTABLE_SIZE - 1] = HLIST_HEAD_INIT -}; - /* mutex protects atomicity of extending measurement list * and extending the TPM PCR aggregate. Since tpm_extend can take * long (and the tpm driver uses a mutex), we can't use the spinlock. @@ -45,8 +38,10 @@ struct ima_h_table ima_htable = { static DEFINE_MUTEX(ima_extend_list_mutex); /* lookup up the digest value in the hash table, and return the entry */ -static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value, - int pcr) +static struct ima_queue_entry *ima_lookup_digest_entry + (struct ima_namespace *ns, + u8 *digest_value, + int pcr) { struct ima_queue_entry *qe, *ret = NULL; unsigned int key; @@ -54,7 +49,7 @@ static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value, key = ima_hash_key(digest_value); rcu_read_lock(); - hlist_for_each_entry_rcu(qe, &ima_htable.queue[key], hnext) { + hlist_for_each_entry_rcu(qe, &ns->ima_htable.queue[key], hnext) { rc = memcmp(qe->entry->digests[ima_hash_algo_idx].digest, digest_value, hash_digest_size[ima_hash_algo]); if ((rc == 0) && (qe->entry->pcr == pcr)) { @@ -90,7 +85,8 @@ static int get_binary_runtime_size(struct ima_template_entry *entry) * * (Called with ima_extend_list_mutex held.) */ -static int ima_add_digest_entry(struct ima_template_entry *entry, +static int ima_add_digest_entry(struct ima_namespace *ns, + struct ima_template_entry *entry, bool update_htable) { struct ima_queue_entry *qe; @@ -106,10 +102,12 @@ static int ima_add_digest_entry(struct ima_template_entry *entry, INIT_LIST_HEAD(&qe->later); list_add_tail_rcu(&qe->later, &ima_measurements); - atomic_long_inc(&ima_htable.len); + atomic_long_inc(&ns->ima_htable.len); if (update_htable) { key = ima_hash_key(entry->digests[ima_hash_algo_idx].digest); - hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]); + hlist_add_head_rcu(&qe->hnext, &ns->ima_htable.queue[key]); + } else { + INIT_HLIST_NODE(&qe->hnext); } if (binary_runtime_size != ULONG_MAX) { @@ -156,7 +154,8 @@ static int ima_pcr_extend(struct tpm_digest *digests_arg, int pcr) * kexec, maintain the total memory size required for serializing the * binary_runtime_measurements. */ -int ima_add_template_entry(struct ima_template_entry *entry, int violation, +int ima_add_template_entry(struct ima_namespace *ns, + struct ima_template_entry *entry, int violation, const char *op, struct inode *inode, const unsigned char *filename) { @@ -169,14 +168,14 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, mutex_lock(&ima_extend_list_mutex); if (!violation && !IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE)) { - if (ima_lookup_digest_entry(digest, entry->pcr)) { + if (ima_lookup_digest_entry(ns, digest, entry->pcr)) { audit_cause = "hash_exists"; result = -EEXIST; goto out; } } - result = ima_add_digest_entry(entry, + result = ima_add_digest_entry(ns, entry, !IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE)); if (result < 0) { audit_cause = "ENOMEM"; @@ -201,12 +200,13 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, return result; } -int ima_restore_measurement_entry(struct ima_template_entry *entry) +int ima_restore_measurement_entry(struct ima_namespace *ns, + struct ima_template_entry *entry) { int result = 0; mutex_lock(&ima_extend_list_mutex); - result = ima_add_digest_entry(entry, 0); + result = ima_add_digest_entry(ns, entry, 0); mutex_unlock(&ima_extend_list_mutex); return result; } diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index 694560396be0..0f8aa10b56fc 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -400,7 +400,8 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc, } /* Restore the serialized binary measurement list without extending PCRs. */ -int ima_restore_measurement_list(loff_t size, void *buf) +int ima_restore_measurement_list(struct ima_namespace *ns, + loff_t size, void *buf) { char template_name[MAX_TEMPLATE_NAME_LEN]; unsigned char zero[TPM_DIGEST_SIZE] = { 0 }; @@ -516,7 +517,7 @@ int ima_restore_measurement_list(loff_t size, void *buf) entry->pcr = !ima_canonical_fmt ? *(u32 *)(hdr[HDR_PCR].data) : le32_to_cpu(*(__le32 *)(hdr[HDR_PCR].data)); - ret = ima_restore_measurement_entry(entry); + ret = ima_restore_measurement_entry(ns, entry); if (ret < 0) break; From patchwork Tue Jan 25 22:46:30 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724308 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BEE1DC4707F for ; Tue, 25 Jan 2022 22:47:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234325AbiAYWro (ORCPT ); Tue, 25 Jan 2022 17:47:44 -0500 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:21074 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S234210AbiAYWr2 (ORCPT ); Tue, 25 Jan 2022 17:47:28 -0500 Received: from pps.filterd (m0098416.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PMh5ve012443; Tue, 25 Jan 2022 22:47:02 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=5rMJ0GxI29de328bAoCs9zzKvAFzXksiJa6AwpmA9ZY=; b=bgR3A7CHI7ong+tOJcSirB7rT7lvIBx4MryWKbgcYqpzfz9lkxU/wRNfNA/QrsbQ/HwO LpIaF1kVRaIiqU3EKquxAcMEyvT/Wu5WiHEasDuPrMpiVw3P2bgea5d1ze7S7Psp9xVV ezoFa1ctiA9CvKFV7r6O1ajEpmJ3HUiC+rH3oybCaoj56cm3g0q+obtw8xFfMikgRVDS TDcBdttXkT+tToHQVevnPW7Klf0FYCMjbvwTuzZglPIYt/XMDyQckNYRAK9n3bBo0ohK vUOVFvpfCpx4CrT8cXCybS0PFMKtK1N63Fif1KBoplt1X1BmP1u2cUa7FggPv+/qi0zo PA== Received: from pps.reinject (localhost [127.0.0.1]) by mx0b-001b2d01.pphosted.com with ESMTP id 3dtt83g1uc-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:01 +0000 Received: from m0098416.ppops.net (m0098416.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMiC28014835; Tue, 25 Jan 2022 22:47:01 GMT Received: from ppma02wdc.us.ibm.com (aa.5b.37a9.ip4.static.sl-reverse.com [169.55.91.170]) by mx0b-001b2d01.pphosted.com with ESMTP id 3dtt83g1u1-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:01 +0000 Received: from pps.filterd (ppma02wdc.us.ibm.com [127.0.0.1]) by ppma02wdc.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMhoYW025050; Tue, 25 Jan 2022 22:47:00 GMT Received: from b01cxnp23032.gho.pok.ibm.com (b01cxnp23032.gho.pok.ibm.com [9.57.198.27]) by ppma02wdc.us.ibm.com with ESMTP id 3dr9ja734p-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:00 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23032.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkvI031326586 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:57 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 9FE90AC066; Tue, 25 Jan 2022 22:46:57 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 823D5AC05B; Tue, 25 Jan 2022 22:46:57 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:57 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger Subject: [PATCH v9 08/23] ima: Move measurement list related variables into ima_namespace Date: Tue, 25 Jan 2022 17:46:30 -0500 Message-Id: <20220125224645.79319-9-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: s4l7mjqwyWN-QTo_UjXR3mmfbDUylEOE X-Proofpoint-GUID: obV0UJObi2441BolYMM9ToBQX7gYUj1V X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_06,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 mlxscore=0 phishscore=0 lowpriorityscore=0 spamscore=0 malwarescore=0 adultscore=0 priorityscore=1501 clxscore=1015 bulkscore=0 impostorscore=0 mlxlogscore=999 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger Move measurement list related variables into the ima_namespace. This way a front-end like securityfs can show the measurement list inside an IMA namespace. Signed-off-by: Stefan Berger --- security/integrity/ima/ima.h | 5 +++-- security/integrity/ima/ima_fs.c | 6 ++++-- security/integrity/ima/ima_init_ima_ns.c | 5 +++++ security/integrity/ima/ima_kexec.c | 12 ++++++----- security/integrity/ima/ima_queue.c | 27 +++++++++++------------- 5 files changed, 31 insertions(+), 24 deletions(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 340a59174670..45706836a77b 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -106,7 +106,6 @@ struct ima_queue_entry { struct list_head later; /* place in ima_measurements list */ struct ima_template_entry *entry; }; -extern struct list_head ima_measurements; /* list of all measurements */ /* Some details preceding the binary serialized measurement list */ struct ima_kexec_hdr { @@ -136,6 +135,8 @@ struct ima_namespace { struct ima_rule_entry *arch_policy_entry; struct ima_h_table ima_htable; + struct list_head ima_measurements; /* list of all measurements */ + unsigned long binary_runtime_size; /* used by init_ima_ns */ } __randomize_layout; extern struct ima_namespace init_ima_ns; @@ -186,7 +187,7 @@ int ima_restore_measurement_entry(struct ima_namespace *ns, int ima_restore_measurement_list(struct ima_namespace *ns, loff_t bufsize, void *buf); int ima_measurements_show(struct seq_file *m, void *v); -unsigned long ima_get_binary_runtime_size(void); +unsigned long ima_get_binary_runtime_size(struct ima_namespace *ns); int ima_init_template(void); void ima_init_template_list(void); int __init ima_init_digests(void); diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 9b4dce57c1a6..b2f088dd8572 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -80,12 +80,13 @@ static const struct file_operations ima_measurements_count_ops = { /* returns pointer to hlist_node */ static void *ima_measurements_start(struct seq_file *m, loff_t *pos) { + struct ima_namespace *ns = &init_ima_ns; loff_t l = *pos; struct ima_queue_entry *qe; /* we need a lock since pos could point beyond last element */ rcu_read_lock(); - list_for_each_entry_rcu(qe, &ima_measurements, later) { + list_for_each_entry_rcu(qe, &ns->ima_measurements, later) { if (!l--) { rcu_read_unlock(); return qe; @@ -97,6 +98,7 @@ static void *ima_measurements_start(struct seq_file *m, loff_t *pos) static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos) { + struct ima_namespace *ns = &init_ima_ns; struct ima_queue_entry *qe = v; /* lock protects when reading beyond last element @@ -107,7 +109,7 @@ static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos) rcu_read_unlock(); (*pos)++; - return (&qe->later == &ima_measurements) ? NULL : qe; + return (&qe->later == &ns->ima_measurements) ? NULL : qe; } static void ima_measurements_stop(struct seq_file *m, void *v) diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c index 1945fa8cfc4d..a7477072c587 100644 --- a/security/integrity/ima/ima_init_ima_ns.c +++ b/security/integrity/ima/ima_init_ima_ns.c @@ -20,6 +20,11 @@ static int ima_init_namespace(struct ima_namespace *ns) atomic_long_set(&ns->ima_htable.len, 0); atomic_long_set(&ns->ima_htable.violations, 0); memset(&ns->ima_htable.queue, 0, sizeof(ns->ima_htable.queue)); + INIT_LIST_HEAD(&ns->ima_measurements); + if (IS_ENABLED(CONFIG_IMA_KEXEC) && ns == &init_ima_ns) + ns->binary_runtime_size = 0; + else + ns->binary_runtime_size = ULONG_MAX; return 0; } diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index f3ef8a0df992..e83b18492f46 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -15,7 +15,8 @@ #include "ima.h" #ifdef CONFIG_IMA_KEXEC -static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer, +static int ima_dump_measurement_list(struct ima_namespace *ns, + unsigned long *buffer_size, void **buffer, unsigned long segment_size) { struct ima_queue_entry *qe; @@ -36,7 +37,7 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer, memset(&khdr, 0, sizeof(khdr)); khdr.version = 1; - list_for_each_entry_rcu(qe, &ima_measurements, later) { + list_for_each_entry_rcu(qe, &ns->ima_measurements, later) { if (file.count < file.size) { khdr.count++; ima_measurements_show(&file, qe); @@ -84,6 +85,7 @@ void ima_add_kexec_buffer(struct kimage *image) struct kexec_buf kbuf = { .image = image, .buf_align = PAGE_SIZE, .buf_min = 0, .buf_max = ULONG_MAX, .top_down = true }; + struct ima_namespace *ns = &init_ima_ns; unsigned long binary_runtime_size; /* use more understandable variable names than defined in kbuf */ @@ -96,11 +98,11 @@ void ima_add_kexec_buffer(struct kimage *image) * Reserve an extra half page of memory for additional measurements * added during the kexec load. */ - binary_runtime_size = ima_get_binary_runtime_size(); + binary_runtime_size = ima_get_binary_runtime_size(ns); if (binary_runtime_size >= ULONG_MAX - PAGE_SIZE) kexec_segment_size = ULONG_MAX; else - kexec_segment_size = ALIGN(ima_get_binary_runtime_size() + + kexec_segment_size = ALIGN(ima_get_binary_runtime_size(ns) + PAGE_SIZE / 2, PAGE_SIZE); if ((kexec_segment_size == ULONG_MAX) || ((kexec_segment_size >> PAGE_SHIFT) > totalram_pages() / 2)) { @@ -108,7 +110,7 @@ void ima_add_kexec_buffer(struct kimage *image) return; } - ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer, + ima_dump_measurement_list(ns, &kexec_buffer_size, &kexec_buffer, kexec_segment_size); if (!kexec_buffer) { pr_err("Not enough memory for the kexec measurement buffer.\n"); diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 43961d5cd2ef..0355c2b0932c 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -24,13 +24,6 @@ /* pre-allocated array of tpm_digest structures to extend a PCR */ static struct tpm_digest *digests; -LIST_HEAD(ima_measurements); /* list of all measurements */ -#ifdef CONFIG_IMA_KEXEC -static unsigned long binary_runtime_size; -#else -static unsigned long binary_runtime_size = ULONG_MAX; -#endif - /* mutex protects atomicity of extending measurement list * and extending the TPM PCR aggregate. Since tpm_extend can take * long (and the tpm driver uses a mutex), we can't use the spinlock. @@ -100,7 +93,7 @@ static int ima_add_digest_entry(struct ima_namespace *ns, qe->entry = entry; INIT_LIST_HEAD(&qe->later); - list_add_tail_rcu(&qe->later, &ima_measurements); + list_add_tail_rcu(&qe->later, &ns->ima_measurements); atomic_long_inc(&ns->ima_htable.len); if (update_htable) { @@ -110,12 +103,14 @@ static int ima_add_digest_entry(struct ima_namespace *ns, INIT_HLIST_NODE(&qe->hnext); } - if (binary_runtime_size != ULONG_MAX) { + if (ns->binary_runtime_size != ULONG_MAX) { int size; size = get_binary_runtime_size(entry); - binary_runtime_size = (binary_runtime_size < ULONG_MAX - size) ? - binary_runtime_size + size : ULONG_MAX; + ns->binary_runtime_size = + (ns->binary_runtime_size < ULONG_MAX - size) + ? ns->binary_runtime_size + size + : ULONG_MAX; } return 0; } @@ -123,14 +118,16 @@ static int ima_add_digest_entry(struct ima_namespace *ns, /* * Return the amount of memory required for serializing the * entire binary_runtime_measurement list, including the ima_kexec_hdr - * structure. + * structure. Carrying the measurement list across kexec is limited + * to init_ima_ns. */ -unsigned long ima_get_binary_runtime_size(void) +unsigned long ima_get_binary_runtime_size(struct ima_namespace *ns) { - if (binary_runtime_size >= (ULONG_MAX - sizeof(struct ima_kexec_hdr))) + if (ns->binary_runtime_size >= + (ULONG_MAX - sizeof(struct ima_kexec_hdr))) return ULONG_MAX; else - return binary_runtime_size + sizeof(struct ima_kexec_hdr); + return ns->binary_runtime_size + sizeof(struct ima_kexec_hdr); } static int ima_pcr_extend(struct tpm_digest *digests_arg, int pcr) From patchwork Tue Jan 25 22:46:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724353 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 84803C63684 for ; Tue, 25 Jan 2022 23:09:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234316AbiAYWro (ORCPT ); Tue, 25 Jan 2022 17:47:44 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:30220 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234219AbiAYWr2 (ORCPT ); Tue, 25 Jan 2022 17:47:28 -0500 Received: from pps.filterd (m0098404.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PMCFjn031541; Tue, 25 Jan 2022 22:47:10 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=qN7ROB+dCkHt4DyWhBGf/JfsT4Ulk+ro/0WEu/nlB7I=; b=lHTSBm7ia7yo9LwKgwHCmMFsjA4e3psIhFW1bknSN2KX/momhN9qZS9W6LACrTjSV6Qr TlFJK33Ggxd6diPks+OtX2Aj43xbsRHG8mUnQFDYuUoEP+Mh7opJmjVGsVs+l/easB20 yJMoEYxaNwVs5aetdgeohvYrF5grENb3xhbMccKIxTevqgCpY9bMuOwrS0GYpmYhfeR4 jSG0L2yQnu8c+Uk36UtXQ/UU9B18wOvh2vW3Ecp655KG/6tYeNHADLJ7uin0qiF2NBOH nIndN9UWg2XQkklxgKISn9Yr+YT7wtdl5rB1QxPWjP1fdQLmvK5SKxkaoanAoTSQtopt sw== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtssp0hxn-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:09 +0000 Received: from m0098404.ppops.net (m0098404.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMl9S5030806; Tue, 25 Jan 2022 22:47:09 GMT Received: from ppma03dal.us.ibm.com (b.bd.3ea9.ip4.static.sl-reverse.com [169.62.189.11]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtssp0hxa-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:09 +0000 Received: from pps.filterd (ppma03dal.us.ibm.com [127.0.0.1]) by ppma03dal.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMhmwN006709; Tue, 25 Jan 2022 22:47:08 GMT Received: from b01cxnp23032.gho.pok.ibm.com (b01cxnp23032.gho.pok.ibm.com [9.57.198.27]) by ppma03dal.us.ibm.com with ESMTP id 3dr9jb6e8h-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:07 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23032.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkv1x24838494 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:57 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id B73A8AC065; Tue, 25 Jan 2022 22:46:57 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id A4DB6AC05F; Tue, 25 Jan 2022 22:46:57 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:57 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger Subject: [PATCH v9 09/23] ima: Move some IMA policy and filesystem related variables into ima_namespace Date: Tue, 25 Jan 2022 17:46:31 -0500 Message-Id: <20220125224645.79319-10-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: oTaaRR4NrTIhT5CgQz5-0bcb72rlxWL4 X-Proofpoint-ORIG-GUID: gBr-j7UcbY1KMv7FqyjKi9BsZgmndXsW X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_05,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 bulkscore=0 phishscore=0 adultscore=0 malwarescore=0 suspectscore=0 spamscore=0 mlxscore=0 mlxlogscore=999 impostorscore=0 clxscore=1015 priorityscore=1501 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger Move the ima_write_mutex, ima_fs_flag, and valid_policy variables into ima_namespace. This way each IMA namespace can set those variables independently. Signed-off-by: Stefan Berger Acked-by: Christian Brauner --- security/integrity/ima/ima.h | 5 ++++ security/integrity/ima/ima_fs.c | 32 +++++++++++------------- security/integrity/ima/ima_init_ima_ns.c | 4 +++ 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 45706836a77b..1092c926daf9 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -137,6 +137,11 @@ struct ima_namespace { struct ima_h_table ima_htable; struct list_head ima_measurements; /* list of all measurements */ unsigned long binary_runtime_size; /* used by init_ima_ns */ + + /* securityfs support related variables */ + struct mutex ima_write_mutex; + unsigned long ima_fs_flags; + int valid_policy; } __randomize_layout; extern struct ima_namespace init_ima_ns; diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index b2f088dd8572..34132cc7de4d 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -24,8 +24,6 @@ #include "ima.h" -static DEFINE_MUTEX(ima_write_mutex); - bool ima_canonical_fmt; static int __init default_canonical_fmt_setup(char *str) { @@ -36,8 +34,6 @@ static int __init default_canonical_fmt_setup(char *str) } __setup("ima_canonical_fmt", default_canonical_fmt_setup); -static int valid_policy = 1; - static ssize_t ima_show_htable_value(char __user *buf, size_t count, loff_t *ppos, atomic_long_t *val) { @@ -338,7 +334,7 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf, goto out; } - result = mutex_lock_interruptible(&ima_write_mutex); + result = mutex_lock_interruptible(&ns->ima_write_mutex); if (result < 0) goto out_free; @@ -353,12 +349,12 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf, } else { result = ima_parse_add_rule(ns, data); } - mutex_unlock(&ima_write_mutex); + mutex_unlock(&ns->ima_write_mutex); out_free: kfree(data); out: if (result < 0) - valid_policy = 0; + ns->valid_policy = 0; return result; } @@ -375,8 +371,6 @@ enum ima_fs_flags { IMA_FS_BUSY, }; -static unsigned long ima_fs_flags; - #ifdef CONFIG_IMA_READ_POLICY static const struct seq_operations ima_policy_seqops = { .start = ima_policy_start, @@ -391,6 +385,8 @@ static const struct seq_operations ima_policy_seqops = { */ static int ima_open_policy(struct inode *inode, struct file *filp) { + struct ima_namespace *ns = &init_ima_ns; + if (!(filp->f_flags & O_WRONLY)) { #ifndef CONFIG_IMA_READ_POLICY return -EACCES; @@ -402,7 +398,7 @@ static int ima_open_policy(struct inode *inode, struct file *filp) return seq_open(filp, &ima_policy_seqops); #endif } - if (test_and_set_bit(IMA_FS_BUSY, &ima_fs_flags)) + if (test_and_set_bit(IMA_FS_BUSY, &ns->ima_fs_flags)) return -EBUSY; return 0; } @@ -416,25 +412,25 @@ static int ima_open_policy(struct inode *inode, struct file *filp) */ static int ima_release_policy(struct inode *inode, struct file *file) { - const char *cause = valid_policy ? "completed" : "failed"; struct ima_namespace *ns = &init_ima_ns; + const char *cause = ns->valid_policy ? "completed" : "failed"; if ((file->f_flags & O_ACCMODE) == O_RDONLY) return seq_release(inode, file); - if (valid_policy && ima_check_policy(ns) < 0) { + if (ns->valid_policy && ima_check_policy(ns) < 0) { cause = "failed"; - valid_policy = 0; + ns->valid_policy = 0; } pr_info("policy update %s\n", cause); integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, - "policy_update", cause, !valid_policy, 0); + "policy_update", cause, !ns->valid_policy, 0); - if (!valid_policy) { + if (!ns->valid_policy) { ima_delete_rules(ns); - valid_policy = 1; - clear_bit(IMA_FS_BUSY, &ima_fs_flags); + ns->valid_policy = 1; + clear_bit(IMA_FS_BUSY, &ns->ima_fs_flags); return 0; } @@ -443,7 +439,7 @@ static int ima_release_policy(struct inode *inode, struct file *file) securityfs_remove(ima_policy); ima_policy = NULL; #elif defined(CONFIG_IMA_WRITE_POLICY) - clear_bit(IMA_FS_BUSY, &ima_fs_flags); + clear_bit(IMA_FS_BUSY, &ns->ima_fs_flags); #elif defined(CONFIG_IMA_READ_POLICY) inode->i_mode &= ~S_IWUSR; #endif diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c index a7477072c587..425eed1c6838 100644 --- a/security/integrity/ima/ima_init_ima_ns.c +++ b/security/integrity/ima/ima_init_ima_ns.c @@ -26,6 +26,10 @@ static int ima_init_namespace(struct ima_namespace *ns) else ns->binary_runtime_size = ULONG_MAX; + mutex_init(&ns->ima_write_mutex); + ns->valid_policy = 1; + ns->ima_fs_flags = 0; + return 0; } From patchwork Tue Jan 25 22:46:32 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724310 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3D747C47080 for ; Tue, 25 Jan 2022 22:47:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234338AbiAYWrq (ORCPT ); Tue, 25 Jan 2022 17:47:46 -0500 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:9226 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S234207AbiAYWr2 (ORCPT ); Tue, 25 Jan 2022 17:47:28 -0500 Received: from pps.filterd (m0098416.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PMh9ZN012492; Tue, 25 Jan 2022 22:47:01 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=niLp33XDMnRnMqOmIlJPPSSqYe7CnBuWCnNKRRUYlqw=; b=eWG7CzRSjlAq/kL+QMZCUteORGGp8lRbirjKZpED454fED4IRrtRvlfLifQU/zCCr+YV /dcCssn/vugQTTERDqICeZ674rS+j7QiF4SsxK+u4NN/ll46cowwLEx/fAEd9k2CAhOe 4m/3armbKoOYTvfqro1Le2EvBaPiPg6oAVAE2D9ZXjT8wB+6g9dMkzlXUA8auxIfEnyt m/NEbnNayzBxfKdscfp6j0pi0ik/19yolAy94OxgMIbAmmKSfr+V/wshcGHIL4OQemvT gGHAoa4WyuVoPxsZU2O7/NhMf5YEdlhDRPwZEs5ZPiTN+5ywZurKryvTy+eyG1yZzXO/ Dw== Received: from pps.reinject (localhost [127.0.0.1]) by mx0b-001b2d01.pphosted.com with ESMTP id 3dtt83g1tx-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:01 +0000 Received: from m0098416.ppops.net (m0098416.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMi5am014684; Tue, 25 Jan 2022 22:47:00 GMT Received: from ppma04wdc.us.ibm.com (1a.90.2fa9.ip4.static.sl-reverse.com [169.47.144.26]) by mx0b-001b2d01.pphosted.com with ESMTP id 3dtt83g1tp-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:00 +0000 Received: from pps.filterd (ppma04wdc.us.ibm.com [127.0.0.1]) by ppma04wdc.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMhSuU005128; Tue, 25 Jan 2022 22:46:59 GMT Received: from b01cxnp23032.gho.pok.ibm.com (b01cxnp23032.gho.pok.ibm.com [9.57.198.27]) by ppma04wdc.us.ibm.com with ESMTP id 3dr9jaq509-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:46:59 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23032.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkwj133292650 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:58 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id E2021AC064; Tue, 25 Jan 2022 22:46:57 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C58E5AC067; Tue, 25 Jan 2022 22:46:57 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:57 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger Subject: [PATCH v9 10/23] ima: Move IMA securityfs files into ima_namespace or onto stack Date: Tue, 25 Jan 2022 17:46:32 -0500 Message-Id: <20220125224645.79319-11-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: SYJ0f_6iovLxeo-Frg4OxvF8TbYc9u4Z X-Proofpoint-GUID: 1p4hPL4uQauATAp4sdORQ8WEGftXnPGF X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_06,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 mlxscore=0 phishscore=0 lowpriorityscore=0 spamscore=0 malwarescore=0 adultscore=0 priorityscore=1501 clxscore=1015 bulkscore=0 impostorscore=0 mlxlogscore=999 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger Only the securityfs IMA policy file is ever removed based on Kconfig options. For this reason, move the IMA securityfs policy file variable 'ima_policy' into the ima_namespace. Move the other IMA securityfs files onto the stack since they are not needed outside the function where they are created in. Also, their cleanup is automatically handled by the filesystem upon umount of a virtualized securityfs instance, so they don't need to be explicitly freed. In the failure cleanup path clean up the ima_policy dentry before cleaning up the directories. Signed-off-by: Stefan Berger Acked-by: Christian Brauner --- v9: - Revert renaming of ima_policy to policy_dentry --- security/integrity/ima/ima.h | 2 ++ security/integrity/ima/ima_fs.c | 36 ++++++++++++++++++--------------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 1092c926daf9..94c6e3a4d666 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -142,6 +142,8 @@ struct ima_namespace { struct mutex ima_write_mutex; unsigned long ima_fs_flags; int valid_policy; + + struct dentry *ima_policy; } __randomize_layout; extern struct ima_namespace init_ima_ns; diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 34132cc7de4d..3afb7a74d2cf 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -359,14 +359,6 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf, return result; } -static struct dentry *ima_dir; -static struct dentry *ima_symlink; -static struct dentry *binary_runtime_measurements; -static struct dentry *ascii_runtime_measurements; -static struct dentry *runtime_measurements_count; -static struct dentry *violations; -static struct dentry *ima_policy; - enum ima_fs_flags { IMA_FS_BUSY, }; @@ -436,8 +428,8 @@ static int ima_release_policy(struct inode *inode, struct file *file) ima_update_policy(ns); #if !defined(CONFIG_IMA_WRITE_POLICY) && !defined(CONFIG_IMA_READ_POLICY) - securityfs_remove(ima_policy); - ima_policy = NULL; + securityfs_remove(ns->ima_policy); + ns->ima_policy = NULL; #elif defined(CONFIG_IMA_WRITE_POLICY) clear_bit(IMA_FS_BUSY, &ns->ima_fs_flags); #elif defined(CONFIG_IMA_READ_POLICY) @@ -454,8 +446,15 @@ static const struct file_operations ima_measure_policy_ops = { .llseek = generic_file_llseek, }; -int __init ima_fs_init(void) +static int __init ima_fs_ns_init(struct ima_namespace *ns) { + struct dentry *ima_dir; + struct dentry *ima_symlink = NULL; + struct dentry *binary_runtime_measurements = NULL; + struct dentry *ascii_runtime_measurements = NULL; + struct dentry *runtime_measurements_count = NULL; + struct dentry *violations = NULL; + ima_dir = securityfs_create_dir("ima", integrity_dir); if (IS_ERR(ima_dir)) return -1; @@ -492,15 +491,15 @@ int __init ima_fs_init(void) if (IS_ERR(violations)) goto out; - ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS, - ima_dir, NULL, - &ima_measure_policy_ops); - if (IS_ERR(ima_policy)) + ns->ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS, + ima_dir, NULL, + &ima_measure_policy_ops); + if (IS_ERR(ns->ima_policy)) goto out; return 0; out: - securityfs_remove(ima_policy); + securityfs_remove(ns->ima_policy); securityfs_remove(violations); securityfs_remove(runtime_measurements_count); securityfs_remove(ascii_runtime_measurements); @@ -509,3 +508,8 @@ int __init ima_fs_init(void) securityfs_remove(ima_dir); return -1; } + +int __init ima_fs_init(void) +{ + return ima_fs_ns_init(&init_ima_ns); +} From patchwork Tue Jan 25 22:46:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724296 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B7966C433FE for ; Tue, 25 Jan 2022 22:47:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234173AbiAYWrf (ORCPT ); Tue, 25 Jan 2022 17:47:35 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:59298 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234194AbiAYWrZ (ORCPT ); Tue, 25 Jan 2022 17:47:25 -0500 Received: from pps.filterd (m0098410.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PMkZMY004365; Tue, 25 Jan 2022 22:47:07 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=9DMyReKh9yvG9YiRlcnDMSlffJv01Ff61I2J36cK/E8=; b=LcN1e5ms9UIMnxxVDQxIWglai0WtlKsV0/NWueYRAqM+T5nZzuJb8ithQd191B3al74S FIXPleh3fXGolXMx9yFblajFxiamjp6APX0iOKHGVYz5W4y5nSX8GDqzuRcu8RVKTfcY OrRN2O5pCldiHg6eatB17SGWEiIPYnBVlUGVW03z/nfSzh8LVuZkqAKhSvB4DeToOd25 MWe4gLV7IBXys1Gwrg10jtzLyV/V7xl2NwZoz5B0nbJ5yhA8XWFwShuI9BMmxy8KMG0I eb0mPKci6yGoiKcUDedGeVMzh7uk50AmNjGTeS0oMbADotBbNtCAHgdy+98hkp3yPn7j Jg== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtta2008v-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:07 +0000 Received: from m0098410.ppops.net (m0098410.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMl7GN005609; Tue, 25 Jan 2022 22:47:07 GMT Received: from ppma03wdc.us.ibm.com (ba.79.3fa9.ip4.static.sl-reverse.com [169.63.121.186]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtta2008e-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:07 +0000 Received: from pps.filterd (ppma03wdc.us.ibm.com [127.0.0.1]) by ppma03wdc.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMhbfL016423; Tue, 25 Jan 2022 22:47:05 GMT Received: from b01cxnp23033.gho.pok.ibm.com (b01cxnp23033.gho.pok.ibm.com [9.57.198.28]) by ppma03wdc.us.ibm.com with ESMTP id 3dr9jaf1fb-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:05 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23033.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkwr342860872 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:58 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 0E451AC05B; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id E6845AC066; Tue, 25 Jan 2022 22:46:57 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:57 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger Subject: [PATCH v9 11/23] ima: Move ima_lsm_policy_notifier into ima_namespace Date: Tue, 25 Jan 2022 17:46:33 -0500 Message-Id: <20220125224645.79319-12-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: 7mT2gZPXhBkhpAlMYR_msfXbKHCu9Cbb X-Proofpoint-ORIG-GUID: lM3RwWPWIJud2bZ-fedeNn1j0gKTGG6A X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_05,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 mlxscore=0 malwarescore=0 impostorscore=0 phishscore=0 bulkscore=0 suspectscore=0 adultscore=0 mlxlogscore=999 lowpriorityscore=0 priorityscore=1501 clxscore=1015 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger Move the ima_lsm_policy_notifier into the ima_namespace. Each IMA namespace can now register its own LSM policy change notifier callback. The policy change notifier for the init_ima_ns still remains in init_ima() and therefore handle the registration of the callback for all other namespaces in init_ima_namespace(). Signed-off-by: Stefan Berger --- security/integrity/ima/ima.h | 2 ++ security/integrity/ima/ima_init_ima_ns.c | 14 ++++++++++++++ security/integrity/ima/ima_main.c | 6 +----- security/integrity/ima/ima_policy.c | 4 +++- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 94c6e3a4d666..fb6bd054d899 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -144,6 +144,8 @@ struct ima_namespace { int valid_policy; struct dentry *ima_policy; + + struct notifier_block ima_lsm_policy_notifier; } __randomize_layout; extern struct ima_namespace init_ima_ns; diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c index 425eed1c6838..1cba545ae477 100644 --- a/security/integrity/ima/ima_init_ima_ns.c +++ b/security/integrity/ima/ima_init_ima_ns.c @@ -10,6 +10,8 @@ static int ima_init_namespace(struct ima_namespace *ns) { + int rc; + INIT_LIST_HEAD(&ns->ima_default_rules); INIT_LIST_HEAD(&ns->ima_policy_rules); INIT_LIST_HEAD(&ns->ima_temp_rules); @@ -30,6 +32,15 @@ static int ima_init_namespace(struct ima_namespace *ns) ns->valid_policy = 1; ns->ima_fs_flags = 0; + if (ns != &init_ima_ns) { + ns->ima_lsm_policy_notifier.notifier_call = + ima_lsm_policy_change; + rc = register_blocking_lsm_notifier + (&ns->ima_lsm_policy_notifier); + if (rc) + return rc; + } + return 0; } @@ -39,5 +50,8 @@ int __init ima_ns_init(void) } struct ima_namespace init_ima_ns = { + .ima_lsm_policy_notifier = { + .notifier_call = ima_lsm_policy_change, + }, }; EXPORT_SYMBOL(init_ima_ns); diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 2cd5cc90ab79..ae0e9b14554a 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -38,10 +38,6 @@ int ima_appraise; int __ro_after_init ima_hash_algo = HASH_ALGO_SHA1; static int hash_setup_done; -static struct notifier_block ima_lsm_policy_notifier = { - .notifier_call = ima_lsm_policy_change, -}; - static int __init hash_setup(char *str) { struct ima_template_desc *template_desc = ima_template_desc_current(); @@ -1072,7 +1068,7 @@ static int __init init_ima(void) if (error) return error; - error = register_blocking_lsm_notifier(&ima_lsm_policy_notifier); + error = register_blocking_lsm_notifier(&ns->ima_lsm_policy_notifier); if (error) pr_warn("Couldn't register LSM notifier, error %d\n", error); diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 05b2bc06ab0c..3b754b9f5ef7 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -465,12 +465,14 @@ static void ima_lsm_update_rules(struct ima_namespace *ns) int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event, void *lsm_data) { - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns; if (event != LSM_POLICY_CHANGE) return NOTIFY_DONE; + ns = container_of(nb, struct ima_namespace, ima_lsm_policy_notifier); ima_lsm_update_rules(ns); + return NOTIFY_OK; } From patchwork Tue Jan 25 22:46:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724300 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 473DCC4321E for ; Tue, 25 Jan 2022 22:47:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234253AbiAYWrk (ORCPT ); Tue, 25 Jan 2022 17:47:40 -0500 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:18554 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S234225AbiAYWr3 (ORCPT ); Tue, 25 Jan 2022 17:47:29 -0500 Received: from pps.filterd (m0098413.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PLGeI3031514; Tue, 25 Jan 2022 22:47:01 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=ADg8slEUxx1nyVrfNPf7q4g1mltMrxp4uCFeeo4DNRs=; b=EO9WqZp6A2pdhIEyLbiiGhORYOJ7hvd2z9M0/3FbnEGvV7zrNn7ctfwo6lBI+8i0IHnU D2xpkCMfnq7KeQ7CPNxMS4Gu8fMPGsFKynmq/TZZ65O/CUhUlVElAkrn0E0GeMkQ6rX8 4H+/bI0n9wBD6x51SUDkJLGJmGhBL2xyc7ivmN4qmog5kOln3CYQlELTqJKzJSMiilf9 N7z/zpoNEINBTBLE6YyfXnA+I57Nq79G7olQlNUXsa0rWBiFdgi5kDv5Lk94w5qbAT2Q 42lJ87a9Q2kMdGx9p4cIiuEjbLAMcm8rnLQomTXrTUeQ6giJTFLfRutcNGgs8/HIeORh zA== Received: from pps.reinject (localhost [127.0.0.1]) by mx0b-001b2d01.pphosted.com with ESMTP id 3dtryvsftu-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:01 +0000 Received: from m0098413.ppops.net (m0098413.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMgMCl011573; Tue, 25 Jan 2022 22:47:00 GMT Received: from ppma04wdc.us.ibm.com (1a.90.2fa9.ip4.static.sl-reverse.com [169.47.144.26]) by mx0b-001b2d01.pphosted.com with ESMTP id 3dtryvsftq-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:00 +0000 Received: from pps.filterd (ppma04wdc.us.ibm.com [127.0.0.1]) by ppma04wdc.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMhSdR005118; Tue, 25 Jan 2022 22:47:00 GMT Received: from b01cxnp23033.gho.pok.ibm.com (b01cxnp23033.gho.pok.ibm.com [9.57.198.28]) by ppma04wdc.us.ibm.com with ESMTP id 3dr9jaq50h-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:00 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23033.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkwVN39256494 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:58 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 261BCAC066; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 13524AC067; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger , Denis Semakin Subject: [PATCH v9 12/23] ima: Define mac_admin_ns_capable() as a wrapper for ns_capable() Date: Tue, 25 Jan 2022 17:46:34 -0500 Message-Id: <20220125224645.79319-13-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: PT1s5Lw4AZsJILgU7IuyW3lVtLfcIr4S X-Proofpoint-ORIG-GUID: wrTfO28z6fwkhfY98-nG2CheCI6twWvm X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_05,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 clxscore=1015 lowpriorityscore=0 bulkscore=0 impostorscore=0 adultscore=0 malwarescore=0 priorityscore=1501 mlxlogscore=999 suspectscore=0 mlxscore=0 phishscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger Define mac_admin_ns_capable() as a wrapper for the combined ns_capable() checks on CAP_MAC_ADMIN and CAP_SYS_ADMIN in a user namespace. Return true on the check if either capability or both are available. Use mac_admin_ns_capable() in place of capable(SYS_ADMIN). This will allow an IMA namespace to read the policy with only CAP_MAC_ADMIN, which has less privileges than CAP_SYS_ADMIN. Signed-off-by: Denis Semakin Signed-off-by: Stefan Berger --- include/linux/capability.h | 6 ++++++ security/integrity/ima/ima.h | 6 ++++++ security/integrity/ima/ima_fs.c | 5 ++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/linux/capability.h b/include/linux/capability.h index 65efb74c3585..991579178f32 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -270,6 +270,12 @@ static inline bool checkpoint_restore_ns_capable(struct user_namespace *ns) ns_capable(ns, CAP_SYS_ADMIN); } +static inline bool mac_admin_ns_capable(struct user_namespace *ns) +{ + return ns_capable(ns, CAP_MAC_ADMIN) || + ns_capable(ns, CAP_SYS_ADMIN); +} + /* audit system wants to get cap info from files as well */ int get_vfs_caps_from_disk(struct user_namespace *mnt_userns, const struct dentry *dentry, diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index fb6bd054d899..0057b1fd6c18 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -487,4 +487,10 @@ static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op, #define POLICY_FILE_FLAGS S_IWUSR #endif /* CONFIG_IMA_READ_POLICY */ +static inline +struct user_namespace *ima_user_ns_from_file(const struct file *filp) +{ + return file_inode(filp)->i_sb->s_user_ns; +} + #endif /* __LINUX_IMA_H */ diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 3afb7a74d2cf..9162f06d182f 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -377,6 +377,9 @@ static const struct seq_operations ima_policy_seqops = { */ static int ima_open_policy(struct inode *inode, struct file *filp) { +#ifdef CONFIG_IMA_READ_POLICY + struct user_namespace *user_ns = ima_user_ns_from_file(filp); +#endif struct ima_namespace *ns = &init_ima_ns; if (!(filp->f_flags & O_WRONLY)) { @@ -385,7 +388,7 @@ static int ima_open_policy(struct inode *inode, struct file *filp) #else if ((filp->f_flags & O_ACCMODE) != O_RDONLY) return -EACCES; - if (!capable(CAP_SYS_ADMIN)) + if (!mac_admin_ns_capable(user_ns)) return -EPERM; return seq_open(filp, &ima_policy_seqops); #endif From patchwork Tue Jan 25 22:46:35 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724306 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E1BDBC35274 for ; Tue, 25 Jan 2022 22:47:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234329AbiAYWrp (ORCPT ); Tue, 25 Jan 2022 17:47:45 -0500 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:35654 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S234211AbiAYWr2 (ORCPT ); Tue, 25 Jan 2022 17:47:28 -0500 Received: from pps.filterd (m0098414.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PM6BvZ002670; Tue, 25 Jan 2022 22:47:02 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=M5GQfvz2hg5dXcQWST/28zSIctIm71dQ5WYSoFeXAhs=; b=VWxNOfolrB0QlqzeoUOYgEAjpZug8j/L7jbeSZ/RCHOmLJcj0DjstlzG++E8acIN6pFh OJOkIC98Hy5itm20sY9iYi/IDzFG0yALcEn9mzmPrzALn40MuSAZx+2PxAvwrQ4SHC9d 0TZ6Kfh43vToQrWbRi8dirPV3+MYV6xCZ4lvqTdTxy6LnQ8Q8FhBQHnDZZm4QAL8Hhgb 5Oo97fknf9FXlOoEgaYlBTwEcLbuENNiTaLiI8XyFK+yPE0nvBXr70mFN7W44EQKFQ1B lKfE3VdIB8f9fWCwG8nh4wMcaASGTlBX13oOogRQ2cB1s+xWYtCGa+XV3yMlq6LvK0R8 rg== Received: from pps.reinject (localhost [127.0.0.1]) by mx0b-001b2d01.pphosted.com with ESMTP id 3dtryw1cbs-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:02 +0000 Received: from m0098414.ppops.net (m0098414.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMYtBw032167; Tue, 25 Jan 2022 22:47:01 GMT Received: from ppma02dal.us.ibm.com (a.bd.3ea9.ip4.static.sl-reverse.com [169.62.189.10]) by mx0b-001b2d01.pphosted.com with ESMTP id 3dtryw1cbk-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:01 +0000 Received: from pps.filterd (ppma02dal.us.ibm.com [127.0.0.1]) by ppma02dal.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMh3Mn011257; Tue, 25 Jan 2022 22:47:00 GMT Received: from b01cxnp23033.gho.pok.ibm.com (b01cxnp23033.gho.pok.ibm.com [9.57.198.28]) by ppma02dal.us.ibm.com with ESMTP id 3dt1x9rg89-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:00 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23033.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkwwj32440780 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:58 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 5068AAC062; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 34A0DAC05E; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger Subject: [PATCH v9 13/23] ima: Only accept AUDIT rules for non-init_ima_ns namespaces for now Date: Tue, 25 Jan 2022 17:46:35 -0500 Message-Id: <20220125224645.79319-14-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: 0R-m_-LSTiCmPTt-rdxHe7bfEikHdTKu X-Proofpoint-ORIG-GUID: YZAPGAFh1pgH6Nns4KRVs7SkuIirmbZW X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_06,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxscore=0 lowpriorityscore=0 clxscore=1015 mlxlogscore=999 phishscore=0 suspectscore=0 spamscore=0 impostorscore=0 priorityscore=1501 bulkscore=0 adultscore=0 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger Only accept AUDIT rules for non-init_ima_ns namespaces rejecting all rules that require support for measuring, appraisal, and hashing. Signed-off-by: Stefan Berger Acked-by: Christian Brauner --- v9: - Jump to err_audit when unsupported rules are detected --- security/integrity/ima/ima_policy.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 3b754b9f5ef7..e8140e73d80b 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -1794,6 +1794,17 @@ static int ima_parse_rule(struct ima_namespace *ns, result = -EINVAL; break; } + + /* IMA namespace only accepts AUDIT rules */ + if (ns != &init_ima_ns && result == 0) { + switch (entry->action) { + case MEASURE: + case APPRAISE: + case HASH: + result = -EINVAL; + goto err_audit; + } + } } if (!result && !ima_validate_rule(entry)) result = -EINVAL; @@ -1806,6 +1817,7 @@ static int ima_parse_rule(struct ima_namespace *ns, check_template_modsig(template_desc); } +err_audit: audit_log_format(ab, "res=%d", !result); audit_log_end(ab); return result; From patchwork Tue Jan 25 22:46:36 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724305 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A0419C4707E for ; Tue, 25 Jan 2022 22:47:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234311AbiAYWrn (ORCPT ); Tue, 25 Jan 2022 17:47:43 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:16860 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234215AbiAYWr2 (ORCPT ); Tue, 25 Jan 2022 17:47:28 -0500 Received: from pps.filterd (m0187473.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PLfeJp031655; Tue, 25 Jan 2022 22:47:04 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=QyPScA20Bh1zljbHYtY9GeWirSRDvpTCapiCqMkxoFY=; b=ANAIlirYz6xZYP8dvVH/bzcYlMA9E7QDOP2eny5qZHxJMPipCgpWXc4MjcGu425/Q+p5 OIbkf4206QekIVLuNT74zm57DqDzUvcNho2BWz0dTALT+r4gajCqwCKFl7UIs8CaxUq1 r4HBRkuZBy+VIY2b8DaL7+LPjV17OCVDc8T/BsR2wdTY81YllfepXG5LAFe+wOmKIZCM qj5AstcJBKYlFAuEE9PLXd+a1YGi0V0xbs/juEmbvNWgVJxJ5/SdgHKp7m4tWFUSthdc 4ti1xm/v+atAeqPSPpFWa2X4ZEgICqH/sP3EB6X48VQF6p96QH3y+KuTCRNQXI6SsOn/ lg== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtsbch54a-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:03 +0000 Received: from m0187473.ppops.net (m0187473.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMX9f3037081; Tue, 25 Jan 2022 22:47:03 GMT Received: from ppma01dal.us.ibm.com (83.d6.3fa9.ip4.static.sl-reverse.com [169.63.214.131]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtsbch53y-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:03 +0000 Received: from pps.filterd (ppma01dal.us.ibm.com [127.0.0.1]) by ppma01dal.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMhbI8027114; Tue, 25 Jan 2022 22:47:02 GMT Received: from b01cxnp23033.gho.pok.ibm.com (b01cxnp23033.gho.pok.ibm.com [9.57.198.28]) by ppma01dal.us.ibm.com with ESMTP id 3dr9jb6drw-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:01 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23033.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkwQ032768426 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:58 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 6A931AC05B; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 55157AC067; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger Subject: [PATCH v9 14/23] userns: Add pointer to ima_namespace to user_namespace Date: Tue, 25 Jan 2022 17:46:36 -0500 Message-Id: <20220125224645.79319-15-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: 9eWkUen3sPqdcrE4Of2-EUpfGECFwUB3 X-Proofpoint-ORIG-GUID: 4omr4UhEtaWNOx4SMMcTypm8c0g2Bbx4 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_06,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 spamscore=0 clxscore=1015 adultscore=0 lowpriorityscore=0 mlxscore=0 phishscore=0 mlxlogscore=999 suspectscore=0 impostorscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger Add a pointer to ima_namespace to the user_namespace and initialize the init_user_ns with a pointer to init_ima_ns. Signed-off-by: Stefan Berger Acked-by: Christian Brauner --- v9: - Deferred implementation of ima_ns_from_user_ns() to later patch --- include/linux/ima.h | 2 ++ include/linux/user_namespace.h | 4 ++++ kernel/user.c | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/include/linux/ima.h b/include/linux/ima.h index b6ab66a546ae..0cf2a80c8b35 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -14,6 +14,8 @@ #include struct linux_binprm; +extern struct ima_namespace init_ima_ns; + #ifdef CONFIG_IMA extern enum hash_algo ima_get_current_hash_algo(void); extern int ima_bprm_check(struct linux_binprm *bprm); diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index 33a4240e6a6f..019e8cf7b633 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -36,6 +36,7 @@ struct uid_gid_map { /* 64 bytes -- 1 cache line */ #define USERNS_INIT_FLAGS USERNS_SETGROUPS_ALLOWED struct ucounts; +struct ima_namespace; enum ucount_type { UCOUNT_USER_NAMESPACES, @@ -99,6 +100,9 @@ struct user_namespace { #endif struct ucounts *ucounts; long ucount_max[UCOUNT_COUNTS]; +#ifdef CONFIG_IMA_NS + struct ima_namespace *ima_ns; +#endif } __randomize_layout; struct ucounts { diff --git a/kernel/user.c b/kernel/user.c index e2cf8c22b539..e5d1f4b9b8ba 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -19,6 +19,7 @@ #include #include #include +#include /* * userns count is 1 for root user, 1 for init_uts_ns, @@ -67,6 +68,9 @@ struct user_namespace init_user_ns = { .keyring_name_list = LIST_HEAD_INIT(init_user_ns.keyring_name_list), .keyring_sem = __RWSEM_INITIALIZER(init_user_ns.keyring_sem), #endif +#ifdef CONFIG_IMA_NS + .ima_ns = &init_ima_ns, +#endif }; EXPORT_SYMBOL_GPL(init_user_ns); From patchwork Tue Jan 25 22:46:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724292 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3D3C6C433FE for ; Tue, 25 Jan 2022 22:47:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234128AbiAYWrc (ORCPT ); Tue, 25 Jan 2022 17:47:32 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:62964 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234203AbiAYWr0 (ORCPT ); Tue, 25 Jan 2022 17:47:26 -0500 Received: from pps.filterd (m0098409.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PMfiYg010964; Tue, 25 Jan 2022 22:47:03 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=SFcFD/EvTQUoNcYyKVdfg6JmVIDdzQPCJOH1FaaGd5g=; b=p4Yf+StFEY8xsu172qvPCKqPPx3DTnpJYE410WsrLrNOVCqzJke/19Xp+WFWobP6IhBV ab1xr1+60gqMY49IGFRCY1K/RY/6THPyhPUuK/TVT3oAzEu7Tr/9uABXauvNlnforeky K4AwI5C/nRTdb+HN38ECoaZbMSFreAy5RybIOWqEZ99Ko9LzVCnyd2gnGX7L/hXN39bM 1gR4SmwT28q4FvW2jawswMv+j8KABou0hWsu5f7qz6okDr2AMipR405qLUCPvrU7NByn ln3QCR6kJZAew8HybXlBq8Xt4HDM3JaZlZ/kTJBNNcduvb2Z+lazzUuQg2nWkVqcLHbb 9w== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtt7ng2g7-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:03 +0000 Received: from m0098409.ppops.net (m0098409.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMgSiM012126; Tue, 25 Jan 2022 22:47:03 GMT Received: from ppma03dal.us.ibm.com (b.bd.3ea9.ip4.static.sl-reverse.com [169.62.189.11]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtt7ng2ft-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:03 +0000 Received: from pps.filterd (ppma03dal.us.ibm.com [127.0.0.1]) by ppma03dal.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMhnL7006726; Tue, 25 Jan 2022 22:47:02 GMT Received: from b01cxnp23033.gho.pok.ibm.com (b01cxnp23033.gho.pok.ibm.com [9.57.198.28]) by ppma03dal.us.ibm.com with ESMTP id 3dr9jb6e5x-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:01 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23033.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkwv732768428 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:58 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 96778AC062; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 7927DAC05E; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger Subject: [PATCH v9 15/23] ima: Implement hierarchical processing of file accesses Date: Tue, 25 Jan 2022 17:46:37 -0500 Message-Id: <20220125224645.79319-16-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: HCdg-vNidBEYyHILyHmR7rwAN1zlubVr X-Proofpoint-ORIG-GUID: 9ga8XOLzV59JZDzjNC1xxYo1NmfJBHx2 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_06,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 suspectscore=0 phishscore=0 impostorscore=0 bulkscore=0 priorityscore=1501 lowpriorityscore=0 mlxscore=0 spamscore=0 clxscore=1015 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger Implement hierarchical processing of file accesses in IMA namespaces by walking the list of user namespaces towards the root. This way file accesses can be audited in an IMA namespace and also be evaluated against the IMA policies of parent IMA namespaces. Pass the user_namespace into process_measurement since we will be walking the hierarchy of user_namespaces towards the init_user_ns and we can easily derive the ima_namespace from the user_namespace. __process_measurement() returns either 0 or -EACCES. For hierarchical processing remember the -EACCES returned by this function but continue to the parent user namespace. At the end either return 0 or -EACCES if an error occurred in one of the IMA namespaces. Currently the ima_ns pointer of the user_namespace is always NULL except at the init_user_ns, so test ima_ns for NULL pointer and skip the call to __process_measurement() if it is NULL. Once IMA namespacing is fully enabled, the pointer may still be NULL due to late initialization of the IMA namespace. Signed-off-by: Stefan Berger --- v9: - Switch callers to pass user_namespace rather than ima_namespace with potential NULL pointer - Add default case to switch statement and warn if this happens - Implement ima_ns_from_user_ns() in this patch now --- security/integrity/ima/ima.h | 8 ++++ security/integrity/ima/ima_main.c | 75 +++++++++++++++++++++++-------- 2 files changed, 64 insertions(+), 19 deletions(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 0057b1fd6c18..aea8fb8d2854 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -493,4 +493,12 @@ struct user_namespace *ima_user_ns_from_file(const struct file *filp) return file_inode(filp)->i_sb->s_user_ns; } +static inline struct ima_namespace +*ima_ns_from_user_ns(struct user_namespace *user_ns) +{ + if (user_ns == &init_user_ns) + return &init_ima_ns; + return NULL; +} + #endif /* __LINUX_IMA_H */ diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index ae0e9b14554a..3385221ca1d5 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -196,10 +196,10 @@ void ima_file_free(struct file *file) ima_check_last_writer(iint, inode, file); } -static int process_measurement(struct ima_namespace *ns, - struct file *file, const struct cred *cred, - u32 secid, char *buf, loff_t size, int mask, - enum ima_hooks func) +static int __process_measurement(struct ima_namespace *ns, + struct file *file, const struct cred *cred, + u32 secid, char *buf, loff_t size, int mask, + enum ima_hooks func) { struct inode *inode = file_inode(file); struct integrity_iint_cache *iint = NULL; @@ -391,6 +391,41 @@ static int process_measurement(struct ima_namespace *ns, return 0; } +static int process_measurement(struct user_namespace *user_ns, + struct file *file, const struct cred *cred, + u32 secid, char *buf, loff_t size, int mask, + enum ima_hooks func) +{ + struct ima_namespace *ns; + int ret = 0; + + while (user_ns) { + ns = ima_ns_from_user_ns(user_ns); + if (ns) { + int rc; + + rc = __process_measurement(ns, file, cred, secid, buf, + size, mask, func); + switch (rc) { + case 0: + break; + case -EACCES: + /* return this error at the end but continue */ + ret = -EACCES; + break; + default: + /* should not happen */ + ret = -EACCES; + WARN_ON_ONCE(true); + } + } + + user_ns = user_ns->parent; + }; + + return ret; +} + /** * ima_file_mmap - based on policy, collect/store measurement. * @file: pointer to the file to be measured (May be NULL) @@ -404,13 +439,14 @@ static int process_measurement(struct ima_namespace *ns, */ int ima_file_mmap(struct file *file, unsigned long prot) { - struct ima_namespace *ns = &init_ima_ns; + struct user_namespace *user_ns = current_user_ns(); u32 secid; if (file && (prot & PROT_EXEC)) { security_task_getsecid_subj(current, &secid); - return process_measurement(ns, file, current_cred(), secid, - NULL, 0, MAY_EXEC, MMAP_CHECK); + return process_measurement(user_ns, file, current_cred(), + secid, NULL, 0, MAY_EXEC, + MMAP_CHECK); } return 0; @@ -485,19 +521,19 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot) */ int ima_bprm_check(struct linux_binprm *bprm) { - struct ima_namespace *ns = &init_ima_ns; + struct user_namespace *user_ns = current_user_ns(); int ret; u32 secid; security_task_getsecid_subj(current, &secid); - ret = process_measurement(ns, bprm->file, current_cred(), secid, NULL, - 0, MAY_EXEC, BPRM_CHECK); + ret = process_measurement(user_ns, bprm->file, current_cred(), secid, + NULL, 0, MAY_EXEC, BPRM_CHECK); if (ret) return ret; security_cred_getsecid(bprm->cred, &secid); - return process_measurement(ns, bprm->file, bprm->cred, secid, NULL, 0, - MAY_EXEC, CREDS_CHECK); + return process_measurement(user_ns, bprm->file, bprm->cred, secid, + NULL, 0, MAY_EXEC, CREDS_CHECK); } /** @@ -512,11 +548,12 @@ int ima_bprm_check(struct linux_binprm *bprm) */ int ima_file_check(struct file *file, int mask) { - struct ima_namespace *ns = &init_ima_ns; + struct user_namespace *user_ns = current_user_ns(); u32 secid; security_task_getsecid_subj(current, &secid); - return process_measurement(ns, file, current_cred(), secid, NULL, 0, + return process_measurement(user_ns, file, current_cred(), secid, + NULL, 0, mask & (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND), FILE_CHECK); } @@ -698,7 +735,7 @@ void ima_post_path_mknod(struct user_namespace *mnt_userns, int ima_read_file(struct file *file, enum kernel_read_file_id read_id, bool contents) { - struct ima_namespace *ns = &init_ima_ns; + struct user_namespace *user_ns = current_user_ns(); enum ima_hooks func; u32 secid; @@ -721,7 +758,7 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id, /* Read entire file for all partial reads. */ func = read_idmap[read_id] ?: FILE_CHECK; security_task_getsecid_subj(current, &secid); - return process_measurement(ns, file, current_cred(), secid, NULL, + return process_measurement(user_ns, file, current_cred(), secid, NULL, 0, MAY_READ, func); } @@ -749,7 +786,7 @@ const int read_idmap[READING_MAX_ID] = { int ima_post_read_file(struct file *file, void *buf, loff_t size, enum kernel_read_file_id read_id) { - struct ima_namespace *ns = &init_ima_ns; + struct user_namespace *user_ns = current_user_ns(); enum ima_hooks func; u32 secid; @@ -766,8 +803,8 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, func = read_idmap[read_id] ?: FILE_CHECK; security_task_getsecid_subj(current, &secid); - return process_measurement(ns, file, current_cred(), secid, buf, size, - MAY_READ, func); + return process_measurement(user_ns, file, current_cred(), secid, + buf, size, MAY_READ, func); } /** From patchwork Tue Jan 25 22:46:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724303 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 60BA5C46467 for ; Tue, 25 Jan 2022 22:47:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234291AbiAYWrn (ORCPT ); Tue, 25 Jan 2022 17:47:43 -0500 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:39380 "EHLO mx0b-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234221AbiAYWr2 (ORCPT ); Tue, 25 Jan 2022 17:47:28 -0500 Received: from pps.filterd (m0098417.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PMeNgM016888; Tue, 25 Jan 2022 22:47:02 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=nE+PSQxb5vGtfHjolgjPf7jOdCwe1ilsr/0hQlENfEk=; b=sDV5vcg4tTTsebEiRAIwy73qmk8BxL2bb/oZ6Ku6BBU6leUzSWxVn6dUP+2o9yVcJ2Aq N5O0zyJcl+bZYGk/a3SmWuAReyMjGFbGrbQ2fihG8EbOc16eJAl+tpVYyfgknM3Euooy 22f82X37yYnAOYrZ8suc+XVNfzcsGS0FTAnUHlyINA4NYjay3+VlwWrzUBGHd3GI0cH7 88I9snfRMo20AfTy/gZf7XI4RfDcIa9WQkckLtebV/o7/Qhemq4QYWP22v+azBb9/Z2Z zmB4K6zMBZdujik0M2/i+PuRUumjJxLd/JxS05T7AW8sKsgEzjQphM/iocgFzclRrrhL WA== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtqnjtsen-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:01 +0000 Received: from m0098417.ppops.net (m0098417.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMh5tD029384; Tue, 25 Jan 2022 22:47:01 GMT Received: from ppma01wdc.us.ibm.com (fd.55.37a9.ip4.static.sl-reverse.com [169.55.85.253]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtqnjtsee-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:01 +0000 Received: from pps.filterd (ppma01wdc.us.ibm.com [127.0.0.1]) by ppma01wdc.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMhVdH008811; Tue, 25 Jan 2022 22:47:00 GMT Received: from b01cxnp23033.gho.pok.ibm.com (b01cxnp23033.gho.pok.ibm.com [9.57.198.28]) by ppma01wdc.us.ibm.com with ESMTP id 3dr9jaf3j5-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:00 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23033.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkwIo32768430 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:58 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id AC978AC066; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 9B0E7AC064; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger Subject: [PATCH v9 16/23] ima: Implement ima_free_policy_rules() for freeing of an ima_namespace Date: Tue, 25 Jan 2022 17:46:38 -0500 Message-Id: <20220125224645.79319-17-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: 9y6_ocsyyiA1VFbXF0rfIc-ZaGALqD43 X-Proofpoint-GUID: lyPMS9VSh1aadn4oNM0vwaf3HdVgCVt5 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_06,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 lowpriorityscore=0 suspectscore=0 impostorscore=0 malwarescore=0 spamscore=0 adultscore=0 mlxlogscore=999 bulkscore=0 phishscore=0 priorityscore=1501 mlxscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger Implement ima_free_policy_rules() that is needed when an ima_namespace is freed. Only reset temp_ima_appraise when using init_ima_ns. Signed-off-by: Stefan Berger --- v9: - Only reset temp_ima_appraise when using init_ima_ns. --- security/integrity/ima/ima.h | 1 + security/integrity/ima/ima_policy.c | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index aea8fb8d2854..8c757223d549 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -329,6 +329,7 @@ void ima_update_policy_flags(struct ima_namespace *ns); ssize_t ima_parse_add_rule(struct ima_namespace *ns, char *rule); void ima_delete_rules(struct ima_namespace *ns); int ima_check_policy(struct ima_namespace *ns); +void ima_free_policy_rules(struct ima_namespace *ns); void *ima_policy_start(struct seq_file *m, loff_t *pos); void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos); void ima_policy_stop(struct seq_file *m, void *v); diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index e8140e73d80b..47f2d1b5d156 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -1880,13 +1880,31 @@ void ima_delete_rules(struct ima_namespace *ns) { struct ima_rule_entry *entry, *tmp; - temp_ima_appraise = 0; + if (ns == &init_ima_ns) + temp_ima_appraise = 0; + list_for_each_entry_safe(entry, tmp, &ns->ima_temp_rules, list) { list_del(&entry->list); ima_free_rule(entry); } } +/** + * ima_free_policy_rules - free all policy rules + * @ns: IMA namespace that has the policy + */ +void ima_free_policy_rules(struct ima_namespace *ns) +{ + struct ima_rule_entry *entry, *tmp; + + ima_delete_rules(ns); + + list_for_each_entry_safe(entry, tmp, &ns->ima_policy_rules, list) { + list_del(&entry->list); + ima_free_rule(entry); + } +} + #define __ima_hook_stringify(func, str) (#func), const char *const func_tokens[] = { From patchwork Tue Jan 25 22:46:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724301 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6E3B6C4167D for ; Tue, 25 Jan 2022 22:47:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234247AbiAYWrk (ORCPT ); Tue, 25 Jan 2022 17:47:40 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:43398 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234205AbiAYWr1 (ORCPT ); Tue, 25 Jan 2022 17:47:27 -0500 Received: from pps.filterd (m0187473.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PLfgMb031686; Tue, 25 Jan 2022 22:47:04 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=uITBW42IUuMk1nOtRjPFqgtTB/+zDZIMPjuNWrUHhXo=; b=J/zBUnZy1JCYRU886ua5fwgLOg6c0j0YgsWd01mzDK0R2XW8wkUCp6jKT641jTL3h3u9 kDOcE5Q/eKswc1uh7yCh8wkfP8a0Tu4jxzM8MhI0wHL5MJjyaYa3ZzTb2mE0aiG8tA9D ApUMHL5dNIhGDDJDyq5mup1M0uNZta3HTRr98XYczyUT6Xg9+C9yuIAA9+0YR5lhjWV+ um8E3jm7hTDNTjMTZYcuXvvbbbdc+cPOr6l0FeD2TMr/25fecf5Hnkx8TYYn8h5+UGkc TMMOtWFEiuTmC79keVZvWOdyVjO+pqXdtq+/6bcUZ12jcRFyyEFd6D1plSaYHpjQJqm5 gQ== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtsbch54f-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:04 +0000 Received: from m0187473.ppops.net (m0187473.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMVdZ4032206; Tue, 25 Jan 2022 22:47:03 GMT Received: from ppma02wdc.us.ibm.com (aa.5b.37a9.ip4.static.sl-reverse.com [169.55.91.170]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtsbch53x-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:03 +0000 Received: from pps.filterd (ppma02wdc.us.ibm.com [127.0.0.1]) by ppma02wdc.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMhqFK025192; Tue, 25 Jan 2022 22:47:02 GMT Received: from b01cxnp23033.gho.pok.ibm.com (b01cxnp23033.gho.pok.ibm.com [9.57.198.28]) by ppma02wdc.us.ibm.com with ESMTP id 3dr9ja7356-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:02 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23033.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkxS232571836 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:59 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id D9C59AC059; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id BBDB6AC068; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger Subject: [PATCH v9 17/23] ima: Add functions for creating and freeing of an ima_namespace Date: Tue, 25 Jan 2022 17:46:39 -0500 Message-Id: <20220125224645.79319-18-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: jhP1ID4ZZOoIJ4aqT77bMcFYxpYGf5Vv X-Proofpoint-ORIG-GUID: BWgcqPuSKFis9qy0Eda-pPFanpxoN72V X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_06,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 spamscore=0 clxscore=1015 adultscore=0 lowpriorityscore=0 mlxscore=0 phishscore=0 mlxlogscore=999 suspectscore=0 impostorscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger Implement create_ima_ns() to create an empty ima_namespace. Defer its initialization to a later point outside this function. Implement free_ima_ns() to free it. Signed-off-by: Stefan Berger Acked-by: Christian Brauner --- v9: - Set user_ns->ims_ns = NULL in free_ima_ns() - Refactored create_ima_ns() to defer initialization - Removed pr_debug functions --- include/linux/ima.h | 13 ++++++ security/integrity/ima/Makefile | 1 + security/integrity/ima/ima.h | 15 +++++++ security/integrity/ima/ima_init_ima_ns.c | 2 +- security/integrity/ima/ima_ns.c | 53 ++++++++++++++++++++++++ 5 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 security/integrity/ima/ima_ns.c diff --git a/include/linux/ima.h b/include/linux/ima.h index 0cf2a80c8b35..964a08702573 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -220,4 +220,17 @@ static inline bool ima_appraise_signature(enum kernel_read_file_id func) return false; } #endif /* CONFIG_IMA_APPRAISE && CONFIG_INTEGRITY_TRUSTED_KEYRING */ + +#ifdef CONFIG_IMA_NS + +void free_ima_ns(struct user_namespace *ns); + +#else + +static inline void free_ima_ns(struct user_namespace *user_ns) +{ +} + +#endif /* CONFIG_IMA_NS */ + #endif /* _LINUX_IMA_H */ diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile index f8a5e5f3975d..b86a35fbed60 100644 --- a/security/integrity/ima/Makefile +++ b/security/integrity/ima/Makefile @@ -14,6 +14,7 @@ ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o ima-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o ima-$(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) += ima_asymmetric_keys.o ima-$(CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS) += ima_queue_keys.o +ima-$(CONFIG_IMA_NS) += ima_ns.o ifeq ($(CONFIG_EFI),y) ima-$(CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT) += ima_efi.o diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 8c757223d549..751e936a6311 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -167,6 +167,7 @@ extern bool ima_canonical_fmt; int ima_init(void); int ima_fs_init(void); int ima_ns_init(void); +int ima_init_namespace(struct ima_namespace *ns); int ima_add_template_entry(struct ima_namespace *ns, struct ima_template_entry *entry, int violation, const char *op, struct inode *inode, @@ -502,4 +503,18 @@ static inline struct ima_namespace return NULL; } +#ifdef CONFIG_IMA_NS + +struct ima_namespace *create_ima_ns(void); + +#else + +static inline struct ima_namespace *create_ima_ns(void) +{ + WARN(1, "Cannot create an IMA namespace\n"); + return ERR_PTR(-EFAULT); +} + +#endif /* CONFIG_IMA_NS */ + #endif /* __LINUX_IMA_H */ diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c index 1cba545ae477..166dab4a3126 100644 --- a/security/integrity/ima/ima_init_ima_ns.c +++ b/security/integrity/ima/ima_init_ima_ns.c @@ -8,7 +8,7 @@ #include "ima.h" -static int ima_init_namespace(struct ima_namespace *ns) +int ima_init_namespace(struct ima_namespace *ns) { int rc; diff --git a/security/integrity/ima/ima_ns.c b/security/integrity/ima/ima_ns.c new file mode 100644 index 000000000000..b3b81a1e313e --- /dev/null +++ b/security/integrity/ima/ima_ns.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2016-2021 IBM Corporation + * Author: + * Yuqiong Sun + * Stefan Berger + */ + +#include + +#include "ima.h" + +static struct kmem_cache *imans_cachep; + +struct ima_namespace *create_ima_ns(void) +{ + struct ima_namespace *ns; + + ns = kmem_cache_zalloc(imans_cachep, GFP_KERNEL); + if (!ns) + return ERR_PTR(-ENOMEM); + + return ns; +} + +/* destroy_ima_ns() must only be called after ima_init_namespace() was called */ +static void destroy_ima_ns(struct ima_namespace *ns) +{ + unregister_blocking_lsm_notifier(&ns->ima_lsm_policy_notifier); + kfree(ns->arch_policy_entry); + ima_free_policy_rules(ns); +} + +void free_ima_ns(struct user_namespace *user_ns) +{ + struct ima_namespace *ns = user_ns->ima_ns; + + if (!ns || WARN_ON(ns == &init_ima_ns)) + return; + + destroy_ima_ns(ns); + + kmem_cache_free(imans_cachep, ns); + + user_ns->ima_ns = NULL; +} + +static int __init imans_cache_init(void) +{ + imans_cachep = KMEM_CACHE(ima_namespace, SLAB_PANIC); + return 0; +} +subsys_initcall(imans_cache_init) From patchwork Tue Jan 25 22:46:40 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724312 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7D5D7C3527B for ; Tue, 25 Jan 2022 22:47:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234362AbiAYWrt (ORCPT ); Tue, 25 Jan 2022 17:47:49 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:3278 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234230AbiAYWra (ORCPT ); Tue, 25 Jan 2022 17:47:30 -0500 Received: from pps.filterd (m0098393.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PKAYEA008922; Tue, 25 Jan 2022 22:47:04 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=KBMRAlHqbaq34yIQdl6nAq6Rioh+rNG5BNvB7eK4kx0=; b=oEXPc7l5xGPvLOJcRi6WU3d5IbegVKmGVJs+lyc3vGCcSz9jsXY9fQpT01b1ciPrBbIu UxUPZp2s7UzLyyIeYoZpYugcs9vqT6A1qQyPagbPYN3cwn+fSWbBth5PuVlYObye/UNF dY97QjRbWb3ZqZSrEgWRCE3sVl4x1uSW+CfGRzxPERC7I39eXog5nFZFh8KeuHdNfVLh zvSj90MS3vbRJCXgZwhYAr25zERuDtfk/oykBnq9NFTbgeYFPuAcKaoftuK6TeYk5tlL tLu/YzCMXEiAi/20NgbUPcj7tRXW/WtFXiA437Qa7uLu2uHF7jo4ak6+f6gudqeSkidT Yg== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtqp0jxrh-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:04 +0000 Received: from m0098393.ppops.net (m0098393.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMSFXn020945; Tue, 25 Jan 2022 22:47:03 GMT Received: from ppma05wdc.us.ibm.com (1b.90.2fa9.ip4.static.sl-reverse.com [169.47.144.27]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtqp0jxqv-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:03 +0000 Received: from pps.filterd (ppma05wdc.us.ibm.com [127.0.0.1]) by ppma05wdc.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMhsCV010557; Tue, 25 Jan 2022 22:47:02 GMT Received: from b01cxnp23034.gho.pok.ibm.com (b01cxnp23034.gho.pok.ibm.com [9.57.198.29]) by ppma05wdc.us.ibm.com with ESMTP id 3dtbch8rgg-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:02 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23034.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkxDp35127760 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:59 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 1496DAC05F; Tue, 25 Jan 2022 22:46:59 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id DFA76AC064; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:58 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Mehmet Kayaalp , Stefan Berger Subject: [PATCH v9 18/23] integrity/ima: Define ns_status for storing namespaced iint data Date: Tue, 25 Jan 2022 17:46:40 -0500 Message-Id: <20220125224645.79319-19-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: G2EHsF9bJAy9xmeCQBG3PiPxFMaLp8ch X-Proofpoint-ORIG-GUID: ewwq64XwFyumiQrassf_CG3fkY_kj_oh X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_05,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 mlxlogscore=999 phishscore=0 mlxscore=0 priorityscore=1501 adultscore=0 bulkscore=0 spamscore=0 impostorscore=0 lowpriorityscore=0 suspectscore=0 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Mehmet Kayaalp Add an rbtree to the IMA namespace structure that stores a namespaced version of iint->flags in ns_status struct. Similar to the integrity_iint_cache, both the iint and ns_status are looked up using the inode pointer value. The lookup, allocate, and insertion code is also similar. In subsequent patches we will have to find all ns_status entries an iint is being used in and reset flags there. To do this, connect a list of ns_status to the integrity_iint_cache and provide a reader-writer lock in the integrity_iint_cache to lock access to the list. To simplify the code in the non-namespaces case embed an ns_status in the integrity_iint_cache and have it linked into the iint's ns_status list when calling ima_get_ns_status(). When getting an ns_status first try to find it in the RB tree. Here we can run into the situation that an ns_status found in the RB tree has a different iint associated with it for the same inode. In this case we need to delete the ns_status structure and get a new one. There are two cases for freeing: - when the iint is freed (inode deletion): Walk the list of ns_status entries and disconnect each ns_status from the list; take the writer lock to protect access to the list; also, take the item off the per-namespace rbtree - when the ima_namepace is freed: While walking the rbtree, remove the ns_status from the list while also holding the iint's writer lock; to be able to grab the lock we have to have a pointer to the iint on the ns_status structure. To avoid an ns_status to be freed by the two cases concurrently, prevent these two cases to run concurrently. Therefore, groups of threads deleting either inodes or ima_namespaces are allowed to run concurrently but no two threads may run and one delete an inode and the other an ima_namespace. Signed-off-by: Mehmet Kayaalp Signed-off-by: Stefan Berger --- v9: - Move ns_status into integrity.h and embedded it into integrity_iint_cache for the non-CONFIG_IMA_NS case --- include/linux/ima.h | 7 + security/integrity/iint.c | 7 + security/integrity/ima/Makefile | 2 +- security/integrity/ima/ima.h | 17 ++ security/integrity/ima/ima_init_ima_ns.c | 5 + security/integrity/ima/ima_ns.c | 1 + security/integrity/ima/ima_ns_status.c | 340 +++++++++++++++++++++++ security/integrity/integrity.h | 35 ++- 8 files changed, 412 insertions(+), 2 deletions(-) create mode 100644 security/integrity/ima/ima_ns_status.c diff --git a/include/linux/ima.h b/include/linux/ima.h index 964a08702573..2fe32f1bf84b 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -225,12 +225,19 @@ static inline bool ima_appraise_signature(enum kernel_read_file_id func) void free_ima_ns(struct user_namespace *ns); +void ima_free_ns_status_list(struct list_head *head, rwlock_t *ns_list_lock); + #else static inline void free_ima_ns(struct user_namespace *user_ns) { } +static inline void ima_free_ns_status_list(struct list_head *head, + rwlock_t *ns_list_lock) +{ +} + #endif /* CONFIG_IMA_NS */ #endif /* _LINUX_IMA_H */ diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 8638976f7990..371cbceaf479 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "integrity.h" static struct rb_root integrity_iint_tree = RB_ROOT; @@ -82,6 +83,8 @@ static void iint_free(struct integrity_iint_cache *iint) iint->ima_creds_status = INTEGRITY_UNKNOWN; iint->evm_status = INTEGRITY_UNKNOWN; iint->measured_pcrs = 0; + rwlock_init(&iint->ns_list_lock); + INIT_LIST_HEAD(&iint->ns_list); kmem_cache_free(iint_cache, iint); } @@ -155,6 +158,8 @@ void integrity_inode_free(struct inode *inode) rb_erase(&iint->rb_node, &integrity_iint_tree); write_unlock(&integrity_iint_lock); + ima_free_ns_status_list(&iint->ns_list, &iint->ns_list_lock); + iint_free(iint); } @@ -170,6 +175,8 @@ static void init_once(void *foo) iint->ima_creds_status = INTEGRITY_UNKNOWN; iint->evm_status = INTEGRITY_UNKNOWN; mutex_init(&iint->mutex); + rwlock_init(&iint->ns_list_lock); + INIT_LIST_HEAD(&iint->ns_list); } static int __init integrity_iintcache_init(void) diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile index b86a35fbed60..edfb0c30a063 100644 --- a/security/integrity/ima/Makefile +++ b/security/integrity/ima/Makefile @@ -14,7 +14,7 @@ ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o ima-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o ima-$(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) += ima_asymmetric_keys.o ima-$(CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS) += ima_queue_keys.o -ima-$(CONFIG_IMA_NS) += ima_ns.o +ima-$(CONFIG_IMA_NS) += ima_ns.o ima_ns_status.o ifeq ($(CONFIG_EFI),y) ima-$(CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT) += ima_efi.o diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 751e936a6311..4af8f2c4df40 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -123,6 +123,10 @@ struct ima_h_table { }; struct ima_namespace { + struct rb_root ns_status_tree; + rwlock_t ns_tree_lock; + struct kmem_cache *ns_status_cache; + /* policy rules */ struct list_head ima_default_rules; struct list_head ima_policy_rules; @@ -507,6 +511,12 @@ static inline struct ima_namespace struct ima_namespace *create_ima_ns(void); +struct ns_status *ima_get_ns_status(struct ima_namespace *ns, + struct inode *inode, + struct integrity_iint_cache *iint); + +void ima_free_ns_status_tree(struct ima_namespace *ns); + #else static inline struct ima_namespace *create_ima_ns(void) @@ -515,6 +525,13 @@ static inline struct ima_namespace *create_ima_ns(void) return ERR_PTR(-EFAULT); } +static inline struct ns_status *ima_get_ns_status(struct ima_namespace *ns, + struct inode *inode, + struct integrity_iint_cache *iint) +{ + return NULL; +} + #endif /* CONFIG_IMA_NS */ #endif /* __LINUX_IMA_H */ diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c index 166dab4a3126..d4ddfd1de60b 100644 --- a/security/integrity/ima/ima_init_ima_ns.c +++ b/security/integrity/ima/ima_init_ima_ns.c @@ -12,6 +12,11 @@ int ima_init_namespace(struct ima_namespace *ns) { int rc; + ns->ns_status_tree = RB_ROOT; + rwlock_init(&ns->ns_tree_lock); + /* Use KMEM_CACHE for simplicity */ + ns->ns_status_cache = KMEM_CACHE(ns_status, SLAB_PANIC); + INIT_LIST_HEAD(&ns->ima_default_rules); INIT_LIST_HEAD(&ns->ima_policy_rules); INIT_LIST_HEAD(&ns->ima_temp_rules); diff --git a/security/integrity/ima/ima_ns.c b/security/integrity/ima/ima_ns.c index b3b81a1e313e..29af6fea2d74 100644 --- a/security/integrity/ima/ima_ns.c +++ b/security/integrity/ima/ima_ns.c @@ -29,6 +29,7 @@ static void destroy_ima_ns(struct ima_namespace *ns) unregister_blocking_lsm_notifier(&ns->ima_lsm_policy_notifier); kfree(ns->arch_policy_entry); ima_free_policy_rules(ns); + ima_free_ns_status_tree(ns); } void free_ima_ns(struct user_namespace *user_ns) diff --git a/security/integrity/ima/ima_ns_status.c b/security/integrity/ima/ima_ns_status.c new file mode 100644 index 000000000000..061adb114417 --- /dev/null +++ b/security/integrity/ima/ima_ns_status.c @@ -0,0 +1,340 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2016-2021 IBM Corporation + * Author: + * Yuqiong Sun + * Stefan Berger + */ + +#include +#include + +#include "ima.h" + +/* + * An ns_status must be on a per-namespace rbtree and on a per-iint list. + * + * Locking order for ns_status: + * 1) ns->ns_tree_lock : Lock the rbtree + * 2) iint->ns_list_lock: Lock the list + * + * An ns_status can be freed either by walking the rbtree (namespace deletion) + * or by walking the linked list of ns_status (inode/iint deletion). There are + * two functions that implement each one of the cases. To avoid concurrent + * freeing of the same ns_status, the two freeing paths cannot be run + * concurrently but each path can be run by multiple threads since no two + * threads will free the same inode/iint and no two threads will free the same + * namespace. Grouping threads like this ensures that: + * - while walking the rbtree: all ns_status will be on their list and the iint + * will still exist + * - while walking the list: all ns_status will be on their rbtree + */ +enum lk_group { + GRP_NS_STATUS_LIST = 0, + GRP_NS_STATUS_TREE +}; + +static atomic_t lg_ctr[2] = { + ATOMIC_INIT(0), + ATOMIC_INIT(0) +}; + +static DEFINE_SPINLOCK(lg_ctr_lock); + +static struct wait_queue_head lg_wq[2] = { + __WAIT_QUEUE_HEAD_INITIALIZER(lg_wq[0]), + __WAIT_QUEUE_HEAD_INITIALIZER(lg_wq[1]) +}; + +static atomic_t ns_list_waiters = ATOMIC_INIT(0); + +/* Any number of concurrent threads may free ns_status's in either one of the + * groups but the groups must not run concurrently. The GRP_NS_STATUS_TREE + * group yields to waiters in the GRP_NS_STATUS_LIST group since namespace + * deletion has more time. + */ +static void lock_group(enum lk_group group) +{ + unsigned long flags; + bool done = false; + int announced = 0; + + while (1) { + spin_lock_irqsave(&lg_ctr_lock, flags); + + switch (group) { + case GRP_NS_STATUS_LIST: + if (atomic_read(&lg_ctr[GRP_NS_STATUS_TREE]) == 0) { + if (announced) + atomic_dec(&ns_list_waiters); + done = true; + atomic_inc(&lg_ctr[GRP_NS_STATUS_LIST]); + } else { + /* rbtree being deleted; announce waiting */ + if (!announced) { + atomic_inc(&ns_list_waiters); + announced = 1; + } + } + break; + case GRP_NS_STATUS_TREE: + if (atomic_read(&lg_ctr[GRP_NS_STATUS_LIST]) == 0 && + atomic_read(&ns_list_waiters) == 0) { + done = true; + atomic_inc(&lg_ctr[GRP_NS_STATUS_TREE]); + } + break; + } + + spin_unlock_irqrestore(&lg_ctr_lock, flags); + + if (done) + break; + + /* wait until opposite group is done */ + switch (group) { + case GRP_NS_STATUS_LIST: + wait_event_interruptible + (lg_wq[GRP_NS_STATUS_LIST], + atomic_read(&lg_ctr[GRP_NS_STATUS_TREE]) == 0); + break; + case GRP_NS_STATUS_TREE: + wait_event_interruptible + (lg_wq[GRP_NS_STATUS_TREE], + atomic_read(&lg_ctr[GRP_NS_STATUS_LIST]) == 0 && + atomic_read(&ns_list_waiters) == 0); + break; + } + } +} + +static void unlock_group(enum lk_group group) +{ + switch (group) { + case GRP_NS_STATUS_LIST: + if (atomic_dec_and_test(&lg_ctr[GRP_NS_STATUS_LIST])) + wake_up_interruptible_all(&lg_wq[GRP_NS_STATUS_TREE]); + break; + case GRP_NS_STATUS_TREE: + if (atomic_dec_and_test(&lg_ctr[GRP_NS_STATUS_TREE])) + wake_up_interruptible_all(&lg_wq[GRP_NS_STATUS_LIST]); + break; + } +} + +static void ns_status_free(struct ima_namespace *ns, + struct ns_status *ns_status) +{ + pr_debug("FREE ns_status: %p\n", ns_status); + + kmem_cache_free(ns->ns_status_cache, ns_status); +} + +/* + * ima_free_ns_status_tree - free all items on the ns_status_tree and take each + * one off the list; yield to ns_list free'ers + * + * This function is called when an ima_namespace is freed. All entries in the + * rbtree will be taken off their list and collected in a garbage collection + * list and freed at the end. This allows to walk the rbtree again. + */ +void ima_free_ns_status_tree(struct ima_namespace *ns) +{ + struct ns_status *ns_status, *next; + struct llist_node *node; + LLIST_HEAD(garbage); + unsigned int ctr; + bool restart; + + do { + ctr = 0; + restart = false; + + lock_group(GRP_NS_STATUS_TREE); + write_lock(&ns->ns_tree_lock); + + rbtree_postorder_for_each_entry_safe(ns_status, next, + &ns->ns_status_tree, + rb_node) { + write_lock(&ns_status->iint->ns_list_lock); + if (!list_empty(&ns_status->ns_next)) { + list_del_init(&ns_status->ns_next); + llist_add(&ns_status->gc_llist, &garbage); + ctr++; + } + write_unlock(&ns_status->iint->ns_list_lock); + + /* After some progress yield to any waiting ns_list + * free'ers. + */ + if (atomic_read(&ns_list_waiters) > 0 && ctr >= 5) { + restart = true; + break; + } + } + + write_unlock(&ns->ns_tree_lock); + unlock_group(GRP_NS_STATUS_TREE); + } while (restart); + + node = llist_del_all(&garbage); + llist_for_each_entry_safe(ns_status, next, node, gc_llist) + ns_status_free(ns, ns_status); + + kmem_cache_destroy(ns->ns_status_cache); +} + +/* + * ima_free_ns_status_list: free the list of ns_status items and take + * each one off its namespace rbtree + */ +void ima_free_ns_status_list(struct list_head *head, rwlock_t *ns_list_lock) +{ + struct ns_status *ns_status; + + lock_group(GRP_NS_STATUS_LIST); + + while (1) { + write_lock(ns_list_lock); + ns_status = list_first_entry_or_null(head, struct ns_status, + ns_next); + if (ns_status) + list_del_init(&ns_status->ns_next); + write_unlock(ns_list_lock); + + if (!ns_status) + break; + + write_lock(&ns_status->ns->ns_tree_lock); + + rb_erase(&ns_status->rb_node, &ns_status->ns->ns_status_tree); + RB_CLEAR_NODE(&ns_status->rb_node); + + write_unlock(&ns_status->ns->ns_tree_lock); + + ns_status_free(ns_status->ns, ns_status); + } + + unlock_group(GRP_NS_STATUS_LIST); +} + +/* + * ns_status_find - return the ns_status associated with an inode; + * caller must hold lock for tree + */ +static struct ns_status *ns_status_find(struct ima_namespace *ns, + struct inode *inode) +{ + struct ns_status *ns_status; + struct rb_node *n = ns->ns_status_tree.rb_node; + + while (n) { + ns_status = rb_entry(n, struct ns_status, rb_node); + + if (inode < ns_status->inode) + n = n->rb_left; + else if (inode > ns_status->inode) + n = n->rb_right; + else + break; + } + if (!n) + return NULL; + + return ns_status; +} + +static void insert_ns_status(struct ima_namespace *ns, struct inode *inode, + struct ns_status *ns_status) +{ + struct rb_node **p; + struct rb_node *node, *parent = NULL; + struct ns_status *test_status; + + p = &ns->ns_status_tree.rb_node; + while (*p) { + parent = *p; + test_status = rb_entry(parent, struct ns_status, rb_node); + if (inode < test_status->inode) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + node = &ns_status->rb_node; + rb_link_node(node, parent, p); + rb_insert_color(node, &ns->ns_status_tree); +} + +static void ns_status_unlink(struct ima_namespace *ns, + struct ns_status *ns_status) +{ + write_lock(&ns_status->iint->ns_list_lock); + if (!list_empty(&ns_status->ns_next)) + list_del_init(&ns_status->ns_next); + write_unlock(&ns_status->iint->ns_list_lock); + + rb_erase(&ns_status->rb_node, &ns->ns_status_tree); + RB_CLEAR_NODE(&ns_status->rb_node); +} + +struct ns_status *ima_get_ns_status(struct ima_namespace *ns, + struct inode *inode, + struct integrity_iint_cache *iint) +{ + struct ns_status *ns_status; + + /* Prevent finding the status via the list (inode/iint deletion) since + * we may free it. + */ + lock_group(GRP_NS_STATUS_TREE); + + write_lock(&ns->ns_tree_lock); + + ns_status = ns_status_find(ns, inode); + if (ns_status) { + /* Check for ns_status with same inode but a stale iint. + */ + if (unlikely(ns_status->iint != iint)) { + ns_status_unlink(ns, ns_status); + ns_status_free(ns, ns_status); + goto get_new; + } else if (inode->i_ino == ns_status->i_ino && + inode->i_generation == ns_status->i_generation) { + goto unlock; + } + + /* Same inode number is reused, overwrite the ns_status */ + ns_status_reset(ns_status); + } else { +get_new: + ns_status = kmem_cache_alloc(ns->ns_status_cache, GFP_NOFS); + if (!ns_status) { + ns_status = ERR_PTR(-ENOMEM); + goto unlock; + } + + pr_debug("NEW ns_status: %p\n", ns_status); + + ns_status_init(ns_status); + insert_ns_status(ns, inode, ns_status); + } + + ns_status->iint = iint; + ns_status->inode = inode; + ns_status->ns = ns; + ns_status->i_ino = inode->i_ino; + ns_status->i_generation = inode->i_generation; + + /* make visible on list */ + write_lock(&iint->ns_list_lock); + if (list_empty(&ns_status->ns_next)) + list_add_tail(&ns_status->ns_next, &iint->ns_list); + write_unlock(&iint->ns_list_lock); + +unlock: + write_unlock(&ns->ns_tree_lock); + + unlock_group(GRP_NS_STATUS_TREE); + + return ns_status; +} diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 547425c20e11..b7d5ca108900 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -122,13 +122,39 @@ struct signature_v2_hdr { uint8_t sig[]; /* signature payload */ } __packed; +/* integrity status of an inode in a namespace */ +struct ns_status { + struct list_head ns_next; + unsigned long flags; /* flags split with iint */ +#ifdef CONFIG_IMA_NS + struct rb_node rb_node; + struct integrity_iint_cache *iint; + struct inode *inode; + struct ima_namespace *ns; + ino_t i_ino; + u32 i_generation; + struct llist_node gc_llist; /* used while freeing */ +#endif +}; + +static inline void ns_status_reset(struct ns_status *ns_status) +{ + ns_status->flags = 0; +} + +static inline void ns_status_init(struct ns_status *ns_status) +{ + INIT_LIST_HEAD(&ns_status->ns_next); + ns_status_reset(ns_status); +} + /* integrity data associated with an inode */ struct integrity_iint_cache { struct rb_node rb_node; /* rooted in integrity_iint_tree */ struct mutex mutex; /* protects: version, flags, digest */ struct inode *inode; /* back pointer to inode in question */ u64 version; /* track inode changes */ - unsigned long flags; + unsigned long flags; /* flags split with ns_status */ unsigned long measured_pcrs; unsigned long atomic_flags; enum integrity_status ima_file_status:4; @@ -138,6 +164,13 @@ struct integrity_iint_cache { enum integrity_status ima_creds_status:4; enum integrity_status evm_status:4; struct ima_digest_data *ima_hash; + + /* + * Lock and list of ns_status for files shared by different + * namespaces + */ + rwlock_t ns_list_lock; + struct list_head ns_list; }; /* rbtree tree calls to lookup, insert, delete From patchwork Tue Jan 25 22:46:41 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724293 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2C7DEC43219 for ; Tue, 25 Jan 2022 22:47:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234145AbiAYWre (ORCPT ); Tue, 25 Jan 2022 17:47:34 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:32894 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234200AbiAYWrZ (ORCPT ); Tue, 25 Jan 2022 17:47:25 -0500 Received: from pps.filterd (m0098396.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PMZoWd025044; Tue, 25 Jan 2022 22:47:03 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=aqawj1wFF0kX/ncjqKoiF1OjUAUe2oNsy9Xoz9wGfE4=; b=gnFcelG4E67NKZgYb/aujpStdzDEXBeNQcL1D2CVvJC6L/5IFIgXQ1iuKlLy7Q1xZy83 mtUvaP8xotjUluKELU2ZlC/EJ0iBe/Jh5mD90DT8O3sbnPNnAdbCJ02Io2mvmFD/6i3h x+zBMpm11zXPGAAgl+b8JLXFIMkYpkJop3TABlWiJvWBv8pRvF00qxjEwD32fPzHTA7T 80nuUBl2yHpmQrZuGQLx9RIqy8+Fe5ipaSOx8vAk5BsRH58SDv36LhZozDkZa/oQD7yv VJBH0d0kLRhTyE8pnUGgYRzrZ7U7ugbY+dP3zC/LZxhs9OnrRXjmnCWYk236ltkIPyAR 8Q== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtsvfgb7t-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:03 +0000 Received: from m0098396.ppops.net (m0098396.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMkPWd005713; Tue, 25 Jan 2022 22:47:02 GMT Received: from ppma02wdc.us.ibm.com (aa.5b.37a9.ip4.static.sl-reverse.com [169.55.91.170]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtsvfgb7c-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:02 +0000 Received: from pps.filterd (ppma02wdc.us.ibm.com [127.0.0.1]) by ppma02wdc.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMhqN2025185; Tue, 25 Jan 2022 22:47:01 GMT Received: from b01cxnp23034.gho.pok.ibm.com (b01cxnp23034.gho.pok.ibm.com [9.57.198.29]) by ppma02wdc.us.ibm.com with ESMTP id 3dr9ja734q-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:00 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23034.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkxcu30605634 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:59 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 2F81CAC064; Tue, 25 Jan 2022 22:46:59 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 1B197AC062; Tue, 25 Jan 2022 22:46:59 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:59 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Mehmet Kayaalp , Stefan Berger Subject: [PATCH v9 19/23] ima: Namespace audit status flags Date: Tue, 25 Jan 2022 17:46:41 -0500 Message-Id: <20220125224645.79319-20-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: bhdrM3DjYhbulOmz_bzIx0s-oANdJjVW X-Proofpoint-ORIG-GUID: 88N8UcMC5tgDm-DkRcXZ9s_doXuefgyj X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_05,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxlogscore=999 bulkscore=0 mlxscore=0 phishscore=0 spamscore=0 clxscore=1015 malwarescore=0 adultscore=0 suspectscore=0 priorityscore=1501 lowpriorityscore=0 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Mehmet Kayaalp The iint cache stores whether the file is measured, appraised, audited etc. This patch moves the IMA_AUDIT and IMA_AUDITED flags into the per-namespace ns_status, enabling IMA audit mechanism to audit the same file each time it is accessed in a new namespace. Read and write operations on the iint flags is replaced with function calls. For reading, iint_flags() returns the bitwise OR of iint->flags and ns_status->flags. The ns_status flags are masked with IMA_NS_STATUS_FLAGS (currently only IMA_AUDIT & IMA_AUDITED) while the iint flags are masked with ~IMA_NS_STATUS_FLAGS. Similarly, set_iint_flags() writes the one masked portion to the ns_status flags, while the iint flags receive the remaining flags. The ns_status parameter added to ima_audit_measurement() is used with the above functions to query and set the ns_status flags. Replace all occurrences where the IMA_AUDITED flag is set with the iint_flags() and set_iint_flags() operations so that the splitting and merging of the flags works properly. Whenever the IMA_AUDITED flag is tested, use iint_flags() to receive the merged version of the flags. Since IMA_AUDITED is also part of the IMA_DONE_MASK, use the new functions wherever the IMA_DONE_MASK is involved. Move the IMA_AUDIT flag also into the ns_status flags since this flag is dependent on policy rules that may be different per namespace. Signed-off-by: Mehmet Kayaalp Signed-off-by: Stefan Berger --- v9: - Use ns_status also in non-namespaced case and use same flag splitting for namespaced and non-namespaced case, thus use one implementation for iint_flags() and set_iint_flags() - Merge-in patch 'Enable re-auditing of modified files' - Use one implementation of mask_iint_ns_status_flags() for namespaced and non-namespaced case - Added IMA_AUDIT to IMA_NS_STATUS_FLAGS since it's a per namespace flag --- security/integrity/ima/ima.h | 40 ++++++++++++++++++++-- security/integrity/ima/ima_api.c | 8 +++-- security/integrity/ima/ima_main.c | 56 ++++++++++++++++++++++++++----- security/integrity/integrity.h | 3 ++ 4 files changed, 94 insertions(+), 13 deletions(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 4af8f2c4df40..883aeb30590f 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -310,7 +310,8 @@ int process_buffer_measurement(struct ima_namespace *ns, int pcr, const char *func_data, bool buf_hash, u8 *digest, size_t digest_len); void ima_audit_measurement(struct integrity_iint_cache *iint, - const unsigned char *filename); + const unsigned char *filename, + struct ns_status *ns_status); int ima_alloc_init_template(struct ima_event_data *event_data, struct ima_template_entry **entry, struct ima_template_desc *template_desc); @@ -493,6 +494,34 @@ static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op, #define POLICY_FILE_FLAGS S_IWUSR #endif /* CONFIG_IMA_READ_POLICY */ +#define IMA_NS_STATUS_ACTIONS IMA_AUDIT +#define IMA_NS_STATUS_FLAGS (IMA_AUDIT | IMA_AUDITED) + +static inline unsigned long iint_flags(struct integrity_iint_cache *iint, + struct ns_status *ns_status) +{ + if (!ns_status) + return iint->flags; + + return (iint->flags & ~IMA_NS_STATUS_FLAGS) | + (ns_status->flags & IMA_NS_STATUS_FLAGS); +} + +static inline unsigned long set_iint_flags(struct integrity_iint_cache *iint, + struct ns_status *ns_status, + unsigned long flags) +{ + unsigned long ns_status_flags = flags & IMA_NS_STATUS_FLAGS; + + WARN_ON(!ns_status && ns_status_flags); + + iint->flags = flags & ~IMA_NS_STATUS_FLAGS; + if (ns_status) + ns_status->flags = ns_status_flags; + + return flags; +} + static inline struct user_namespace *ima_user_ns_from_file(const struct file *filp) { @@ -529,7 +558,14 @@ static inline struct ns_status *ima_get_ns_status(struct ima_namespace *ns, struct inode *inode, struct integrity_iint_cache *iint) { - return NULL; + struct ns_status *ns_status = &iint->ns_status; + + if (list_empty(&iint->ns_list)) { + ns_status_init(ns_status); + list_add(&ns_status->ns_next, &iint->ns_list); + } + + return ns_status; } #endif /* CONFIG_IMA_NS */ diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index bee35ebb3a38..4284c216ee7b 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -348,14 +348,16 @@ void ima_store_measurement(struct ima_namespace *ns, } void ima_audit_measurement(struct integrity_iint_cache *iint, - const unsigned char *filename) + const unsigned char *filename, + struct ns_status *ns_status) { struct audit_buffer *ab; char *hash; const char *algo_name = hash_algo_name[iint->ima_hash->algo]; int i; + unsigned long flags = iint_flags(iint, ns_status); - if (iint->flags & IMA_AUDITED) + if (flags & IMA_AUDITED) return; hash = kzalloc((iint->ima_hash->length * 2) + 1, GFP_KERNEL); @@ -378,7 +380,7 @@ void ima_audit_measurement(struct integrity_iint_cache *iint, audit_log_task_info(ab); audit_log_end(ab); - iint->flags |= IMA_AUDITED; + set_iint_flags(iint, ns_status, flags | IMA_AUDITED); out: kfree(hash); return; diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 3385221ca1d5..8018e9aaad32 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -149,6 +149,31 @@ static void ima_rdwr_violation_check(struct ima_namespace *ns, "invalid_pcr", "open_writers"); } +static void mask_iint_ns_status_flags(struct integrity_iint_cache *iint, + unsigned long mask) +{ + struct ns_status *ns_status; + unsigned long flags; + + read_lock(&iint->ns_list_lock); + if (list_empty(&iint->ns_list)) { + /* + * An empty list is possible due to __process_measurement only + * creating ns_status for IMA_NS_STATUS_ACTIONS. + * No ns_status being used implies that for example IMA_AUDIT + * was never used and thus IMA_AUDITED cannot have been set. + */ + flags = iint_flags(iint, NULL) & mask; + set_iint_flags(iint, NULL, flags); + } else { + list_for_each_entry(ns_status, &iint->ns_list, ns_next) { + flags = iint_flags(iint, ns_status) & mask; + set_iint_flags(iint, ns_status, flags); + } + } + read_unlock(&iint->ns_list_lock); +} + static void ima_check_last_writer(struct integrity_iint_cache *iint, struct inode *inode, struct file *file) { @@ -165,8 +190,11 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint, if (!IS_I_VERSION(inode) || !inode_eq_iversion(inode, iint->version) || (iint->flags & IMA_NEW_FILE)) { - iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE); + mask_iint_ns_status_flags + (iint, + ~(IMA_DONE_MASK | IMA_NEW_FILE)); iint->measured_pcrs = 0; + if (update) ima_update_xattr(iint, file); } @@ -203,6 +231,7 @@ static int __process_measurement(struct ima_namespace *ns, { struct inode *inode = file_inode(file); struct integrity_iint_cache *iint = NULL; + struct ns_status *ns_status = NULL; struct ima_template_desc *template_desc = NULL; char *pathbuf = NULL; char filename[NAME_MAX]; @@ -215,6 +244,7 @@ static int __process_measurement(struct ima_namespace *ns, bool violation_check; enum hash_algo hash_algo; unsigned int allowed_algos = 0; + unsigned long flags; if (!ns->ima_policy_flag || !S_ISREG(inode->i_mode)) return 0; @@ -243,6 +273,14 @@ static int __process_measurement(struct ima_namespace *ns, iint = integrity_inode_get(inode); if (!iint) rc = -ENOMEM; + + if (!rc && (action & IMA_NS_STATUS_ACTIONS)) { + ns_status = ima_get_ns_status(ns, inode, iint); + if (IS_ERR(ns_status)) { + rc = PTR_ERR(ns_status); + ns_status = NULL; + } + } } if (!rc && violation_check) @@ -258,11 +296,13 @@ static int __process_measurement(struct ima_namespace *ns, mutex_lock(&iint->mutex); + flags = iint_flags(iint, ns_status); + if (test_and_clear_bit(IMA_CHANGE_ATTR, &iint->atomic_flags)) /* reset appraisal flags if ima_inode_post_setattr was called */ - iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED | - IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK | - IMA_ACTION_FLAGS); + flags &= ~(IMA_APPRAISE | IMA_APPRAISED | + IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK | + IMA_ACTION_FLAGS); /* * Re-evaulate the file if either the xattr has changed or the @@ -273,7 +313,7 @@ static int __process_measurement(struct ima_namespace *ns, ((inode->i_sb->s_iflags & SB_I_IMA_UNVERIFIABLE_SIGNATURE) && !(inode->i_sb->s_iflags & SB_I_UNTRUSTED_MOUNTER) && !(action & IMA_FAIL_UNVERIFIABLE_SIGS))) { - iint->flags &= ~IMA_DONE_MASK; + flags &= ~IMA_DONE_MASK; iint->measured_pcrs = 0; } @@ -281,9 +321,9 @@ static int __process_measurement(struct ima_namespace *ns, * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, * IMA_AUDIT, IMA_AUDITED) */ - iint->flags |= action; + flags = set_iint_flags(iint, ns_status, flags | action); action &= IMA_DO_MASK; - action &= ~((iint->flags & (IMA_DONE_MASK ^ IMA_MEASURED)) >> 1); + action &= ~((flags & (IMA_DONE_MASK ^ IMA_MEASURED)) >> 1); /* If target pcr is already measured, unset IMA_MEASURE action */ if ((action & IMA_MEASURE) && (iint->measured_pcrs & (0x1 << pcr))) @@ -358,7 +398,7 @@ static int __process_measurement(struct ima_namespace *ns, &pathname, filename); } if (action & IMA_AUDIT) - ima_audit_measurement(iint, pathname); + ima_audit_measurement(iint, pathname, ns_status); if ((file->f_flags & O_DIRECT) && (iint->flags & IMA_PERMIT_DIRECTIO)) rc = 0; diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index b7d5ca108900..dbe9f36d3692 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -171,6 +171,9 @@ struct integrity_iint_cache { */ rwlock_t ns_list_lock; struct list_head ns_list; +#ifndef CONFIG_IMA_NS + struct ns_status ns_status; +#endif }; /* rbtree tree calls to lookup, insert, delete From patchwork Tue Jan 25 22:46:42 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724299 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 09267C43219 for ; Tue, 25 Jan 2022 22:47:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234237AbiAYWrj (ORCPT ); Tue, 25 Jan 2022 17:47:39 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:36446 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234206AbiAYWr1 (ORCPT ); Tue, 25 Jan 2022 17:47:27 -0500 Received: from pps.filterd (m0098396.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PMZoZY025028; Tue, 25 Jan 2022 22:47:03 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=CAXpUMzsSCYKTR7gjYdFhRw6+nJu3eqXo1Nr5p5G/3s=; b=lx90vT6E9s7+QmnVh4Qtt/DW3GWgXMh9lX8mo865kFGYQ4IqGjPZaeGTPwV/2dHTAekl cziHVMGTd+NBa/PO3nrup6ZdmnNYdjMIF4BKFeXXFBf7IEPh/BpkjcPex+dH8ZtYknsR cdkog2VtK/2f377F20ycKcEDVplbijGNkcNfC0hNpRAf+86FGDZXAhCMV/ugLc6P+v5Y nwm5aF9n8EoWsF1e7L7qos9H/9X0EeMkcXu/ZWtf4rxr/1j9t2LqngNBq2Kip4vOnUNu Qq1A5/g7LozBktoEZOiJ+yKr4PGszeNWXxVM/X3x+85bb/sOTP97+WGY8+mXRJLuKMRV bw== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtsvfgb81-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:03 +0000 Received: from m0098396.ppops.net (m0098396.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMd3FZ008302; Tue, 25 Jan 2022 22:47:02 GMT Received: from ppma04dal.us.ibm.com (7a.29.35a9.ip4.static.sl-reverse.com [169.53.41.122]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtsvfgb7h-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:02 +0000 Received: from pps.filterd (ppma04dal.us.ibm.com [127.0.0.1]) by ppma04dal.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMhEDX008689; Tue, 25 Jan 2022 22:47:01 GMT Received: from b01cxnp23034.gho.pok.ibm.com (b01cxnp23034.gho.pok.ibm.com [9.57.198.29]) by ppma04dal.us.ibm.com with ESMTP id 3dr9japd68-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:01 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23034.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkxZ630605636 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:59 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 5FC98AC059; Tue, 25 Jan 2022 22:46:59 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 3EB2AAC05B; Tue, 25 Jan 2022 22:46:59 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:59 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger , James Bottomley Subject: [PATCH v9 20/23] ima: Setup securityfs for IMA namespace Date: Tue, 25 Jan 2022 17:46:42 -0500 Message-Id: <20220125224645.79319-21-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: O7JHHcFMokKT_pxygNJ7q8RDtgUBN-RW X-Proofpoint-ORIG-GUID: JUgkInAkNMEncwA_fnEE9hi_u30pZsmr X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_05,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxlogscore=999 bulkscore=0 mlxscore=0 phishscore=0 spamscore=0 clxscore=1011 malwarescore=0 adultscore=0 suspectscore=0 priorityscore=1501 lowpriorityscore=0 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger Setup securityfs with symlinks, directories, and files for IMA namespacing support. The same directory structure that IMA uses on the host is also created for the namespacing case. The securityfs file and directory ownerships cannot be set when the IMA namespace is initialized. Therefore, delay the setup of the file system to a later point when securityfs is in securityfs_fill_super. Introduce a variable ima_policy_removed in ima_namespace that is used to remember whether the policy file has previously been removed and thus should not be created again in case of unmounting and again mounting securityfs inside an IMA namespace. This filesystem can now be mounted as follows: mount -t securityfs /sys/kernel/security/ /sys/kernel/security/ The following directories, symlinks, and files are available when IMA namespacing is enabled, otherwise it will be empty: $ ls -l sys/kernel/security/ total 0 lr--r--r--. 1 root root 0 Dec 2 00:18 ima -> integrity/ima drwxr-xr-x. 3 root root 0 Dec 2 00:18 integrity $ ls -l sys/kernel/security/ima/ total 0 -r--r-----. 1 root root 0 Dec 2 00:18 ascii_runtime_measurements -r--r-----. 1 root root 0 Dec 2 00:18 binary_runtime_measurements -rw-------. 1 root root 0 Dec 2 00:18 policy -r--r-----. 1 root root 0 Dec 2 00:18 runtime_measurements_count -r--r-----. 1 root root 0 Dec 2 00:18 violations Signed-off-by: Stefan Berger Signed-off-by: James Bottomley Acked-by: Christian Brauner --- v9: - rename policy_dentry_removed to ima_policy_removed --- include/linux/ima.h | 13 +++++++++++ security/inode.c | 6 ++++- security/integrity/ima/ima.h | 1 + security/integrity/ima/ima_fs.c | 41 ++++++++++++++++++++++++--------- 4 files changed, 49 insertions(+), 12 deletions(-) diff --git a/include/linux/ima.h b/include/linux/ima.h index 2fe32f1bf84b..c584527c0f47 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -41,6 +41,7 @@ extern int ima_measure_critical_data(const char *event_label, const char *event_name, const void *buf, size_t buf_len, bool hash, u8 *digest, size_t digest_len); +extern int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root); #ifdef CONFIG_IMA_APPRAISE_BOOTPARAM extern void ima_appraise_parse_cmdline(void); @@ -227,6 +228,12 @@ void free_ima_ns(struct user_namespace *ns); void ima_free_ns_status_list(struct list_head *head, rwlock_t *ns_list_lock); +static inline int ima_securityfs_init(struct user_namespace *user_ns, + struct dentry *root) +{ + return ima_fs_ns_init(user_ns, root); +} + #else static inline void free_ima_ns(struct user_namespace *user_ns) @@ -238,6 +245,12 @@ static inline void ima_free_ns_status_list(struct list_head *head, { } +static inline int ima_securityfs_init(struct user_namespace *ns, + struct dentry *root) +{ + return 0; +} + #endif /* CONFIG_IMA_NS */ #endif /* _LINUX_IMA_H */ diff --git a/security/inode.c b/security/inode.c index e525ba960063..cdb08520151c 100644 --- a/security/inode.c +++ b/security/inode.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -81,7 +82,10 @@ static int securityfs_fill_super(struct super_block *sb, struct fs_context *fc) sb->s_op = &securityfs_super_operations; sb->s_root->d_inode->i_op = &securityfs_dir_inode_operations; - return 0; + if (ns != &init_user_ns) + error = ima_securityfs_init(ns, sb->s_root); + + return error; } static int securityfs_get_tree(struct fs_context *fc) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 883aeb30590f..a52b388b4157 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -148,6 +148,7 @@ struct ima_namespace { int valid_policy; struct dentry *ima_policy; + bool ima_policy_removed; struct notifier_block ima_lsm_policy_notifier; } __randomize_layout; diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 9162f06d182f..5dd0e759a470 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "ima.h" @@ -433,6 +434,7 @@ static int ima_release_policy(struct inode *inode, struct file *file) #if !defined(CONFIG_IMA_WRITE_POLICY) && !defined(CONFIG_IMA_READ_POLICY) securityfs_remove(ns->ima_policy); ns->ima_policy = NULL; + ns->ima_policy_removed = true; #elif defined(CONFIG_IMA_WRITE_POLICY) clear_bit(IMA_FS_BUSY, &ns->ima_fs_flags); #elif defined(CONFIG_IMA_READ_POLICY) @@ -449,20 +451,31 @@ static const struct file_operations ima_measure_policy_ops = { .llseek = generic_file_llseek, }; -static int __init ima_fs_ns_init(struct ima_namespace *ns) +int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root) { - struct dentry *ima_dir; + struct ima_namespace *ns = ima_ns_from_user_ns(user_ns); + struct dentry *int_dir; + struct dentry *ima_dir = NULL; struct dentry *ima_symlink = NULL; struct dentry *binary_runtime_measurements = NULL; struct dentry *ascii_runtime_measurements = NULL; struct dentry *runtime_measurements_count = NULL; struct dentry *violations = NULL; - ima_dir = securityfs_create_dir("ima", integrity_dir); + /* FIXME: update when evm and integrity are namespaced */ + if (user_ns != &init_user_ns) { + int_dir = securityfs_create_dir("integrity", root); + if (IS_ERR(int_dir)) + return PTR_ERR(int_dir); + } else { + int_dir = integrity_dir; + } + + ima_dir = securityfs_create_dir("ima", int_dir); if (IS_ERR(ima_dir)) - return -1; + goto out; - ima_symlink = securityfs_create_symlink("ima", NULL, "integrity/ima", + ima_symlink = securityfs_create_symlink("ima", root, "integrity/ima", NULL); if (IS_ERR(ima_symlink)) goto out; @@ -494,11 +507,14 @@ static int __init ima_fs_ns_init(struct ima_namespace *ns) if (IS_ERR(violations)) goto out; - ns->ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS, - ima_dir, NULL, - &ima_measure_policy_ops); - if (IS_ERR(ns->ima_policy)) - goto out; + if (!ns->ima_policy_removed) { + ns->ima_policy = + securityfs_create_file("policy", POLICY_FILE_FLAGS, + ima_dir, NULL, + &ima_measure_policy_ops); + if (IS_ERR(ns->ima_policy)) + goto out; + } return 0; out: @@ -509,10 +525,13 @@ static int __init ima_fs_ns_init(struct ima_namespace *ns) securityfs_remove(binary_runtime_measurements); securityfs_remove(ima_symlink); securityfs_remove(ima_dir); + if (user_ns != &init_user_ns) + securityfs_remove(int_dir); + return -1; } int __init ima_fs_init(void) { - return ima_fs_ns_init(&init_ima_ns); + return ima_fs_ns_init(&init_user_ns, NULL); } From patchwork Tue Jan 25 22:46:43 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724294 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8E38AC4167E for ; Tue, 25 Jan 2022 22:47:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234168AbiAYWre (ORCPT ); Tue, 25 Jan 2022 17:47:34 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:28594 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234199AbiAYWrZ (ORCPT ); Tue, 25 Jan 2022 17:47:25 -0500 Received: from pps.filterd (m0098409.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PMfj6t011040; Tue, 25 Jan 2022 22:47:03 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=369+3T91DjlWnaCaA0PLNFxxrjOgsi4pNFXhE+Rj8uU=; b=XPEbDgvF8693UDqgMotxivQXur5f5OfnPMWVtrrws4lSn5orn94UcX1FRgOoOVSeZ48H qFgwoTOERwiXId5Sy4n9cKFKt578uZOq5MnoBYT3WbuCl4aJ1TTU0k5S34x6izqyeHoW ICy99wIRxqUmsdv+bIb7wlEOgKSp5SiVhXFEZ8r1fvx82yqAK05+UCdyEHn1xwU+3+yP /XtbIeRpxXwJbL236zqTZV2y8Nzorku1Qp6IRJS3pHlq+u/4/Pk12D4Un04i7e3RgnfD qqQ3QWmkPVoS8J++nFnGesakkq1doLDwjkphGE1wSkxwJ2I7D5uv+k1KHyE6dWXgLTkB Fw== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtt7ng2fw-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:03 +0000 Received: from m0098409.ppops.net (m0098409.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMferT010835; Tue, 25 Jan 2022 22:47:02 GMT Received: from ppma05wdc.us.ibm.com (1b.90.2fa9.ip4.static.sl-reverse.com [169.47.144.27]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtt7ng2fj-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:02 +0000 Received: from pps.filterd (ppma05wdc.us.ibm.com [127.0.0.1]) by ppma05wdc.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMhoik010375; Tue, 25 Jan 2022 22:47:01 GMT Received: from b01cxnp23034.gho.pok.ibm.com (b01cxnp23034.gho.pok.ibm.com [9.57.198.29]) by ppma05wdc.us.ibm.com with ESMTP id 3dtbch8rg7-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:01 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23034.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkx9P30605638 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:59 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 77738AC05B; Tue, 25 Jan 2022 22:46:59 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 645CFAC05E; Tue, 25 Jan 2022 22:46:59 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:59 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger Subject: [PATCH v9 21/23] ima: Introduce securityfs file to activate an IMA namespace Date: Tue, 25 Jan 2022 17:46:43 -0500 Message-Id: <20220125224645.79319-22-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: Rr1XYM75bxcaDK2EZCPaqJgXjskGiVoH X-Proofpoint-ORIG-GUID: gNsnAds2jdbJjZM2OSx2yq3NWWkpP0KA X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_06,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 suspectscore=0 phishscore=0 impostorscore=0 bulkscore=0 priorityscore=1501 lowpriorityscore=0 mlxscore=0 spamscore=0 clxscore=1015 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger Introduce securityfs file 'active' that allows a user to activate an IMA namespace by writing a "1" (precisely a '1\0' or '1\n') to it. When reading from the file, it shows either '0' or '1'. Also, introduce ns_is_active() to be used in those places where the ima_namespace pointer may either be NULL or where the active field may not have been set to '1', yet. An inactive IMA namespace should never be accessed since it has not been initialized, yet. Set the init_ima_ns's active field to '1' since it is considered active right from the beginning. The rationale for introducing a file to activate an IMA namespace is that subsequent support for IMA-measurement and IMA-appraisal will add configuration files for selecting for example the template that an IMA namespace is supposed to use for logging measurements, which will add an IMA namespace configuration stage (using securityfs files) before its activation. Signed-off-by: Stefan Berger --- security/integrity/ima/ima.h | 7 +++ security/integrity/ima/ima_fs.c | 59 ++++++++++++++++++++++++ security/integrity/ima/ima_init_ima_ns.c | 1 + security/integrity/ima/ima_main.c | 2 +- 4 files changed, 68 insertions(+), 1 deletion(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index a52b388b4157..cf2f63bb5bdf 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -123,6 +123,8 @@ struct ima_h_table { }; struct ima_namespace { + atomic_t active; /* whether namespace is active */ + struct rb_root ns_status_tree; rwlock_t ns_tree_lock; struct kmem_cache *ns_status_cache; @@ -154,6 +156,11 @@ struct ima_namespace { } __randomize_layout; extern struct ima_namespace init_ima_ns; +static inline bool ns_is_active(struct ima_namespace *ns) +{ + return (ns && atomic_read(&ns->active)); +} + extern const int read_idmap[]; #ifdef CONFIG_HAVE_IMA_KEXEC diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 5dd0e759a470..79a786db79db 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -451,6 +451,62 @@ static const struct file_operations ima_measure_policy_ops = { .llseek = generic_file_llseek, }; +static ssize_t ima_show_active(struct file *filp, + char __user *buf, + size_t count, loff_t *ppos) +{ + struct ima_namespace *ns = &init_ima_ns; + char tmpbuf[2]; + ssize_t len; + + len = scnprintf(tmpbuf, sizeof(tmpbuf), + "%d\n", atomic_read(&ns->active)); + return simple_read_from_buffer(buf, count, ppos, tmpbuf, len); +} + +static ssize_t ima_write_active(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct ima_namespace *ns = &init_ima_ns; + unsigned int active; + char tmpbuf[3]; + ssize_t ret; + + if (ns_is_active(ns)) + return -EBUSY; + + ret = simple_write_to_buffer(tmpbuf, sizeof(tmpbuf) - 1, ppos, + buf, count); + if (ret < 0) + return ret; + tmpbuf[ret] = 0; + + if (!kstrtouint(tmpbuf, 10, &active) && active == 1) + atomic_set(&ns->active, 1); + + return count; +} + +static const struct file_operations ima_active_ops = { + .read = ima_show_active, + .write = ima_write_active, +}; + +static int ima_fs_add_ns_files(struct dentry *ima_dir) +{ + struct dentry *active; + + active = + securityfs_create_file("active", + S_IRUSR | S_IWUSR | S_IRGRP, ima_dir, NULL, + &ima_active_ops); + if (IS_ERR(active)) + return PTR_ERR(active); + + return 0; +} + int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root) { struct ima_namespace *ns = ima_ns_from_user_ns(user_ns); @@ -516,6 +572,9 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root) goto out; } + if (ns != &init_ima_ns && ima_fs_add_ns_files(ima_dir)) + goto out; + return 0; out: securityfs_remove(ns->ima_policy); diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c index d4ddfd1de60b..39ee0c2477a6 100644 --- a/security/integrity/ima/ima_init_ima_ns.c +++ b/security/integrity/ima/ima_init_ima_ns.c @@ -58,5 +58,6 @@ struct ima_namespace init_ima_ns = { .ima_lsm_policy_notifier = { .notifier_call = ima_lsm_policy_change, }, + .active = ATOMIC_INIT(1), }; EXPORT_SYMBOL(init_ima_ns); diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 8018e9aaad32..059917182960 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -441,7 +441,7 @@ static int process_measurement(struct user_namespace *user_ns, while (user_ns) { ns = ima_ns_from_user_ns(user_ns); - if (ns) { + if (ns_is_active(ns)) { int rc; rc = __process_measurement(ns, file, cred, secid, buf, From patchwork Tue Jan 25 22:46:44 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724311 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C2E23C3527D for ; Tue, 25 Jan 2022 22:47:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234351AbiAYWrs (ORCPT ); Tue, 25 Jan 2022 17:47:48 -0500 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:20510 "EHLO mx0b-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234227AbiAYWr3 (ORCPT ); Tue, 25 Jan 2022 17:47:29 -0500 Received: from pps.filterd (m0098421.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PMkL7B000430; Tue, 25 Jan 2022 22:47:04 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=Ky/ABeLzJYYv8wAwevKOfcW2yogVuYyI5RvYcWCzMsQ=; b=QAIG3PFZNs81qW7UJtVqwo0w8VcVKz+8+vuQFbYUBEW2cSMv2ulTQWZuAa94H0HdKei9 NA5NKmnTNz8KghOzleB2HOT25ByTeXJ2yhZ9j6MRgikTx+XgvikvLsfAC80t3ZiIs8jc PupQQYjpWzPLFOxmY6Oe5Y+obcG6bCoOoBoSDEF1ijBJvLONF0XF3gbMnorrYtZmdWnw 7fpmyhV9bG8jNAkrHzAKSHIpgJhNeDEN9dKLJcHNV9DYL6Q6uPLhKzYCObsmJv93fd97 FeSt50R2BquohrIKFjxg72/p/8gyrdQnAwVx98x7PQBdZ95NsU/n/QrCp4E/ZUSIH4bC 6Q== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtt9wr0bm-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:04 +0000 Received: from m0098421.ppops.net (m0098421.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMl4BK001736; Tue, 25 Jan 2022 22:47:04 GMT Received: from ppma04dal.us.ibm.com (7a.29.35a9.ip4.static.sl-reverse.com [169.53.41.122]) by mx0a-001b2d01.pphosted.com with ESMTP id 3dtt9wr0b5-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:03 +0000 Received: from pps.filterd (ppma04dal.us.ibm.com [127.0.0.1]) by ppma04dal.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMhDWf008667; Tue, 25 Jan 2022 22:47:03 GMT Received: from b01cxnp23034.gho.pok.ibm.com (b01cxnp23034.gho.pok.ibm.com [9.57.198.29]) by ppma04dal.us.ibm.com with ESMTP id 3dr9japd6n-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:02 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23034.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkxbh30605640 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:59 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 843ADAC059; Tue, 25 Jan 2022 22:46:59 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 7BF7AAC064; Tue, 25 Jan 2022 22:46:59 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:59 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger Subject: [PATCH v9 22/23] ima: Show owning user namespace's uid and gid when displaying policy Date: Tue, 25 Jan 2022 17:46:44 -0500 Message-Id: <20220125224645.79319-23-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: av4MuksJ14vpA_sAQbEY6XWCga9no2bX X-Proofpoint-ORIG-GUID: DHDnJssSd0ua22jbabLTm0khJFQwexpB X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_06,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 priorityscore=1501 malwarescore=0 bulkscore=0 phishscore=0 mlxscore=0 spamscore=0 impostorscore=0 mlxlogscore=999 lowpriorityscore=0 suspectscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger Show the uid and gid values relative to the user namespace that is currently active. The effect of this changes is that when one displays the policy from the user namespace that originally set the policy, the same uid and gid values are shown in the policy as those that were used when the policy was set. Signed-off-by: Stefan Berger Acked-by: Christian Brauner --- v9: - use seq_user_ns and from_k{g,u}id_munged() --- 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 47f2d1b5d156..151f418036ee 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -2002,6 +2002,7 @@ static void ima_policy_show_appraise_algos(struct seq_file *m, int ima_policy_show(struct seq_file *m, void *v) { + struct user_namespace *user_ns = seq_user_ns(m); struct ima_rule_entry *entry = v; int i; char tbuf[64] = {0,}; @@ -2087,7 +2088,8 @@ int ima_policy_show(struct seq_file *m, void *v) } if (entry->flags & IMA_UID) { - snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid)); + snprintf(tbuf, sizeof(tbuf), + "%d", from_kuid_munged(user_ns, entry->uid)); if (entry->uid_op == &uid_gt) seq_printf(m, pt(Opt_uid_gt), tbuf); else if (entry->uid_op == &uid_lt) @@ -2098,7 +2100,8 @@ int ima_policy_show(struct seq_file *m, void *v) } if (entry->flags & IMA_EUID) { - snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid)); + snprintf(tbuf, sizeof(tbuf), + "%d", from_kuid_munged(user_ns, entry->uid)); if (entry->uid_op == &uid_gt) seq_printf(m, pt(Opt_euid_gt), tbuf); else if (entry->uid_op == &uid_lt) @@ -2109,7 +2112,8 @@ int ima_policy_show(struct seq_file *m, void *v) } if (entry->flags & IMA_GID) { - snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->gid)); + snprintf(tbuf, sizeof(tbuf), + "%d", from_kgid_munged(user_ns, entry->gid)); if (entry->gid_op == &gid_gt) seq_printf(m, pt(Opt_gid_gt), tbuf); else if (entry->gid_op == &gid_lt) @@ -2120,7 +2124,8 @@ int ima_policy_show(struct seq_file *m, void *v) } if (entry->flags & IMA_EGID) { - snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->gid)); + snprintf(tbuf, sizeof(tbuf), + "%d", from_kgid_munged(user_ns, entry->gid)); if (entry->gid_op == &gid_gt) seq_printf(m, pt(Opt_egid_gt), tbuf); else if (entry->gid_op == &gid_lt) @@ -2131,7 +2136,8 @@ int ima_policy_show(struct seq_file *m, void *v) } if (entry->flags & IMA_FOWNER) { - snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner)); + snprintf(tbuf, sizeof(tbuf), + "%d", from_kuid_munged(user_ns, entry->fowner)); if (entry->fowner_op == &uid_gt) seq_printf(m, pt(Opt_fowner_gt), tbuf); else if (entry->fowner_op == &uid_lt) @@ -2142,7 +2148,8 @@ int ima_policy_show(struct seq_file *m, void *v) } if (entry->flags & IMA_FGROUP) { - snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->fgroup)); + snprintf(tbuf, sizeof(tbuf), + "%d", from_kgid_munged(user_ns, entry->fgroup)); if (entry->fgroup_op == &gid_gt) seq_printf(m, pt(Opt_fgroup_gt), tbuf); else if (entry->fgroup_op == &gid_lt) From patchwork Tue Jan 25 22:46:45 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 12724352 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 701FDC5DF62 for ; Tue, 25 Jan 2022 23:09:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234273AbiAYWrm (ORCPT ); Tue, 25 Jan 2022 17:47:42 -0500 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:12368 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S234218AbiAYWr2 (ORCPT ); Tue, 25 Jan 2022 17:47:28 -0500 Received: from pps.filterd (m0098416.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 20PMh0vw011541; Tue, 25 Jan 2022 22:47:05 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=0vN/OnpNxs2gxrQFo4ydOTrn69NRjrKOtMZh3Q4N+Js=; b=UxL+JZ2+j0oUZEwBpvjx5pPDKUqsQH3ABb658S2Nmlc4YvuqjyGJ2nVcCDT+IWAxpquI CIe+aM+6kTFw9QlskC3dylczHOhrnYSqYIEotJg1No4wKaYxE/kyP/gFMdDkG8AP5jm3 /GuZXLlBi9QtbPfHVQ9Z8od6hDEzorVukG8Ci4PVY+PEXcZQQ0oyWrJZbDi+KdLtfBLp HJbM5/tHMDvuCe/KPLrReNXsMOJyr9cbMW4YeSXIo2K7kKnOX+3DH5+E16PSWzsUY4yx yNq86bo3ubygt09f7gYS4PToJarEPTSwCtlfSsDCD6JuCDBONXmXJ3wmu9c9ThsawTy3 bQ== Received: from pps.reinject (localhost [127.0.0.1]) by mx0b-001b2d01.pphosted.com with ESMTP id 3dtt83g1v9-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:05 +0000 Received: from m0098416.ppops.net (m0098416.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 20PMhC3H012543; Tue, 25 Jan 2022 22:47:04 GMT Received: from ppma02dal.us.ibm.com (a.bd.3ea9.ip4.static.sl-reverse.com [169.62.189.10]) by mx0b-001b2d01.pphosted.com with ESMTP id 3dtt83g1uy-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:04 +0000 Received: from pps.filterd (ppma02dal.us.ibm.com [127.0.0.1]) by ppma02dal.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 20PMh3Mr011257; Tue, 25 Jan 2022 22:47:03 GMT Received: from b01cxnp23034.gho.pok.ibm.com (b01cxnp23034.gho.pok.ibm.com [9.57.198.29]) by ppma02dal.us.ibm.com with ESMTP id 3dt1x9rg8u-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 25 Jan 2022 22:47:03 +0000 Received: from b01ledav006.gho.pok.ibm.com (b01ledav006.gho.pok.ibm.com [9.57.199.111]) by b01cxnp23034.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 20PMkxgs31719798 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jan 2022 22:46:59 GMT Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C47D2AC068; Tue, 25 Jan 2022 22:46:59 +0000 (GMT) Received: from b01ledav006.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 93EC1AC05E; Tue, 25 Jan 2022 22:46:59 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b01ledav006.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 25 Jan 2022 22:46:59 +0000 (GMT) From: Stefan Berger To: linux-integrity@vger.kernel.org Cc: zohar@linux.ibm.com, serge@hallyn.com, christian.brauner@ubuntu.com, containers@lists.linux.dev, dmitry.kasatkin@gmail.com, ebiederm@xmission.com, krzysztof.struczynski@huawei.com, roberto.sassu@huawei.com, mpeters@redhat.com, lhinds@redhat.com, lsturman@redhat.com, puiterwi@redhat.com, jejb@linux.ibm.com, jamjoom@us.ibm.com, linux-kernel@vger.kernel.org, paul@paul-moore.com, rgb@redhat.com, linux-security-module@vger.kernel.org, jmorris@namei.org, Stefan Berger Subject: [PATCH v9 23/23] ima: Enable IMA namespaces Date: Tue, 25 Jan 2022 17:46:45 -0500 Message-Id: <20220125224645.79319-24-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> References: <20220125224645.79319-1-stefanb@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: grqyLkGugVKLiWcMKy70l8R11h_vfkiJ X-Proofpoint-GUID: vGO_ywtuqZ0AMPqbdjSjap4nfpVs1T8M X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-25_06,2022-01-25_02,2021-12-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 mlxscore=0 phishscore=0 lowpriorityscore=0 spamscore=0 malwarescore=0 adultscore=0 priorityscore=1501 clxscore=1015 bulkscore=0 impostorscore=0 mlxlogscore=999 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2201110000 definitions=main-2201250135 Precedence: bulk List-ID: From: Stefan Berger Introduce the IMA_NS in Kconfig for IMA namespace enablement. Enable the lazy initialization of an IMA namespace when a user mounts SecurityFS and writes '1' into IMA's 'active' securityfs file. A user_namespace will now get a pointer to an ima_namespace and therefore implement get_current_ns() for the namespacing case that returns this pointer. Use get_current_ns() in those places that require access to the current IMA namespace. In some places, primarily those related to IMA-appraisal and changes to file attributes, keep the pointer to init_ima_ns, since there flags related to file measurements may be affected, which are not supported in IMA namespaces, yet. Before using the ima_namespace pointer test it with ns_is_active() to check whether it is NULL and whether the ima_namespace is active. If it's not active, it cannot be used, yet. Therefore, return early from those functions that may now get either get a NULL pointer from this call or where ns->active is still 0. The init_ima_ns is always set to be active, thus passing the check. Implement ima_ns_from_file() for SecurityFS-related files where we can now get the IMA namespace via the user namespace pointer associated with the superblock of the SecurityFS filesystem instance. Return -EACCES to IMA's securityfs files, except for the 'active' file, until the IMA namespace has been set to active. Switch access to userns->ima_ns to use acquire/release semantics to ensure that a newly created ima_namespace structure is fully visible upon access. Only emit the kernel log message 'policy update completed' for the init_ima_ns. Gate access to ima_appraise variable to init_ima_ns in ima_load_data(). Signed-off-by: Stefan Berger --- v9: - ima_post_key_create_or_update: Only handle key if in init_ima_ns - Removed ns == NULL checks where user_namespace is now passed - Defer setting of user_ns->ima_ns until end of ima_fs_ns_init(); required new ima_free_imans() and new user_ns_set_ima_ns() - Only emit log message 'policy update completed' for init_ima_ns - Introduce get_current_ns() only in this patch - Check for ns == &init_ima_ns in ima_load_data() --- include/linux/ima.h | 13 ++++ init/Kconfig | 13 ++++ kernel/user_namespace.c | 2 + security/integrity/ima/ima.h | 51 ++++++++++++-- security/integrity/ima/ima_appraise.c | 3 + security/integrity/ima/ima_asymmetric_keys.c | 6 +- security/integrity/ima/ima_fs.c | 74 ++++++++++++++++---- security/integrity/ima/ima_init_ima_ns.c | 2 + security/integrity/ima/ima_main.c | 35 +++++---- security/integrity/ima/ima_ns.c | 15 ++-- security/integrity/ima/ima_policy.c | 16 +++-- 11 files changed, 188 insertions(+), 42 deletions(-) diff --git a/include/linux/ima.h b/include/linux/ima.h index c584527c0f47..4e595bd9733e 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -11,6 +11,7 @@ #include #include #include +#include #include struct linux_binprm; @@ -68,6 +69,18 @@ static inline const char * const *arch_get_ima_policy(void) } #endif +static inline struct user_namespace +*ima_ns_to_user_ns(struct ima_namespace *ns) +{ + struct user_namespace *user_ns; + + user_ns = current_user_ns(); +#ifdef CONFIG_IMA_NS + WARN_ON(user_ns->ima_ns != ns); +#endif + return user_ns; +} + #else static inline enum hash_algo ima_get_current_hash_algo(void) { diff --git a/init/Kconfig b/init/Kconfig index 4b7bac10c72d..e27155e0ddba 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1247,6 +1247,19 @@ config NET_NS Allow user space to create what appear to be multiple instances of the network stack. +config IMA_NS + bool "IMA namespace" + depends on USER_NS + depends on IMA + default n + help + Allow the creation of an IMA namespace for each user namespace. + Namespaced IMA enables having IMA features work separately + in each IMA namespace. + Currently, only the audit status flags are stored in the namespace, + which allows the same file to be audited each time it is accessed + in a new namespace. + endif # NAMESPACES config CHECKPOINT_RESTORE diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 6b2e3ca7ee99..653f8fa83b69 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -20,6 +20,7 @@ #include #include #include +#include static struct kmem_cache *user_ns_cachep __read_mostly; static DEFINE_MUTEX(userns_state_mutex); @@ -196,6 +197,7 @@ static void free_user_ns(struct work_struct *work) kfree(ns->projid_map.forward); kfree(ns->projid_map.reverse); } + free_ima_ns(ns); retire_userns_sysctls(ns); key_free_user_ns(ns); ns_free_inum(&ns->ns); diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index cf2f63bb5bdf..a0dbb1dccc8e 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -536,32 +536,70 @@ struct user_namespace *ima_user_ns_from_file(const struct file *filp) return file_inode(filp)->i_sb->s_user_ns; } +#ifdef CONFIG_IMA_NS + static inline struct ima_namespace *ima_ns_from_user_ns(struct user_namespace *user_ns) { - if (user_ns == &init_user_ns) - return &init_ima_ns; - return NULL; + /* Pairs with smp_store_releases() in user_ns_set_ima_ns(). */ + return smp_load_acquire(&user_ns->ima_ns); } -#ifdef CONFIG_IMA_NS +static inline void user_ns_set_ima_ns(struct user_namespace *user_ns, + struct ima_namespace *ns) +{ + /* Pairs with smp_load_acquire() in ima_ns_from_user_ns() */ + smp_store_release(&user_ns->ima_ns, ns); +} + +static inline struct ima_namespace *get_current_ns(void) +{ + return ima_ns_from_user_ns(current_user_ns()); +} struct ima_namespace *create_ima_ns(void); +void ima_free_ima_ns(struct ima_namespace *ns); + struct ns_status *ima_get_ns_status(struct ima_namespace *ns, struct inode *inode, struct integrity_iint_cache *iint); void ima_free_ns_status_tree(struct ima_namespace *ns); +static inline struct ima_namespace *ima_ns_from_file(const struct file *filp) +{ + return ima_user_ns_from_file(filp)->ima_ns; +} + #else +static inline struct ima_namespace +*ima_ns_from_user_ns(struct user_namespace *user_ns) +{ + if (user_ns == &init_user_ns) + return &init_ima_ns; + return NULL; +} + +static inline void user_ns_set_ima_ns(struct user_namespace *user_ns, + struct ima_namespace *ns) +{ +} + +static inline struct ima_namespace *get_current_ns(void) +{ + return &init_ima_ns; +} + static inline struct ima_namespace *create_ima_ns(void) { WARN(1, "Cannot create an IMA namespace\n"); return ERR_PTR(-EFAULT); } +static inline void ima_free_ima_ns(struct ima_namespace *ns) {} + static inline struct ns_status *ima_get_ns_status(struct ima_namespace *ns, struct inode *inode, struct integrity_iint_cache *iint) @@ -576,6 +614,11 @@ static inline struct ns_status *ima_get_ns_status(struct ima_namespace *ns, return ns_status; } +static inline struct ima_namespace *ima_ns_from_file(const struct file *filp) +{ + return &init_ima_ns; +} + #endif /* CONFIG_IMA_NS */ #endif /* __LINUX_IMA_H */ diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 3461025f671b..2ad3327d7ce6 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -74,6 +74,9 @@ int ima_must_appraise(struct ima_namespace *ns, { u32 secid; + if (ns != &init_ima_ns) + return 0; + if (!ima_appraise) return 0; diff --git a/security/integrity/ima/ima_asymmetric_keys.c b/security/integrity/ima/ima_asymmetric_keys.c index 70d87df26068..0d2cc1e23cde 100644 --- a/security/integrity/ima/ima_asymmetric_keys.c +++ b/security/integrity/ima/ima_asymmetric_keys.c @@ -30,9 +30,13 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key, const void *payload, size_t payload_len, unsigned long flags, bool create) { - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns = get_current_ns(); bool queued = false; + /* only handle key if related to init_ima_ns */ + if (ns != &init_ima_ns) + return; + /* Only asymmetric keys are handled by this hook. */ if (key->type != &key_type_asymmetric) return; diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 79a786db79db..f6fd3abcaebf 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -49,7 +49,10 @@ static ssize_t ima_show_htable_violations(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns = ima_ns_from_file(filp); + + if (!ns_is_active(ns)) + return -EACCES; return ima_show_htable_value(buf, count, ppos, &ns->ima_htable.violations); @@ -64,7 +67,10 @@ static ssize_t ima_show_measurements_count(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns = ima_ns_from_file(filp); + + if (!ns_is_active(ns)) + return -EACCES; return ima_show_htable_value(buf, count, ppos, &ns->ima_htable.len); } @@ -77,7 +83,7 @@ static const struct file_operations ima_measurements_count_ops = { /* returns pointer to hlist_node */ static void *ima_measurements_start(struct seq_file *m, loff_t *pos) { - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns = ima_ns_from_file(m->file); loff_t l = *pos; struct ima_queue_entry *qe; @@ -95,7 +101,7 @@ static void *ima_measurements_start(struct seq_file *m, loff_t *pos) static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos) { - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns = ima_ns_from_file(m->file); struct ima_queue_entry *qe = v; /* lock protects when reading beyond last element @@ -198,6 +204,11 @@ static const struct seq_operations ima_measurments_seqops = { static int ima_measurements_open(struct inode *inode, struct file *file) { + struct ima_namespace *ns = ima_ns_from_file(file); + + if (!ns_is_active(ns)) + return -EACCES; + return seq_open(file, &ima_measurments_seqops); } @@ -264,6 +275,11 @@ static const struct seq_operations ima_ascii_measurements_seqops = { static int ima_ascii_measurements_open(struct inode *inode, struct file *file) { + struct ima_namespace *ns = ima_ns_from_file(file); + + if (!ns_is_active(ns)) + return -EACCES; + return seq_open(file, &ima_ascii_measurements_seqops); } @@ -317,10 +333,13 @@ static ssize_t ima_read_policy(struct ima_namespace *ns, char *path) static ssize_t ima_write_policy(struct file *file, const char __user *buf, size_t datalen, loff_t *ppos) { - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns = ima_ns_from_file(file); char *data; ssize_t result; + if (!ns_is_active(ns)) + return -EACCES; + if (datalen >= PAGE_SIZE) datalen = PAGE_SIZE - 1; @@ -381,7 +400,10 @@ static int ima_open_policy(struct inode *inode, struct file *filp) #ifdef CONFIG_IMA_READ_POLICY struct user_namespace *user_ns = ima_user_ns_from_file(filp); #endif - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns = ima_ns_from_file(filp); + + if (!ns_is_active(ns)) + return -EACCES; if (!(filp->f_flags & O_WRONLY)) { #ifndef CONFIG_IMA_READ_POLICY @@ -408,7 +430,7 @@ static int ima_open_policy(struct inode *inode, struct file *filp) */ static int ima_release_policy(struct inode *inode, struct file *file) { - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns = ima_ns_from_file(file); const char *cause = ns->valid_policy ? "completed" : "failed"; if ((file->f_flags & O_ACCMODE) == O_RDONLY) @@ -419,7 +441,8 @@ static int ima_release_policy(struct inode *inode, struct file *file) ns->valid_policy = 0; } - pr_info("policy update %s\n", cause); + if (ns == &init_ima_ns) + pr_info("policy update %s\n", cause); integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, "policy_update", cause, !ns->valid_policy, 0); @@ -455,7 +478,7 @@ static ssize_t ima_show_active(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns = ima_ns_from_file(filp); char tmpbuf[2]; ssize_t len; @@ -468,7 +491,7 @@ static ssize_t ima_write_active(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns = ima_ns_from_file(filp); unsigned int active; char tmpbuf[3]; ssize_t ret; @@ -482,8 +505,11 @@ static ssize_t ima_write_active(struct file *filp, return ret; tmpbuf[ret] = 0; - if (!kstrtouint(tmpbuf, 10, &active) && active == 1) - atomic_set(&ns->active, 1); + if (!kstrtouint(tmpbuf, 10, &active) && active == 1) { + ret = ima_init_namespace(ns); + if (ret < 0) + count = -EINVAL; + } return count; } @@ -518,11 +544,26 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root) struct dentry *runtime_measurements_count = NULL; struct dentry *violations = NULL; + /* + * While multiple superblocks can exist they are keyed by userns in + * s_fs_info for securityfs. The first time a userns mounts a + * securityfs instance we lazily allocate the ima_namespace for the + * userns since that's the only way a userns can meaningfully use ima. + * The vfs ensures we're the only one to call fill_super() and hence + * ima_fs_ns_init(), so we don't need any memory barriers here, i.e. + * user_ns->ima_ns can't change while we're in here. + */ + if (!ns) { + ns = create_ima_ns(); + if (IS_ERR(ns)) + return PTR_ERR(ns); + } + /* FIXME: update when evm and integrity are namespaced */ if (user_ns != &init_user_ns) { int_dir = securityfs_create_dir("integrity", root); if (IS_ERR(int_dir)) - return PTR_ERR(int_dir); + goto free_ns; } else { int_dir = integrity_dir; } @@ -575,6 +616,9 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root) if (ns != &init_ima_ns && ima_fs_add_ns_files(ima_dir)) goto out; + if (!ima_ns_from_user_ns(user_ns)) + user_ns_set_ima_ns(user_ns, ns); + return 0; out: securityfs_remove(ns->ima_policy); @@ -587,6 +631,10 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root) if (user_ns != &init_user_ns) securityfs_remove(int_dir); +free_ns: + if (!ima_ns_from_user_ns(user_ns)) + ima_free_ima_ns(ns); + return -1; } diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c index 39ee0c2477a6..0ff587b874bd 100644 --- a/security/integrity/ima/ima_init_ima_ns.c +++ b/security/integrity/ima/ima_init_ima_ns.c @@ -46,6 +46,8 @@ int ima_init_namespace(struct ima_namespace *ns) return rc; } + atomic_set(&ns->active, 1); + return 0; } diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 059917182960..1ffac9c04df1 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -506,7 +506,7 @@ int ima_file_mmap(struct file *file, unsigned long prot) */ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot) { - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns = get_current_ns(); struct ima_template_desc *template = NULL; struct file *file = vma->vm_file; char filename[NAME_MAX]; @@ -519,7 +519,8 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot) int pcr; /* Is mprotect making an mmap'ed file executable? */ - if (!(ns->ima_policy_flag & IMA_APPRAISE) || !vma->vm_file || + if (!ns_is_active(ns) || + !(ns->ima_policy_flag & IMA_APPRAISE) || !vma->vm_file || !(prot & PROT_EXEC) || (vma->vm_flags & VM_EXEC)) return 0; @@ -655,9 +656,9 @@ static int __ima_inode_hash(struct ima_namespace *ns, */ int ima_file_hash(struct file *file, char *buf, size_t buf_size) { - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns = get_current_ns(); - if (!file) + if (!ns_is_active(ns) || !file) return -EINVAL; return __ima_inode_hash(ns, file_inode(file), buf, buf_size); @@ -684,9 +685,9 @@ EXPORT_SYMBOL_GPL(ima_file_hash); */ int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size) { - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns = get_current_ns(); - if (!inode) + if (!ns_is_active(ns) || !inode) return -EINVAL; return __ima_inode_hash(ns, inode, buf, buf_size); @@ -705,11 +706,11 @@ EXPORT_SYMBOL_GPL(ima_inode_hash); void ima_post_create_tmpfile(struct user_namespace *mnt_userns, struct inode *inode) { - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns = get_current_ns(); struct integrity_iint_cache *iint; int must_appraise; - if (!ns->ima_policy_flag || !S_ISREG(inode->i_mode)) + if (!ns_is_active(ns) || !ns->ima_policy_flag || !S_ISREG(inode->i_mode)) return; must_appraise = ima_must_appraise(ns, mnt_userns, inode, MAY_ACCESS, @@ -738,12 +739,12 @@ void ima_post_create_tmpfile(struct user_namespace *mnt_userns, void ima_post_path_mknod(struct user_namespace *mnt_userns, struct dentry *dentry) { - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns = get_current_ns(); struct integrity_iint_cache *iint; struct inode *inode = dentry->d_inode; int must_appraise; - if (!ns->ima_policy_flag || !S_ISREG(inode->i_mode)) + if (!ns_is_active(ns) || !ns->ima_policy_flag || !S_ISREG(inode->i_mode)) return; must_appraise = ima_must_appraise(ns, mnt_userns, inode, MAY_ACCESS, @@ -827,6 +828,7 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, enum kernel_read_file_id read_id) { struct user_namespace *user_ns = current_user_ns(); + struct ima_namespace *ns = ima_ns_from_user_ns(user_ns); enum ima_hooks func; u32 secid; @@ -861,8 +863,12 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, */ int ima_load_data(enum kernel_load_data_id id, bool contents) { + struct ima_namespace *ns = get_current_ns(); bool ima_enforce, sig_enforce; + if (ns != &init_ima_ns) + return 0; + ima_enforce = (ima_appraise & IMA_APPRAISE_ENFORCE) == IMA_APPRAISE_ENFORCE; @@ -1070,10 +1076,10 @@ int process_buffer_measurement(struct ima_namespace *ns, */ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) { - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns = get_current_ns(); struct fd f; - if (!buf || !size) + if (!ns_is_active(ns) || !buf || !size) return; f = fdget(kernel_fd); @@ -1111,7 +1117,10 @@ int ima_measure_critical_data(const char *event_label, const void *buf, size_t buf_len, bool hash, u8 *digest, size_t digest_len) { - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns = get_current_ns(); + + if (!ns_is_active(ns)) + return -EINVAL; if (!event_name || !event_label || !buf || !buf_len) return -ENOPARAM; diff --git a/security/integrity/ima/ima_ns.c b/security/integrity/ima/ima_ns.c index 29af6fea2d74..244dc9d66fb1 100644 --- a/security/integrity/ima/ima_ns.c +++ b/security/integrity/ima/ima_ns.c @@ -26,22 +26,29 @@ struct ima_namespace *create_ima_ns(void) /* destroy_ima_ns() must only be called after ima_init_namespace() was called */ static void destroy_ima_ns(struct ima_namespace *ns) { + atomic_set(&ns->active, 0); unregister_blocking_lsm_notifier(&ns->ima_lsm_policy_notifier); kfree(ns->arch_policy_entry); ima_free_policy_rules(ns); ima_free_ns_status_tree(ns); } -void free_ima_ns(struct user_namespace *user_ns) +void ima_free_ima_ns(struct ima_namespace *ns) { - struct ima_namespace *ns = user_ns->ima_ns; - if (!ns || WARN_ON(ns == &init_ima_ns)) return; - destroy_ima_ns(ns); + if (ns_is_active(ns)) + destroy_ima_ns(ns); kmem_cache_free(imans_cachep, ns); +} + +void free_ima_ns(struct user_namespace *user_ns) +{ + struct ima_namespace *ns = ima_ns_from_user_ns(user_ns); + + ima_free_ima_ns(ns); user_ns->ima_ns = NULL; } diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 151f418036ee..2b8210f0be44 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -471,7 +471,8 @@ int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event, return NOTIFY_DONE; ns = container_of(nb, struct ima_namespace, ima_lsm_policy_notifier); - ima_lsm_update_rules(ns); + if (ns_is_active(ns)) + ima_lsm_update_rules(ns); return NOTIFY_OK; } @@ -1334,6 +1335,7 @@ static unsigned int ima_parse_appraise_algos(char *arg) static int ima_parse_rule(struct ima_namespace *ns, char *rule, struct ima_rule_entry *entry) { + struct user_namespace *user_ns = ima_ns_to_user_ns(ns); struct audit_buffer *ab; char *from; char *p; @@ -1583,7 +1585,7 @@ static int ima_parse_rule(struct ima_namespace *ns, result = kstrtoul(args[0].from, 10, &lnum); if (!result) { - entry->uid = make_kuid(current_user_ns(), + entry->uid = make_kuid(user_ns, (uid_t) lnum); if (!uid_valid(entry->uid) || (uid_t)lnum != lnum) @@ -1618,7 +1620,7 @@ static int ima_parse_rule(struct ima_namespace *ns, result = kstrtoul(args[0].from, 10, &lnum); if (!result) { - entry->gid = make_kgid(current_user_ns(), + entry->gid = make_kgid(user_ns, (gid_t)lnum); if (!gid_valid(entry->gid) || (((gid_t)lnum) != lnum)) @@ -1645,7 +1647,7 @@ static int ima_parse_rule(struct ima_namespace *ns, result = kstrtoul(args[0].from, 10, &lnum); if (!result) { - entry->fowner = make_kuid(current_user_ns(), + entry->fowner = make_kuid(user_ns, (uid_t)lnum); if (!uid_valid(entry->fowner) || (((uid_t)lnum) != lnum)) @@ -1671,7 +1673,7 @@ static int ima_parse_rule(struct ima_namespace *ns, result = kstrtoul(args[0].from, 10, &lnum); if (!result) { - entry->fgroup = make_kgid(current_user_ns(), + entry->fgroup = make_kgid(user_ns, (gid_t)lnum); if (!gid_valid(entry->fgroup) || (((gid_t)lnum) != lnum)) @@ -1925,7 +1927,7 @@ static const char *const mask_tokens[] = { void *ima_policy_start(struct seq_file *m, loff_t *pos) { - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns = ima_ns_from_file(m->file); loff_t l = *pos; struct ima_rule_entry *entry; struct list_head *ima_rules_tmp; @@ -1944,7 +1946,7 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos) void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos) { - struct ima_namespace *ns = &init_ima_ns; + struct ima_namespace *ns = ima_ns_from_file(m->file); struct ima_rule_entry *entry = v; rcu_read_lock();