ima: Access decompressed kernel module to verify appended signature

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=secure_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=MODULE_CHECK appraise_type=imasig|modsig".

Reported-by: Karel Srot <ksrot@redhat.com>
Suggested-by: Mimi Zohar <zohar@linux.ibm.com>
Suggested-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Coiby Xu <coxu@redhat.com>
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
This commit is contained in:
Coiby Xu
2025-11-19 22:03:25 +08:00
committed by Mimi Zohar
parent 4336927351
commit c200892b46
6 changed files with 37 additions and 14 deletions

View File

@@ -3675,24 +3675,35 @@ static int idempotent_wait_for_completion(struct idempotent *u)
static int init_module_from_file(struct file *f, const char __user * uargs, int flags)
{
bool compressed = !!(flags & MODULE_INIT_COMPRESSED_FILE);
struct load_info info = { };
void *buf = NULL;
int len;
int err;
len = kernel_read_file(f, 0, &buf, INT_MAX, NULL, READING_MODULE);
len = 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;
}
if (flags & MODULE_INIT_COMPRESSED_FILE) {
int err = module_decompress(&info, buf, len);
if (compressed) {
err = 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 = 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 = buf;
info.len = len;