From nobody Tue Dec 2 02:19:56 2025 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (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 479DB325737 for ; Wed, 19 Nov 2025 14:03:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763561026; cv=none; b=nMXheZvmNf0GOssBwmHNuOjgbfbjZ2/9g5IaURuhedX6pYl4HZ6uJe8+ucBlfyKObC2ehWBjwDOalc1+wuub9iPCq5XYctAiUmJdfyYC6LcM4QL+BM1K8SSU/oO4FwqriySkqo4HP3dFPXsiYDFlrLKeUk1slpu/jTIQ5c9Dqeg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763561026; c=relaxed/simple; bh=sMM0Td1pTUZfgcV1XQAs8U+6FRC5Dx7pl1U5YG27aiA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=oAPZO3Zvw7RkXriJrdo18ndubgsC/xScgXcOSuL+l6ymvs6hqErRKMTkrigwAQf2+wdqlCFv/+/9V9+feeaPmwRK+vZ4eKra/1d8YZ3Xe6K9Ovh1GSfjIbztayBlLj6mk8aEWDSMcghx1yXXwPRjpEnw8CWURNQwM0W+OzxpL2k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=GGOA83O4; dkim=pass (2048-bit key) header.d=redhat.com header.i=@redhat.com header.b=fe8y8CTb; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="GGOA83O4"; dkim=pass (2048-bit key) header.d=redhat.com header.i=@redhat.com header.b="fe8y8CTb" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1763561023; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=43huBOvLkP9Orb60esyoQoOyuL+2DOEyrVCLCaUwMJA=; b=GGOA83O4dLvEQx3BA/i9akxSqWvAgtpL8+O0fn4P5uCwRaGObm6LzSCkgN6xNlvdDD4apl bxieqP4SjzKkZUGxtQEEIIYqWiqmGAT6O4+FsbpUKej3LEjz4iydBKhQZReX8smwlSDi0V aZLAyjO2RNvHsm5D1Vb2QYERdl2qXCg= Received: from mail-pj1-f69.google.com (mail-pj1-f69.google.com [209.85.216.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-112-LtlCEQjQMf2Yh9jTZ4Lhkw-1; Wed, 19 Nov 2025 09:03:39 -0500 X-MC-Unique: LtlCEQjQMf2Yh9jTZ4Lhkw-1 X-Mimecast-MFC-AGG-ID: LtlCEQjQMf2Yh9jTZ4Lhkw_1763561015 Received: by mail-pj1-f69.google.com with SMTP id 98e67ed59e1d1-340c07119bfso17586951a91.2 for ; Wed, 19 Nov 2025 06:03:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1763561014; x=1764165814; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=43huBOvLkP9Orb60esyoQoOyuL+2DOEyrVCLCaUwMJA=; b=fe8y8CTbtcqa2MZLSP8mhNmvmKo7Ouj8fmZ8+AEQWKiqX9d9ELUVitZtNB6xDQffgh jleTT9UpZp7mrWhGxiMDscJSv0uwCn+oQCT1PExe7Yw1Z4Jz25dBUXv5oE2kF+syqUQq X1SbT4KvcQDh/rW9c6Mitk0C8u3nPW64olCFkjkLRyZcXnoownN0ke9+Sb/VsteZv18z BrW2gSTVORtJpk+2WrI1/QCrrCJQxYycawcIubuKn8A1zwp32N4RHSTUMtdpMxYGWBtN HL0pE+O97teqrE3NeEux2ZaI1tl8jynXTqQqp7xTcw5QoW/zjcojpTSlE9vVxtHH/u1o hKeg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1763561014; x=1764165814; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=43huBOvLkP9Orb60esyoQoOyuL+2DOEyrVCLCaUwMJA=; b=gBpVMSOJbAZmmHBvAE/AiicgbhaK3Fn62YByvbPlTUPibimcX+KRn+gBPANNCxMRLf CkBJrVKR0w75wNhuAoROxk/W9szWsFRHzaHArvfOWZB8pRBb/I0vGUA6ysNGornXrISS 9GplxBtOZhaAAk37cd1u0g5FcVfrlezdLNsNEi6aRFalJmZvVXeqLOU6HlmvJkaGT8ZN u9046xf7A9p8SZNldq4hzHB+RTsvCS4OZQm8yDsaVBrl+pf1JfwXPl2D3QZjuJdAxuzI QCmxSc2bLQkFJzt9fNnNxd+W+x2ZjiqjRThed/GJdNYpLWh+ELxrCq+En0wh4x++gD48 lLGA== X-Forwarded-Encrypted: i=1; AJvYcCWjUIHAhNNi7eZ4e4nNwuxhR01DhIIBnIhkTFsoC6bQf2monjqbaXbIuaWvtZnQY8pLCVhBTnrxWx23UiQ=@vger.kernel.org X-Gm-Message-State: AOJu0Yz6aRmZiWKzzXVxjDA36STaxCiFUktRnSt5NyJF/Zj/YenUstVz Tk7Fy/RI+8ry5GXez+2ju9xn0HkFAqemDsOmjRTFLLZu/bEc6U7X9CgxCEtTidW40BVtDxLc+Q4 uz/sEU5T4j5tXKfdW9Y4nTSa7zeVI2U+PzJii6g3DJt4xW5r0O50xfaVh43bV+Z+GOA== X-Gm-Gg: ASbGnctM+FoafwyzKF7YhEU5SyDeUSy0vUDElhZ3y+LmFMb/xVHgFJuGT2uMzZprnQC ULILsTEDLckxGt8Zurx+BDIN8M1vyvLsy0zjsRaWHPa0HjDoHdIlzQa4LLsHuLqn1S8t4HAKkXm R1MofOGdnO/xQ2wvJ4X55Iw/lAApW6kvT+G5n8HScV8zsLmScgbMY2n702nLt5nyEY5BBlznxMn wL29AJUefXF6AplKaQWPRy/Icuxy2qYDvO02vgUbrIJyVNR0hhrZ1EuSs87r1e0XZVL4P5MAALD Hm1Hf4ruoS5p+3RY4xhJZitMuY8XhWnpLDqbk5jlamyjNlWuRyMfc88LOZlw3dEbzoHE+WYACJH M X-Received: by 2002:a17:903:2a8c:b0:297:c889:ba37 with SMTP id d9443c01a7336-2986a755422mr235982765ad.41.1763561012845; Wed, 19 Nov 2025 06:03:32 -0800 (PST) X-Google-Smtp-Source: AGHT+IE5JYdLW6VkCpjZEiTrP+h9ubU8Y8eKrRTH5BmmnLLCtVlJCYiAx2FQsMZqrDxFZTIQ2fSm5A== X-Received: by 2002:a17:903:2a8c:b0:297:c889:ba37 with SMTP id d9443c01a7336-2986a755422mr235980775ad.41.1763561010932; Wed, 19 Nov 2025 06:03:30 -0800 (PST) Received: from localhost ([209.132.188.88]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2985c2b11bfsm210101215ad.53.2025.11.19.06.03.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Nov 2025 06:03:30 -0800 (PST) From: Coiby Xu To: linux-integrity@vger.kernel.org, Mimi Zohar Cc: Karel Srot , Paul Moore , Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen , Roberto Sassu , Dmitry Kasatkin , Eric Snowberg , James Morris , "Serge E. Hallyn" , Fan Wu , Stephen Smalley , Ondrej Mosnacek , linux-kernel@vger.kernel.org (open list), linux-modules@vger.kernel.org (open list:MODULE SUPPORT), linux-security-module@vger.kernel.org (open list:SECURITY SUBSYSTEM), selinux@vger.kernel.org (open list:SELINUX SECURITY MODULE) Subject: [PATCH v4] ima: Access decompressed kernel module to verify appended signature Date: Wed, 19 Nov 2025 22:03:25 +0800 Message-ID: <20251119140326.787451-1-coxu@redhat.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251031074016.1975356-1-coxu@redhat.com> References: <20251031074016.1975356-1-coxu@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Currently, when in-kernel module decompression (CONFIG_MODULE_DECOMPRESS) is enabled, IMA has no way to verify the appended module signature as it can't decompress the module. Define a new kernel_read_file_id enumerate READING_MODULE_COMPRESSED so IMA can calculate the compressed kernel module data hash on READING_MODULE_COMPRESSED and defer appraising/measuring it until on READING_MODULE when the module has been decompressed. Before enabling in-kernel module decompression, a kernel module in initramfs can still be loaded with ima_policy=3Dsecure_boot. So adjust the kernel module rule in secure_boot policy to allow either an IMA signature OR an appended signature i.e. to use "appraise func=3DMODULE_CHECK appraise_type=3Dimasig|modsig". Reported-by: Karel Srot Suggested-by: Mimi Zohar Suggested-by: Paul Moore Signed-off-by: Coiby Xu --- include/linux/kernel_read_file.h | 1 + kernel/module/main.c | 17 ++++++++++++++--- security/integrity/ima/ima_main.c | 24 ++++++++++++++++-------- security/integrity/ima/ima_policy.c | 3 ++- security/ipe/hooks.c | 1 + security/selinux/hooks.c | 5 +++-- 6 files changed, 37 insertions(+), 14 deletions(-) diff --git a/include/linux/kernel_read_file.h b/include/linux/kernel_read_f= ile.h index 90451e2e12bd..d613a7b4dd35 100644 --- a/include/linux/kernel_read_file.h +++ b/include/linux/kernel_read_file.h @@ -14,6 +14,7 @@ id(KEXEC_INITRAMFS, kexec-initramfs) \ id(POLICY, security-policy) \ id(X509_CERTIFICATE, x509-certificate) \ + id(MODULE_COMPRESSED, kernel-module-compressed) \ id(MAX_ID, ) =20 #define __fid_enumify(ENUM, dummy) READING_ ## ENUM, diff --git a/kernel/module/main.c b/kernel/module/main.c index c66b26184936..7b3ec2fa6e7c 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -3675,24 +3675,35 @@ static int idempotent_wait_for_completion(struct id= empotent *u) =20 static int init_module_from_file(struct file *f, const char __user * uargs= , int flags) { + bool compressed =3D !!(flags & MODULE_INIT_COMPRESSED_FILE); struct load_info info =3D { }; void *buf =3D NULL; int len; + int err; =20 - len =3D kernel_read_file(f, 0, &buf, INT_MAX, NULL, READING_MODULE); + len =3D kernel_read_file(f, 0, &buf, INT_MAX, NULL, + compressed ? READING_MODULE_COMPRESSED : + READING_MODULE); if (len < 0) { mod_stat_inc(&failed_kreads); return len; } =20 - if (flags & MODULE_INIT_COMPRESSED_FILE) { - int err =3D module_decompress(&info, buf, len); + if (compressed) { + err =3D module_decompress(&info, buf, len); vfree(buf); /* compressed data is no longer needed */ if (err) { mod_stat_inc(&failed_decompress); mod_stat_add_long(len, &invalid_decompress_bytes); return err; } + err =3D security_kernel_post_read_file(f, (char *)info.hdr, info.len, + READING_MODULE); + if (err) { + mod_stat_inc(&failed_kreads); + free_copy(&info, flags); + return err; + } } else { info.hdr =3D buf; info.len =3D len; diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima= _main.c index ebaebccfbe9a..edd0fd3d77a0 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -235,7 +235,8 @@ static void ima_file_free(struct file *file) =20 static int process_measurement(struct file *file, const struct cred *cred, struct lsm_prop *prop, char *buf, loff_t size, - int mask, enum ima_hooks func) + int mask, enum ima_hooks func, + enum kernel_read_file_id read_id) { struct inode *real_inode, *inode =3D file_inode(file); struct ima_iint_cache *iint =3D NULL; @@ -406,6 +407,12 @@ static int process_measurement(struct file *file, cons= t struct cred *cred, if (rc !=3D 0 && rc !=3D -EBADF && rc !=3D -EINVAL) goto out_locked; =20 + /* Defer measuring/appraising kernel modules to READING_MODULE */ + if (read_id =3D=3D READING_MODULE_COMPRESSED) { + must_appraise =3D 0; + goto out_locked; + } + if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */ pathname =3D ima_d_path(&file->f_path, &pathbuf, filename); =20 @@ -486,14 +493,14 @@ static int ima_file_mmap(struct file *file, unsigned = long reqprot, =20 if (reqprot & PROT_EXEC) { ret =3D process_measurement(file, current_cred(), &prop, NULL, - 0, MAY_EXEC, MMAP_CHECK_REQPROT); + 0, MAY_EXEC, MMAP_CHECK_REQPROT, 0); if (ret) return ret; } =20 if (prot & PROT_EXEC) return process_measurement(file, current_cred(), &prop, NULL, - 0, MAY_EXEC, MMAP_CHECK); + 0, MAY_EXEC, MMAP_CHECK, 0); =20 return 0; } @@ -577,7 +584,7 @@ static int ima_bprm_check(struct linux_binprm *bprm) =20 security_current_getlsmprop_subj(&prop); return process_measurement(bprm->file, current_cred(), - &prop, NULL, 0, MAY_EXEC, BPRM_CHECK); + &prop, NULL, 0, MAY_EXEC, BPRM_CHECK, 0); } =20 /** @@ -607,7 +614,7 @@ static int ima_creds_check(struct linux_binprm *bprm, c= onst struct file *file) =20 security_current_getlsmprop_subj(&prop); return process_measurement((struct file *)file, bprm->cred, &prop, NULL, - 0, MAY_EXEC, CREDS_CHECK); + 0, MAY_EXEC, CREDS_CHECK, 0); } =20 /** @@ -655,7 +662,7 @@ static int ima_file_check(struct file *file, int mask) security_current_getlsmprop_subj(&prop); return process_measurement(file, current_cred(), &prop, NULL, 0, mask & (MAY_READ | MAY_WRITE | MAY_EXEC | - MAY_APPEND), FILE_CHECK); + MAY_APPEND), FILE_CHECK, 0); } =20 static int __ima_inode_hash(struct inode *inode, struct file *file, char *= buf, @@ -874,12 +881,13 @@ static int ima_read_file(struct file *file, enum kern= el_read_file_id read_id, func =3D read_idmap[read_id] ?: FILE_CHECK; security_current_getlsmprop_subj(&prop); return process_measurement(file, current_cred(), &prop, NULL, 0, - MAY_READ, func); + MAY_READ, func, 0); } =20 const int read_idmap[READING_MAX_ID] =3D { [READING_FIRMWARE] =3D FIRMWARE_CHECK, [READING_MODULE] =3D MODULE_CHECK, + [READING_MODULE_COMPRESSED] =3D MODULE_CHECK, [READING_KEXEC_IMAGE] =3D KEXEC_KERNEL_CHECK, [READING_KEXEC_INITRAMFS] =3D KEXEC_INITRAMFS_CHECK, [READING_POLICY] =3D POLICY_CHECK @@ -917,7 +925,7 @@ static int ima_post_read_file(struct file *file, char *= buf, loff_t size, func =3D read_idmap[read_id] ?: FILE_CHECK; security_current_getlsmprop_subj(&prop); return process_measurement(file, current_cred(), &prop, buf, size, - MAY_READ, func); + MAY_READ, func, read_id); } =20 /** diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/i= ma_policy.c index 164d62832f8e..7468afaab686 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -244,7 +244,8 @@ static struct ima_rule_entry build_appraise_rules[] __r= o_after_init =3D { =20 static struct ima_rule_entry secure_boot_rules[] __ro_after_init =3D { {.action =3D APPRAISE, .func =3D MODULE_CHECK, - .flags =3D IMA_FUNC | IMA_DIGSIG_REQUIRED}, + .flags =3D IMA_FUNC | IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED | + IMA_CHECK_BLACKLIST}, {.action =3D APPRAISE, .func =3D FIRMWARE_CHECK, .flags =3D IMA_FUNC | IMA_DIGSIG_REQUIRED}, {.action =3D APPRAISE, .func =3D KEXEC_KERNEL_CHECK, diff --git a/security/ipe/hooks.c b/security/ipe/hooks.c index d0323b81cd8f..1053a4acf589 100644 --- a/security/ipe/hooks.c +++ b/security/ipe/hooks.c @@ -118,6 +118,7 @@ int ipe_kernel_read_file(struct file *file, enum kernel= _read_file_id id, op =3D IPE_OP_FIRMWARE; break; case READING_MODULE: + case READING_MODULE_COMPRESSED: op =3D IPE_OP_KERNEL_MODULE; break; case READING_KEXEC_INITRAMFS: diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index dfc22da42f30..c1ff69d5d76e 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4275,7 +4275,7 @@ static int selinux_kernel_read_file(struct file *file, { int rc =3D 0; =20 - BUILD_BUG_ON_MSG(READING_MAX_ID > 7, + BUILD_BUG_ON_MSG(READING_MAX_ID > 8, "New kernel_read_file_id introduced; update SELinux!"); =20 switch (id) { @@ -4283,6 +4283,7 @@ static int selinux_kernel_read_file(struct file *file, rc =3D selinux_kernel_load_from_file(file, SYSTEM__FIRMWARE_LOAD); break; case READING_MODULE: + case READING_MODULE_COMPRESSED: rc =3D selinux_kernel_load_from_file(file, SYSTEM__MODULE_LOAD); break; case READING_KEXEC_IMAGE: @@ -4311,7 +4312,7 @@ static int selinux_kernel_load_data(enum kernel_load_= data_id id, bool contents) { int rc =3D 0; =20 - BUILD_BUG_ON_MSG(LOADING_MAX_ID > 7, + BUILD_BUG_ON_MSG(LOADING_MAX_ID > 8, "New kernel_load_data_id introduced; update SELinux!"); =20 switch (id) { base-commit: 43369273518f57b7d56c1cf12d636a809b7bd81b --=20 2.51.1