Message ID | 20240205182506.3569743-5-stefanb@linux.ibm.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel+bounces-53210-ouuuleilei=gmail.com@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7301:168b:b0:106:860b:bbdd with SMTP id ma11csp1061426dyb; Mon, 5 Feb 2024 10:28:30 -0800 (PST) X-Google-Smtp-Source: AGHT+IEtDp+N/7rObiTezUJR9KXohh785W7Ml61I3khpGkEsJQ0E6ljvRruybQEbYHG5j9OM+G5L X-Received: by 2002:ac8:5358:0:b0:42c:768:7b12 with SMTP id d24-20020ac85358000000b0042c07687b12mr750533qto.22.1707157710460; Mon, 05 Feb 2024 10:28:30 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1707157710; cv=pass; d=google.com; s=arc-20160816; b=pCXqvGsyf47VGCi4uaQ2HSsQrb+86wjEDRDbBNm61L4p5n66y7mZ2OlReUPyimugrc BJsxMBTHQDeeBH86hBUtsfnJAn33CsLmPSJK2HHOXS44t4199Rbh7Bm1+oglLXuLhcU9 /eS7NptzW7hIn6JEqOidNPqEEMvNl6tmVcw53+YW9a7muLNO5NA059w3RiO7a/kXfGmw ux8ru5FG4W0KMvwBziuPlsC3iksIf1pRRiSWnYsQ6ne28eMYlfazJRangeIRTnd0u/iJ OpwI4G98Rsed9DGAgPHvoN2iUm4QSbIwGGq/CpL8h9zSn1YipUHxa7v6T9B3C/BlxMj/ wV9A== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=HRVq2c9uSuZERHtMlqfSbAbWFd+PcbFQz/T1bvC8R5Y=; fh=hRQkon/SXLG7wtJ28yc7oFKkUSVwYAk/tiRw4ZyJHcg=; b=qKYJVSJq2/7sUeWV93RzRIxTgRVi0hjC+wbG3sJ3/UZ17khJ7NNZszYRvkPlKVidMC NmtDJ27Egn96K0OH6sKWsplDzwjQQQKNHw5IeGffOEmw2vl9vZmQleCX4YcVwjSy2MDq EOpX1UgnUHE/8VuMaCWDOOmqg8/HxvFp36e4QSR/GgBMjTpqY9hCH7szqUexZCtCVC/E 3FWRMIG975PIqT5tnzoWGALm3zk3inmEu8xmYftzT7bPEEGW65nfKlmbEBki9/lwFqML q4mvI5TSF6NVIgT7ha8yjvkvZHnsH0X6RNBVI9aIS9QMZ3QnMOZpDi89YOiPA+b5XN7o GhYQ==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@ibm.com header.s=pp1 header.b=pt3AQHSx; arc=pass (i=1 spf=pass spfdomain=linux.ibm.com dkim=pass dkdomain=ibm.com dmarc=pass fromdomain=linux.ibm.com); spf=pass (google.com: domain of linux-kernel+bounces-53210-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-53210-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=REJECT sp=NONE dis=NONE) header.from=ibm.com X-Forwarded-Encrypted: i=1; AJvYcCUsArzQMJDbGCy6BB6nRr0ZmQbU1IU8BZXl0Ca+kovISkr6BMCTIMm3F+nRLhcB+USCulcuOAyR5mx2l4wfCWkfICbL4g== Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [2604:1380:45d1:ec00::1]) by mx.google.com with ESMTPS id c5-20020ac85a85000000b0042c32fa63eesi38375qtc.601.2024.02.05.10.28.30 for <ouuuleilei@gmail.com> (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 05 Feb 2024 10:28:30 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-53210-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) client-ip=2604:1380:45d1:ec00::1; Authentication-Results: mx.google.com; dkim=pass header.i=@ibm.com header.s=pp1 header.b=pt3AQHSx; arc=pass (i=1 spf=pass spfdomain=linux.ibm.com dkim=pass dkdomain=ibm.com dmarc=pass fromdomain=linux.ibm.com); spf=pass (google.com: domain of linux-kernel+bounces-53210-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-53210-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=REJECT sp=NONE dis=NONE) header.from=ibm.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id 35FEB1C231B6 for <ouuuleilei@gmail.com>; Mon, 5 Feb 2024 18:28:30 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id F34E54F8BD; Mon, 5 Feb 2024 18:25:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b="pt3AQHSx" Received: from mx0b-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 07D7F482EB; Mon, 5 Feb 2024 18:25:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.158.5 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707157539; cv=none; b=E/qGZqBK3xM6M2Q6Mw9cDcoKAc3UOvlfO/3cIQFNj/kCWx6/x4TYd3nroXwLWB8metFfXlQRpiDUvir0w7SRYFMy+yC9NeFq4ZthXInNTZ6G6O0xjLxx5+MQwOb5tMwFngJBXMDEFMXTkWRiJlTQxzabgpYhhsATFOi5eygkV+I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707157539; c=relaxed/simple; bh=hqZUaJG+ux2LMrr24JBHv1325O/xG41kZbE+VmUOc+4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ONfCqlGCsAc+E3MdTNCleZM4SYY6AGubkY0UC2Ai2YMcU4iajGbiJDy4Rs5o85Lr+2uFBGH0jx2YD8mJsUoBS5icmiSL8aXERyYk4yGSVZC1+w2ale1BzltdISdU3NQLhtuWV/ByiUOcFRGt3lRINoVmPkOF5Iyg2dPOBk8chTo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com; spf=pass smtp.mailfrom=linux.ibm.com; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b=pt3AQHSx; arc=none smtp.client-ip=148.163.158.5 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.ibm.com Received: from pps.filterd (m0353722.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 415I8o3N000686; Mon, 5 Feb 2024 18:25:16 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=HRVq2c9uSuZERHtMlqfSbAbWFd+PcbFQz/T1bvC8R5Y=; b=pt3AQHSxgiqnPbJV3NGrY63HgIT1z7Y7727hrkks2YD8GAzmTHspjYhE7WatMDHtzuXx REyLdR3S08Ua/hbiHFKg/cCwPgYgYgA86gTHRNHbMDLRlHZXyVtUoRbqAv2wMxhhgvrP WngM53XZgufEe8x9uS1IhihGx5RStC+lCuyvBxE1rzPWBSv8yoc5NKbj8iICO8zciQY7 CYy+E3kko6TqXiruXPjm28A48gxy90Lo9RLgeKakTsSwsSFbgNa6M6yq0zR9SN0OgBN9 xlsNgoFtfb8SCe131E5qjl4X4s6ScU9cAN6zinMdYbzfrwGa/3JsFI0e5clTPeTs2nBP tQ== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3w34pk89xu-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 05 Feb 2024 18:25:16 +0000 Received: from m0353722.ppops.net (m0353722.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 415I9VeY001800; Mon, 5 Feb 2024 18:25:16 GMT Received: from ppma11.dal12v.mail.ibm.com (db.9e.1632.ip4.static.sl-reverse.com [50.22.158.219]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3w34pk89xq-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 05 Feb 2024 18:25:16 +0000 Received: from pps.filterd (ppma11.dal12v.mail.ibm.com [127.0.0.1]) by ppma11.dal12v.mail.ibm.com (8.17.1.19/8.17.1.19) with ESMTP id 415IKubQ016154; Mon, 5 Feb 2024 18:25:15 GMT Received: from smtprelay07.wdc07v.mail.ibm.com ([172.16.1.74]) by ppma11.dal12v.mail.ibm.com (PPS) with ESMTPS id 3w22h1sprf-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 05 Feb 2024 18:25:15 +0000 Received: from smtpav03.dal12v.mail.ibm.com (smtpav03.dal12v.mail.ibm.com [10.241.53.102]) by smtprelay07.wdc07v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 415IPD6r19464922 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 5 Feb 2024 18:25:14 GMT Received: from smtpav03.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id BD3BC58056; Mon, 5 Feb 2024 18:25:13 +0000 (GMT) Received: from smtpav03.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 1BE7E5803F; Mon, 5 Feb 2024 18:25:13 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by smtpav03.dal12v.mail.ibm.com (Postfix) with ESMTP; Mon, 5 Feb 2024 18:25:13 +0000 (GMT) From: Stefan Berger <stefanb@linux.ibm.com> To: linux-integrity@vger.kernel.org, linux-security-module@vger.kernel.org, linux-unionfs@vger.kernel.org Cc: linux-kernel@vger.kernel.org, paul@paul-moore.com, jmorris@namei.org, serge@hallyn.com, zohar@linux.ibm.com, roberto.sassu@huawei.com, amir73il@gmail.com, brauner@kernel.org, miklos@szeredi.hu, Stefan Berger <stefanb@linux.ibm.com> Subject: [PATCH v2 4/9] ima: Reset EVM status upon detecting changes to the real file Date: Mon, 5 Feb 2024 13:25:01 -0500 Message-ID: <20240205182506.3569743-5-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240205182506.3569743-1-stefanb@linux.ibm.com> References: <20240205182506.3569743-1-stefanb@linux.ibm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: <linux-kernel.vger.kernel.org> List-Subscribe: <mailto:linux-kernel+subscribe@vger.kernel.org> List-Unsubscribe: <mailto:linux-kernel+unsubscribe@vger.kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: YS8wDTn87xaAe1z0tJ47U07xMq_AgWYW X-Proofpoint-GUID: aPCwZ4bjjNqqh9eFaNkc7WHi34f_-LFw X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.272,Aquarius:18.0.1011,Hydra:6.0.619,FMLib:17.11.176.26 definitions=2024-02-05_12,2024-01-31_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 suspectscore=0 mlxscore=0 bulkscore=0 mlxlogscore=785 adultscore=0 impostorscore=0 lowpriorityscore=0 priorityscore=1501 clxscore=1015 spamscore=0 phishscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2311290000 definitions=main-2402050138 X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1790084603401547509 X-GMAIL-MSGID: 1790084603401547509 |
Series |
evm: Support signatures on stacked filesystem
|
|
Commit Message
Stefan Berger
Feb. 5, 2024, 6:25 p.m. UTC
Piggyback the resetting of EVM status on IMA's file content detection that
is triggered when a not-yet-copied-up file on the 'lower' layer was
changed. However, since EVM only cares about changes to the file metadata,
only reset the EVM status if the 'lower' layer file is also the one holding
the file metadata.
Note that in the case of a stacked filesystem (e.g., overlayfs) the iint
represents the file_inode() of a file on the overlay layer. The data in
the in iint must help detect file content (IMA) and file metadata (EVM)
changes occurring on the lower layer for as long as the content or
metadata have not been copied up yet. After copy-up the iit must continue
detecting them on the overlay layer.
Changes to the file metadata on the overlay layer are causing an EVM
status reset through existing evm_inode_post_sattr/setxattr/removexattr
functions *if* an iint for a file exist. An iint exists if the file is
'in (IMA) policy', meaning that IMA created an iint for the file's inode
since the file is covered by the IMA policy.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
---
include/linux/evm.h | 8 ++++++++
security/integrity/evm/evm_main.c | 7 +++++++
security/integrity/ima/ima_main.c | 5 +++++
3 files changed, 20 insertions(+)
Comments
Hi Stefan, kernel test robot noticed the following build errors: [auto build test ERROR on zohar-integrity/next-integrity] [also build test ERROR on pcmoore-selinux/next linus/master v6.8-rc3 next-20240206] [cannot apply to mszeredi-vfs/overlayfs-next mszeredi-vfs/next] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Stefan-Berger/ima-Rename-backing_inode-to-real_inode/20240206-022848 base: https://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git next-integrity patch link: https://lore.kernel.org/r/20240205182506.3569743-5-stefanb%40linux.ibm.com patch subject: [PATCH v2 4/9] ima: Reset EVM status upon detecting changes to the real file config: x86_64-rhel-8.3 (https://download.01.org/0day-ci/archive/20240206/202402062032.8kRzlrPA-lkp@intel.com/config) compiler: gcc-12 (Debian 12.2.0-14) 12.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240206/202402062032.8kRzlrPA-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202402062032.8kRzlrPA-lkp@intel.com/ All errors (new ones prefixed by >>): security/integrity/ima/ima_main.c: In function 'process_measurement': >> security/integrity/ima/ima_main.c:303:58: error: 'D_REAL_METADATA' undeclared (first use in this function) 303 | D_REAL_METADATA))) | ^~~~~~~~~~~~~~~ security/integrity/ima/ima_main.c:303:58: note: each undeclared identifier is reported only once for each function it appears in vim +/D_REAL_METADATA +303 security/integrity/ima/ima_main.c 207 208 static int process_measurement(struct file *file, const struct cred *cred, 209 u32 secid, char *buf, loff_t size, int mask, 210 enum ima_hooks func) 211 { 212 struct inode *real_inode, *inode = file_inode(file); 213 struct integrity_iint_cache *iint = NULL; 214 struct ima_template_desc *template_desc = NULL; 215 char *pathbuf = NULL; 216 char filename[NAME_MAX]; 217 const char *pathname = NULL; 218 int rc = 0, action, must_appraise = 0; 219 int pcr = CONFIG_IMA_MEASURE_PCR_IDX; 220 struct evm_ima_xattr_data *xattr_value = NULL; 221 struct modsig *modsig = NULL; 222 int xattr_len = 0; 223 bool violation_check; 224 enum hash_algo hash_algo; 225 unsigned int allowed_algos = 0; 226 227 if (!ima_policy_flag || !S_ISREG(inode->i_mode)) 228 return 0; 229 230 /* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action 231 * bitmask based on the appraise/audit/measurement policy. 232 * Included is the appraise submask. 233 */ 234 action = ima_get_action(file_mnt_idmap(file), inode, cred, secid, 235 mask, func, &pcr, &template_desc, NULL, 236 &allowed_algos); 237 violation_check = ((func == FILE_CHECK || func == MMAP_CHECK || 238 func == MMAP_CHECK_REQPROT) && 239 (ima_policy_flag & IMA_MEASURE)); 240 if (!action && !violation_check) 241 return 0; 242 243 must_appraise = action & IMA_APPRAISE; 244 245 /* Is the appraise rule hook specific? */ 246 if (action & IMA_FILE_APPRAISE) 247 func = FILE_CHECK; 248 249 inode_lock(inode); 250 251 if (action) { 252 iint = integrity_inode_get(inode); 253 if (!iint) 254 rc = -ENOMEM; 255 } 256 257 if (!rc && violation_check) 258 ima_rdwr_violation_check(file, iint, action & IMA_MEASURE, 259 &pathbuf, &pathname, filename); 260 261 inode_unlock(inode); 262 263 if (rc) 264 goto out; 265 if (!action) 266 goto out; 267 268 mutex_lock(&iint->mutex); 269 270 if (test_and_clear_bit(IMA_CHANGE_ATTR, &iint->atomic_flags)) 271 /* reset appraisal flags if ima_inode_post_setattr was called */ 272 iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED | 273 IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK | 274 IMA_NONACTION_FLAGS); 275 276 /* 277 * Re-evaulate the file if either the xattr has changed or the 278 * kernel has no way of detecting file change on the filesystem. 279 * (Limited to privileged mounted filesystems.) 280 */ 281 if (test_and_clear_bit(IMA_CHANGE_XATTR, &iint->atomic_flags) || 282 ((inode->i_sb->s_iflags & SB_I_IMA_UNVERIFIABLE_SIGNATURE) && 283 !(inode->i_sb->s_iflags & SB_I_UNTRUSTED_MOUNTER) && 284 !(action & IMA_FAIL_UNVERIFIABLE_SIGS))) { 285 iint->flags &= ~IMA_DONE_MASK; 286 iint->measured_pcrs = 0; 287 } 288 289 /* 290 * Detect and re-evaluate changes made to the inode holding file data. 291 */ 292 real_inode = d_real_inode(file_dentry(file)); 293 if (real_inode != inode && 294 (action & IMA_DO_MASK) && (iint->flags & IMA_DONE_MASK)) { 295 if (!IS_I_VERSION(real_inode) || 296 real_inode->i_sb->s_dev != iint->real_dev || 297 real_inode->i_ino != iint->real_ino || 298 !inode_eq_iversion(real_inode, iint->version)) { 299 iint->flags &= ~IMA_DONE_MASK; 300 iint->measured_pcrs = 0; 301 302 if (real_inode == d_inode(d_real(file_dentry(file), > 303 D_REAL_METADATA))) 304 evm_reset_cache_status(file_dentry(file), iint); 305 } 306 } 307 308 /* Determine if already appraised/measured based on bitmask 309 * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, 310 * IMA_AUDIT, IMA_AUDITED) 311 */ 312 iint->flags |= action; 313 action &= IMA_DO_MASK; 314 action &= ~((iint->flags & (IMA_DONE_MASK ^ IMA_MEASURED)) >> 1); 315 316 /* If target pcr is already measured, unset IMA_MEASURE action */ 317 if ((action & IMA_MEASURE) && (iint->measured_pcrs & (0x1 << pcr))) 318 action ^= IMA_MEASURE; 319 320 /* HASH sets the digital signature and update flags, nothing else */ 321 if ((action & IMA_HASH) && 322 !(test_bit(IMA_DIGSIG, &iint->atomic_flags))) { 323 xattr_len = ima_read_xattr(file_dentry(file), 324 &xattr_value, xattr_len); 325 if ((xattr_value && xattr_len > 2) && 326 (xattr_value->type == EVM_IMA_XATTR_DIGSIG)) 327 set_bit(IMA_DIGSIG, &iint->atomic_flags); 328 iint->flags |= IMA_HASHED; 329 action ^= IMA_HASH; 330 set_bit(IMA_UPDATE_XATTR, &iint->atomic_flags); 331 } 332 333 /* Nothing to do, just return existing appraised status */ 334 if (!action) { 335 if (must_appraise) { 336 rc = mmap_violation_check(func, file, &pathbuf, 337 &pathname, filename); 338 if (!rc) 339 rc = ima_get_cache_status(iint, func); 340 } 341 goto out_locked; 342 } 343 344 if ((action & IMA_APPRAISE_SUBMASK) || 345 strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0) { 346 /* read 'security.ima' */ 347 xattr_len = ima_read_xattr(file_dentry(file), 348 &xattr_value, xattr_len); 349 350 /* 351 * Read the appended modsig if allowed by the policy, and allow 352 * an additional measurement list entry, if needed, based on the 353 * template format and whether the file was already measured. 354 */ 355 if (iint->flags & IMA_MODSIG_ALLOWED) { 356 rc = ima_read_modsig(func, buf, size, &modsig); 357 358 if (!rc && ima_template_has_modsig(template_desc) && 359 iint->flags & IMA_MEASURED) 360 action |= IMA_MEASURE; 361 } 362 } 363 364 hash_algo = ima_get_hash_algo(xattr_value, xattr_len); 365 366 rc = ima_collect_measurement(iint, file, buf, size, hash_algo, modsig); 367 if (rc != 0 && rc != -EBADF && rc != -EINVAL) 368 goto out_locked; 369 370 if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */ 371 pathname = ima_d_path(&file->f_path, &pathbuf, filename); 372 373 if (action & IMA_MEASURE) 374 ima_store_measurement(iint, file, pathname, 375 xattr_value, xattr_len, modsig, pcr, 376 template_desc); 377 if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) { 378 rc = ima_check_blacklist(iint, modsig, pcr); 379 if (rc != -EPERM) { 380 inode_lock(inode); 381 rc = ima_appraise_measurement(func, iint, file, 382 pathname, xattr_value, 383 xattr_len, modsig); 384 inode_unlock(inode); 385 } 386 if (!rc) 387 rc = mmap_violation_check(func, file, &pathbuf, 388 &pathname, filename); 389 } 390 if (action & IMA_AUDIT) 391 ima_audit_measurement(iint, pathname); 392 393 if ((file->f_flags & O_DIRECT) && (iint->flags & IMA_PERMIT_DIRECTIO)) 394 rc = 0; 395 396 /* Ensure the digest was generated using an allowed algorithm */ 397 if (rc == 0 && must_appraise && allowed_algos != 0 && 398 (allowed_algos & (1U << hash_algo)) == 0) { 399 rc = -EACCES; 400 401 integrity_audit_msg(AUDIT_INTEGRITY_DATA, file_inode(file), 402 pathname, "collect_data", 403 "denied-hash-algorithm", rc, 0); 404 } 405 out_locked: 406 if ((mask & MAY_WRITE) && test_bit(IMA_DIGSIG, &iint->atomic_flags) && 407 !(iint->flags & IMA_NEW_FILE)) 408 rc = -EACCES; 409 mutex_unlock(&iint->mutex); 410 kfree(xattr_value); 411 ima_free_modsig(modsig); 412 out: 413 if (pathbuf) 414 __putname(pathbuf); 415 if (must_appraise) { 416 if (rc && (ima_appraise & IMA_APPRAISE_ENFORCE)) 417 return -EACCES; 418 if (file->f_mode & FMODE_WRITE) 419 set_bit(IMA_UPDATE_XATTR, &iint->atomic_flags); 420 } 421 return 0; 422 } 423
On Mon, Feb 5, 2024 at 8:25 PM Stefan Berger <stefanb@linux.ibm.com> wrote: > > Piggyback the resetting of EVM status on IMA's file content detection that > is triggered when a not-yet-copied-up file on the 'lower' layer was > changed. However, since EVM only cares about changes to the file metadata, > only reset the EVM status if the 'lower' layer file is also the one holding > the file metadata. > > Note that in the case of a stacked filesystem (e.g., overlayfs) the iint > represents the file_inode() of a file on the overlay layer. The data in > the in iint must help detect file content (IMA) and file metadata (EVM) > changes occurring on the lower layer for as long as the content or > metadata have not been copied up yet. After copy-up the iit must continue > detecting them on the overlay layer. > > Changes to the file metadata on the overlay layer are causing an EVM > status reset through existing evm_inode_post_sattr/setxattr/removexattr > functions *if* an iint for a file exist. An iint exists if the file is > 'in (IMA) policy', meaning that IMA created an iint for the file's inode > since the file is covered by the IMA policy. > > Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> > --- > include/linux/evm.h | 8 ++++++++ > security/integrity/evm/evm_main.c | 7 +++++++ > security/integrity/ima/ima_main.c | 5 +++++ > 3 files changed, 20 insertions(+) > > diff --git a/include/linux/evm.h b/include/linux/evm.h > index 840ffbdc2860..eade9fff7d0b 100644 > --- a/include/linux/evm.h > +++ b/include/linux/evm.h > @@ -66,6 +66,8 @@ extern int evm_protected_xattr_if_enabled(const char *req_xattr_name); > extern int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer, > int buffer_size, char type, > bool canonical_fmt); > +extern void evm_reset_cache_status(struct dentry *dentry, > + struct integrity_iint_cache *iint); > #ifdef CONFIG_FS_POSIX_ACL > extern int posix_xattr_acl(const char *xattrname); > #else > @@ -190,5 +192,11 @@ static inline int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer, > return -EOPNOTSUPP; > } > > +static inline void evm_reset_cache_status(struct dentry *dentry, > + struct integrity_iint_cache *iint) > +{ > + return; > +} > + > #endif /* CONFIG_EVM */ > #endif /* LINUX_EVM_H */ > diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c > index 565c36471408..81c94967f136 100644 > --- a/security/integrity/evm/evm_main.c > +++ b/security/integrity/evm/evm_main.c > @@ -721,6 +721,13 @@ static void evm_reset_status(struct inode *inode) > iint->evm_status = INTEGRITY_UNKNOWN; > } > > +void evm_reset_cache_status(struct dentry *dentry, > + struct integrity_iint_cache *iint) > +{ > + if (d_real_inode(dentry) != d_backing_inode(dentry)) Is this really needed? You get here after checking (real_inode != inode) already > + iint->evm_status = INTEGRITY_UNKNOWN; > +} > + > /** > * evm_revalidate_status - report whether EVM status re-validation is necessary > * @xattr_name: pointer to the affected extended attribute name > diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c > index f1a01d32b92a..b6ba829c4e67 100644 > --- a/security/integrity/ima/ima_main.c > +++ b/security/integrity/ima/ima_main.c > @@ -26,6 +26,7 @@ > #include <linux/ima.h> > #include <linux/fs.h> > #include <linux/iversion.h> > +#include <linux/evm.h> > > #include "ima.h" > > @@ -297,6 +298,10 @@ static int process_measurement(struct file *file, const struct cred *cred, > !inode_eq_iversion(real_inode, iint->version)) { > iint->flags &= ~IMA_DONE_MASK; > iint->measured_pcrs = 0; > + > + if (real_inode == d_inode(d_real(file_dentry(file), > + D_REAL_METADATA))) > + evm_reset_cache_status(file_dentry(file), iint); Technically, you'd also need to store iint->real_meta_{dev,ino} when calculating EVM to be sure if the metadata inode had changed, because there is a possibility that file was not copied up yet, but the file is a metacopy in a middle layer and the lower data is in another layer. Think file metadata was copied from lower to upper layer, then the upper layer was made a middle layer and another upper layer added on top of it. In this situation, real_inode is in the lower layer, real_meta_inode is in the middle layer and after copy up of metadata, real_meta_inode will become in the upper layer. Not sure if this use case is interesting to EVM. Thanks, Amir.
Hi Stefan, kernel test robot noticed the following build errors: [auto build test ERROR on zohar-integrity/next-integrity] [also build test ERROR on pcmoore-selinux/next linus/master v6.8-rc3 next-20240206] [cannot apply to mszeredi-vfs/overlayfs-next mszeredi-vfs/next] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Stefan-Berger/ima-Rename-backing_inode-to-real_inode/20240206-022848 base: https://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git next-integrity patch link: https://lore.kernel.org/r/20240205182506.3569743-5-stefanb%40linux.ibm.com patch subject: [PATCH v2 4/9] ima: Reset EVM status upon detecting changes to the real file config: x86_64-rhel-8.3-rust (https://download.01.org/0day-ci/archive/20240207/202402071226.lXIiGtbl-lkp@intel.com/config) compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240207/202402071226.lXIiGtbl-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202402071226.lXIiGtbl-lkp@intel.com/ All errors (new ones prefixed by >>): >> security/integrity/ima/ima_main.c:303:9: error: use of undeclared identifier 'D_REAL_METADATA' 303 | D_REAL_METADATA))) | ^ 1 error generated. vim +/D_REAL_METADATA +303 security/integrity/ima/ima_main.c 207 208 static int process_measurement(struct file *file, const struct cred *cred, 209 u32 secid, char *buf, loff_t size, int mask, 210 enum ima_hooks func) 211 { 212 struct inode *real_inode, *inode = file_inode(file); 213 struct integrity_iint_cache *iint = NULL; 214 struct ima_template_desc *template_desc = NULL; 215 char *pathbuf = NULL; 216 char filename[NAME_MAX]; 217 const char *pathname = NULL; 218 int rc = 0, action, must_appraise = 0; 219 int pcr = CONFIG_IMA_MEASURE_PCR_IDX; 220 struct evm_ima_xattr_data *xattr_value = NULL; 221 struct modsig *modsig = NULL; 222 int xattr_len = 0; 223 bool violation_check; 224 enum hash_algo hash_algo; 225 unsigned int allowed_algos = 0; 226 227 if (!ima_policy_flag || !S_ISREG(inode->i_mode)) 228 return 0; 229 230 /* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action 231 * bitmask based on the appraise/audit/measurement policy. 232 * Included is the appraise submask. 233 */ 234 action = ima_get_action(file_mnt_idmap(file), inode, cred, secid, 235 mask, func, &pcr, &template_desc, NULL, 236 &allowed_algos); 237 violation_check = ((func == FILE_CHECK || func == MMAP_CHECK || 238 func == MMAP_CHECK_REQPROT) && 239 (ima_policy_flag & IMA_MEASURE)); 240 if (!action && !violation_check) 241 return 0; 242 243 must_appraise = action & IMA_APPRAISE; 244 245 /* Is the appraise rule hook specific? */ 246 if (action & IMA_FILE_APPRAISE) 247 func = FILE_CHECK; 248 249 inode_lock(inode); 250 251 if (action) { 252 iint = integrity_inode_get(inode); 253 if (!iint) 254 rc = -ENOMEM; 255 } 256 257 if (!rc && violation_check) 258 ima_rdwr_violation_check(file, iint, action & IMA_MEASURE, 259 &pathbuf, &pathname, filename); 260 261 inode_unlock(inode); 262 263 if (rc) 264 goto out; 265 if (!action) 266 goto out; 267 268 mutex_lock(&iint->mutex); 269 270 if (test_and_clear_bit(IMA_CHANGE_ATTR, &iint->atomic_flags)) 271 /* reset appraisal flags if ima_inode_post_setattr was called */ 272 iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED | 273 IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK | 274 IMA_NONACTION_FLAGS); 275 276 /* 277 * Re-evaulate the file if either the xattr has changed or the 278 * kernel has no way of detecting file change on the filesystem. 279 * (Limited to privileged mounted filesystems.) 280 */ 281 if (test_and_clear_bit(IMA_CHANGE_XATTR, &iint->atomic_flags) || 282 ((inode->i_sb->s_iflags & SB_I_IMA_UNVERIFIABLE_SIGNATURE) && 283 !(inode->i_sb->s_iflags & SB_I_UNTRUSTED_MOUNTER) && 284 !(action & IMA_FAIL_UNVERIFIABLE_SIGS))) { 285 iint->flags &= ~IMA_DONE_MASK; 286 iint->measured_pcrs = 0; 287 } 288 289 /* 290 * Detect and re-evaluate changes made to the inode holding file data. 291 */ 292 real_inode = d_real_inode(file_dentry(file)); 293 if (real_inode != inode && 294 (action & IMA_DO_MASK) && (iint->flags & IMA_DONE_MASK)) { 295 if (!IS_I_VERSION(real_inode) || 296 real_inode->i_sb->s_dev != iint->real_dev || 297 real_inode->i_ino != iint->real_ino || 298 !inode_eq_iversion(real_inode, iint->version)) { 299 iint->flags &= ~IMA_DONE_MASK; 300 iint->measured_pcrs = 0; 301 302 if (real_inode == d_inode(d_real(file_dentry(file), > 303 D_REAL_METADATA))) 304 evm_reset_cache_status(file_dentry(file), iint); 305 } 306 } 307 308 /* Determine if already appraised/measured based on bitmask 309 * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, 310 * IMA_AUDIT, IMA_AUDITED) 311 */ 312 iint->flags |= action; 313 action &= IMA_DO_MASK; 314 action &= ~((iint->flags & (IMA_DONE_MASK ^ IMA_MEASURED)) >> 1); 315 316 /* If target pcr is already measured, unset IMA_MEASURE action */ 317 if ((action & IMA_MEASURE) && (iint->measured_pcrs & (0x1 << pcr))) 318 action ^= IMA_MEASURE; 319 320 /* HASH sets the digital signature and update flags, nothing else */ 321 if ((action & IMA_HASH) && 322 !(test_bit(IMA_DIGSIG, &iint->atomic_flags))) { 323 xattr_len = ima_read_xattr(file_dentry(file), 324 &xattr_value, xattr_len); 325 if ((xattr_value && xattr_len > 2) && 326 (xattr_value->type == EVM_IMA_XATTR_DIGSIG)) 327 set_bit(IMA_DIGSIG, &iint->atomic_flags); 328 iint->flags |= IMA_HASHED; 329 action ^= IMA_HASH; 330 set_bit(IMA_UPDATE_XATTR, &iint->atomic_flags); 331 } 332 333 /* Nothing to do, just return existing appraised status */ 334 if (!action) { 335 if (must_appraise) { 336 rc = mmap_violation_check(func, file, &pathbuf, 337 &pathname, filename); 338 if (!rc) 339 rc = ima_get_cache_status(iint, func); 340 } 341 goto out_locked; 342 } 343 344 if ((action & IMA_APPRAISE_SUBMASK) || 345 strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0) { 346 /* read 'security.ima' */ 347 xattr_len = ima_read_xattr(file_dentry(file), 348 &xattr_value, xattr_len); 349 350 /* 351 * Read the appended modsig if allowed by the policy, and allow 352 * an additional measurement list entry, if needed, based on the 353 * template format and whether the file was already measured. 354 */ 355 if (iint->flags & IMA_MODSIG_ALLOWED) { 356 rc = ima_read_modsig(func, buf, size, &modsig); 357 358 if (!rc && ima_template_has_modsig(template_desc) && 359 iint->flags & IMA_MEASURED) 360 action |= IMA_MEASURE; 361 } 362 } 363 364 hash_algo = ima_get_hash_algo(xattr_value, xattr_len); 365 366 rc = ima_collect_measurement(iint, file, buf, size, hash_algo, modsig); 367 if (rc != 0 && rc != -EBADF && rc != -EINVAL) 368 goto out_locked; 369 370 if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */ 371 pathname = ima_d_path(&file->f_path, &pathbuf, filename); 372 373 if (action & IMA_MEASURE) 374 ima_store_measurement(iint, file, pathname, 375 xattr_value, xattr_len, modsig, pcr, 376 template_desc); 377 if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) { 378 rc = ima_check_blacklist(iint, modsig, pcr); 379 if (rc != -EPERM) { 380 inode_lock(inode); 381 rc = ima_appraise_measurement(func, iint, file, 382 pathname, xattr_value, 383 xattr_len, modsig); 384 inode_unlock(inode); 385 } 386 if (!rc) 387 rc = mmap_violation_check(func, file, &pathbuf, 388 &pathname, filename); 389 } 390 if (action & IMA_AUDIT) 391 ima_audit_measurement(iint, pathname); 392 393 if ((file->f_flags & O_DIRECT) && (iint->flags & IMA_PERMIT_DIRECTIO)) 394 rc = 0; 395 396 /* Ensure the digest was generated using an allowed algorithm */ 397 if (rc == 0 && must_appraise && allowed_algos != 0 && 398 (allowed_algos & (1U << hash_algo)) == 0) { 399 rc = -EACCES; 400 401 integrity_audit_msg(AUDIT_INTEGRITY_DATA, file_inode(file), 402 pathname, "collect_data", 403 "denied-hash-algorithm", rc, 0); 404 } 405 out_locked: 406 if ((mask & MAY_WRITE) && test_bit(IMA_DIGSIG, &iint->atomic_flags) && 407 !(iint->flags & IMA_NEW_FILE)) 408 rc = -EACCES; 409 mutex_unlock(&iint->mutex); 410 kfree(xattr_value); 411 ima_free_modsig(modsig); 412 out: 413 if (pathbuf) 414 __putname(pathbuf); 415 if (must_appraise) { 416 if (rc && (ima_appraise & IMA_APPRAISE_ENFORCE)) 417 return -EACCES; 418 if (file->f_mode & FMODE_WRITE) 419 set_bit(IMA_UPDATE_XATTR, &iint->atomic_flags); 420 } 421 return 0; 422 } 423
diff --git a/include/linux/evm.h b/include/linux/evm.h index 840ffbdc2860..eade9fff7d0b 100644 --- a/include/linux/evm.h +++ b/include/linux/evm.h @@ -66,6 +66,8 @@ extern int evm_protected_xattr_if_enabled(const char *req_xattr_name); extern int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer, int buffer_size, char type, bool canonical_fmt); +extern void evm_reset_cache_status(struct dentry *dentry, + struct integrity_iint_cache *iint); #ifdef CONFIG_FS_POSIX_ACL extern int posix_xattr_acl(const char *xattrname); #else @@ -190,5 +192,11 @@ static inline int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer, return -EOPNOTSUPP; } +static inline void evm_reset_cache_status(struct dentry *dentry, + struct integrity_iint_cache *iint) +{ + return; +} + #endif /* CONFIG_EVM */ #endif /* LINUX_EVM_H */ diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 565c36471408..81c94967f136 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -721,6 +721,13 @@ static void evm_reset_status(struct inode *inode) iint->evm_status = INTEGRITY_UNKNOWN; } +void evm_reset_cache_status(struct dentry *dentry, + struct integrity_iint_cache *iint) +{ + if (d_real_inode(dentry) != d_backing_inode(dentry)) + iint->evm_status = INTEGRITY_UNKNOWN; +} + /** * evm_revalidate_status - report whether EVM status re-validation is necessary * @xattr_name: pointer to the affected extended attribute name diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index f1a01d32b92a..b6ba829c4e67 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -26,6 +26,7 @@ #include <linux/ima.h> #include <linux/fs.h> #include <linux/iversion.h> +#include <linux/evm.h> #include "ima.h" @@ -297,6 +298,10 @@ static int process_measurement(struct file *file, const struct cred *cred, !inode_eq_iversion(real_inode, iint->version)) { iint->flags &= ~IMA_DONE_MASK; iint->measured_pcrs = 0; + + if (real_inode == d_inode(d_real(file_dentry(file), + D_REAL_METADATA))) + evm_reset_cache_status(file_dentry(file), iint); } }