From nobody Tue Dec 2 02:32:39 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 96699143C61 for ; Wed, 19 Nov 2025 03:47:26 +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=1763524048; cv=none; b=HiaMy+poGj9vpTjqCIEzkOBfju1XYGt0V10kKJDNV/IPxeHVUyza7tCkRb4L1TyJjIHcD+TPhG6X6Nbc9sd+oCmmJIcQ1HirqA/kHPbMqwzHHDNc6+RlW12nyjeHwl7X5Wkinpu53jjSvjWPo8mn3nlphzzUo5Mvt1nL3iSA50w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763524048; c=relaxed/simple; bh=sAgaW41yIgMaoEvvflo/CQbk3JRAIxoAS7WWcaUJLQk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ktv06dSxzcgkjOhNZ6ItisuopKODMNg6nSG73EjOuA70L+s1HnC+8fb7LKceoCg37Eh9p9uEupLKNE/pna5NkuDyLYQRt97lVYOno42YiJQGr9l4yxHxg/Tmox2Nqm3QqCE5IWhYqJAzLHBJZfDrhjppdhS625RkvP+d64BuhSE= 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=PG2fjgY1; dkim=pass (2048-bit key) header.d=redhat.com header.i=@redhat.com header.b=C0IxfXJS; 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="PG2fjgY1"; dkim=pass (2048-bit key) header.d=redhat.com header.i=@redhat.com header.b="C0IxfXJS" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1763524045; 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=JCJ20fAfU4UAl4nhBDPE2F0lHJsnmGeSDQ/Z9o7J34w=; b=PG2fjgY1l6cyIn1IGdjkzTdLRGmc46MG0wkHw3Tzah+m3LeGHlrJfeB7MTKbPq7fIrAB+9 kBuU1iOaeizgXXpvBNaqGrGtgRF/uN4QankgR1d4FK+PJv2ErA8VnmO/ZQGIQP7FHb8xkU 69/WJOh2eiI4A09ReaahLTtGY7AtuNE= Received: from mail-pl1-f198.google.com (mail-pl1-f198.google.com [209.85.214.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-640-8a1wWwDONA-secH5jTU2CA-1; Tue, 18 Nov 2025 22:47:24 -0500 X-MC-Unique: 8a1wWwDONA-secH5jTU2CA-1 X-Mimecast-MFC-AGG-ID: 8a1wWwDONA-secH5jTU2CA_1763524043 Received: by mail-pl1-f198.google.com with SMTP id d9443c01a7336-29557f43d56so77618075ad.3 for ; Tue, 18 Nov 2025 19:47:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1763524043; x=1764128843; 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=JCJ20fAfU4UAl4nhBDPE2F0lHJsnmGeSDQ/Z9o7J34w=; b=C0IxfXJSbcneOUm1O48iWzA69y5bHtr0JWl72ZmrldhYb9/WBS2c3KsTQifLp0MFzQ 48cyW1SkVnUbEMUHO0flckbuCEGKR31QkrHnOu14mWoQg/usSBGjTPW+amYkdjX1aAZa NZYf6GjAYkoxse2EhSUii4JiHiHR7ocVPYyJ1nAxUCnS2gHjT+gVaAInrGMwVW2FpHFH /umy465thLzFFiz21bojvKEVu4EIAUHw6VsPSsX3SpwJNzfDmDd39YzucW997ZsIQFAI R8m/hIKZdXpMjjQCVn5xh61mfZQiQSem0or/TlsiEI5kdsLII09O9D0wJQrfHPDW/Ugd 9t8g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1763524043; x=1764128843; 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=JCJ20fAfU4UAl4nhBDPE2F0lHJsnmGeSDQ/Z9o7J34w=; b=nHp3JSAOBi5E0XHfzMVezH/EEcvq02F/idXHSF44wIka+57tzev2BXyJTcfmLTbKhS nJ28P3xa3aP1b1E9+zffmw7hzHDuTD2+Uw6fnwestygf+dG1DKTbXiePEgRkCoJUPtaw X1KaRqX86FCsj+dfEriZ9TEDdPvip0fxZxy8sSWq3LPDNTHbi4Vn8YDgSBb+WtpFia5M xxybaX7NQZIHbkizuGXU1gdwmpnMU8xfA6tUjbLS7d1riB86k4V1yAtSzTgXLx0nDRet YxnpNeB1h5ct5w/SJ67bQnSl70itAYAl32WFcznRoY0Sqyy3tmvpq4L+laUu8q9dccGZ v3WQ== X-Forwarded-Encrypted: i=1; AJvYcCWTwcv8f1FH2Oa6WYaTlfgw2ltrOztEKwt2GZ03LwrfOsIjcryL/xH3s8l4tTwkjCe2pXZeUx+gk/WdQk4=@vger.kernel.org X-Gm-Message-State: AOJu0YzT3rbReuHvGARkb6WQgotsdFBtNu3I1d9aqe2Qkbh+Wjn989p2 45rZcPbTpmlxz3mIx+9poASK2iayk6oCDPt6p52lVm/rPRtYHwnLz7Q/DEKx23klJUxj3qn81/D X709CORAFuc9FVB4uJ3h5KUvIzp0Rn66cadUqyiIBKpBSXjl7zLueJruomDhIVErVCg== X-Gm-Gg: ASbGnctRaZgNxIrhfXCECxYncwXN+Y08ffEiHOmHsYVSB8P2sIEecHNl/X4kAPBT+PD w13r0s+BiBEqockpeRdG8tOndgbgCeyOSUqAX50pLLB7ScUqfXpSxXwqqAVX8q2ad2D+Our1OKI tZLNoadHYB+hmpTMpMQu4fb0wPwRyypLyj7cZoZ6A/udNAgToQ1mkzHfQul4nMOwVRB323PY1jh ToaGRHYBLmMSIXv9ROLo0Yj+z1XMrza6uLHzEp9cg18/jltCp3hYuv26qDkqgfv9J46Pk4WzKpl W6GWG4/4uZf+G8mLxr50wHGKuCqJJ2JNTrgLaMD3pFpHmT6EKGiLg/vZHjaCm2pb6/q7p8yBl3W a X-Received: by 2002:a17:902:d48e:b0:295:570d:116e with SMTP id d9443c01a7336-2986a74a03amr203814795ad.41.1763524042711; Tue, 18 Nov 2025 19:47:22 -0800 (PST) X-Google-Smtp-Source: AGHT+IGKYqgZfFXPmK/y5ioIfktkqnDZ4BIIot5KWSoNG8E059/HCjYd/LVVgtAco2dIKSYFg6P4mA== X-Received: by 2002:a17:902:d48e:b0:295:570d:116e with SMTP id d9443c01a7336-2986a74a03amr203814415ad.41.1763524042118; Tue, 18 Nov 2025 19:47:22 -0800 (PST) Received: from localhost ([209.132.188.88]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2985c2b06b6sm189666015ad.55.2025.11.18.19.47.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Nov 2025 19:47:21 -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 v3] ima: Access decompressed kernel module to verify appended signature Date: Wed, 19 Nov 2025 11:47:16 +0800 Message-ID: <20251119034718.618008-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 know only to collect original 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 cdd225f65a62..49f8b2b1a9af 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; } @@ -578,13 +585,13 @@ static int ima_bprm_check(struct linux_binprm *bprm) =20 security_current_getlsmprop_subj(&prop); ret =3D process_measurement(bprm->file, current_cred(), - &prop, NULL, 0, MAY_EXEC, BPRM_CHECK); + &prop, NULL, 0, MAY_EXEC, BPRM_CHECK, 0); if (ret) return ret; =20 security_cred_getlsmprop(bprm->cred, &prop); return process_measurement(bprm->file, bprm->cred, &prop, NULL, 0, - MAY_EXEC, CREDS_CHECK); + MAY_EXEC, CREDS_CHECK, 0); } =20 /** @@ -632,7 +639,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, @@ -851,12 +858,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 @@ -894,7 +902,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 128fab897930..ae520e6bb1cf 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -241,7 +241,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: 6a23ae0a96a600d1d12557add110e0bb6e32730c --=20 2.51.1