Skip to content

Commit c200892

Browse files
coibymimizohar
authored andcommitted
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>
1 parent 4336927 commit c200892

6 files changed

Lines changed: 37 additions & 14 deletions

File tree

include/linux/kernel_read_file.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
id(KEXEC_INITRAMFS, kexec-initramfs) \
1515
id(POLICY, security-policy) \
1616
id(X509_CERTIFICATE, x509-certificate) \
17+
id(MODULE_COMPRESSED, kernel-module-compressed) \
1718
id(MAX_ID, )
1819

1920
#define __fid_enumify(ENUM, dummy) READING_ ## ENUM,

kernel/module/main.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3675,24 +3675,35 @@ static int idempotent_wait_for_completion(struct idempotent *u)
36753675

36763676
static int init_module_from_file(struct file *f, const char __user * uargs, int flags)
36773677
{
3678+
bool compressed = !!(flags & MODULE_INIT_COMPRESSED_FILE);
36783679
struct load_info info = { };
36793680
void *buf = NULL;
36803681
int len;
3682+
int err;
36813683

3682-
len = kernel_read_file(f, 0, &buf, INT_MAX, NULL, READING_MODULE);
3684+
len = kernel_read_file(f, 0, &buf, INT_MAX, NULL,
3685+
compressed ? READING_MODULE_COMPRESSED :
3686+
READING_MODULE);
36833687
if (len < 0) {
36843688
mod_stat_inc(&failed_kreads);
36853689
return len;
36863690
}
36873691

3688-
if (flags & MODULE_INIT_COMPRESSED_FILE) {
3689-
int err = module_decompress(&info, buf, len);
3692+
if (compressed) {
3693+
err = module_decompress(&info, buf, len);
36903694
vfree(buf); /* compressed data is no longer needed */
36913695
if (err) {
36923696
mod_stat_inc(&failed_decompress);
36933697
mod_stat_add_long(len, &invalid_decompress_bytes);
36943698
return err;
36953699
}
3700+
err = security_kernel_post_read_file(f, (char *)info.hdr, info.len,
3701+
READING_MODULE);
3702+
if (err) {
3703+
mod_stat_inc(&failed_kreads);
3704+
free_copy(&info, flags);
3705+
return err;
3706+
}
36963707
} else {
36973708
info.hdr = buf;
36983709
info.len = len;

security/integrity/ima/ima_main.c

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,8 @@ static void ima_file_free(struct file *file)
235235

236236
static int process_measurement(struct file *file, const struct cred *cred,
237237
struct lsm_prop *prop, char *buf, loff_t size,
238-
int mask, enum ima_hooks func)
238+
int mask, enum ima_hooks func,
239+
enum kernel_read_file_id read_id)
239240
{
240241
struct inode *real_inode, *inode = file_inode(file);
241242
struct ima_iint_cache *iint = NULL;
@@ -406,6 +407,12 @@ static int process_measurement(struct file *file, const struct cred *cred,
406407
if (rc != 0 && rc != -EBADF && rc != -EINVAL)
407408
goto out_locked;
408409

410+
/* Defer measuring/appraising kernel modules to READING_MODULE */
411+
if (read_id == READING_MODULE_COMPRESSED) {
412+
must_appraise = 0;
413+
goto out_locked;
414+
}
415+
409416
if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */
410417
pathname = ima_d_path(&file->f_path, &pathbuf, filename);
411418

@@ -486,14 +493,14 @@ static int ima_file_mmap(struct file *file, unsigned long reqprot,
486493

487494
if (reqprot & PROT_EXEC) {
488495
ret = process_measurement(file, current_cred(), &prop, NULL,
489-
0, MAY_EXEC, MMAP_CHECK_REQPROT);
496+
0, MAY_EXEC, MMAP_CHECK_REQPROT, 0);
490497
if (ret)
491498
return ret;
492499
}
493500

494501
if (prot & PROT_EXEC)
495502
return process_measurement(file, current_cred(), &prop, NULL,
496-
0, MAY_EXEC, MMAP_CHECK);
503+
0, MAY_EXEC, MMAP_CHECK, 0);
497504

498505
return 0;
499506
}
@@ -577,7 +584,7 @@ static int ima_bprm_check(struct linux_binprm *bprm)
577584

578585
security_current_getlsmprop_subj(&prop);
579586
return process_measurement(bprm->file, current_cred(),
580-
&prop, NULL, 0, MAY_EXEC, BPRM_CHECK);
587+
&prop, NULL, 0, MAY_EXEC, BPRM_CHECK, 0);
581588
}
582589

583590
/**
@@ -607,7 +614,7 @@ static int ima_creds_check(struct linux_binprm *bprm, const struct file *file)
607614

608615
security_current_getlsmprop_subj(&prop);
609616
return process_measurement((struct file *)file, bprm->cred, &prop, NULL,
610-
0, MAY_EXEC, CREDS_CHECK);
617+
0, MAY_EXEC, CREDS_CHECK, 0);
611618
}
612619

613620
/**
@@ -655,7 +662,7 @@ static int ima_file_check(struct file *file, int mask)
655662
security_current_getlsmprop_subj(&prop);
656663
return process_measurement(file, current_cred(), &prop, NULL, 0,
657664
mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
658-
MAY_APPEND), FILE_CHECK);
665+
MAY_APPEND), FILE_CHECK, 0);
659666
}
660667

661668
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 kernel_read_file_id read_id,
874881
func = read_idmap[read_id] ?: FILE_CHECK;
875882
security_current_getlsmprop_subj(&prop);
876883
return process_measurement(file, current_cred(), &prop, NULL, 0,
877-
MAY_READ, func);
884+
MAY_READ, func, 0);
878885
}
879886

880887
const int read_idmap[READING_MAX_ID] = {
881888
[READING_FIRMWARE] = FIRMWARE_CHECK,
882889
[READING_MODULE] = MODULE_CHECK,
890+
[READING_MODULE_COMPRESSED] = MODULE_CHECK,
883891
[READING_KEXEC_IMAGE] = KEXEC_KERNEL_CHECK,
884892
[READING_KEXEC_INITRAMFS] = KEXEC_INITRAMFS_CHECK,
885893
[READING_POLICY] = POLICY_CHECK
@@ -917,7 +925,7 @@ static int ima_post_read_file(struct file *file, char *buf, loff_t size,
917925
func = read_idmap[read_id] ?: FILE_CHECK;
918926
security_current_getlsmprop_subj(&prop);
919927
return process_measurement(file, current_cred(), &prop, buf, size,
920-
MAY_READ, func);
928+
MAY_READ, func, read_id);
921929
}
922930

923931
/**

security/integrity/ima/ima_policy.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,8 @@ static struct ima_rule_entry build_appraise_rules[] __ro_after_init = {
244244

245245
static struct ima_rule_entry secure_boot_rules[] __ro_after_init = {
246246
{.action = APPRAISE, .func = MODULE_CHECK,
247-
.flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
247+
.flags = IMA_FUNC | IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED |
248+
IMA_CHECK_BLACKLIST},
248249
{.action = APPRAISE, .func = FIRMWARE_CHECK,
249250
.flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
250251
{.action = APPRAISE, .func = KEXEC_KERNEL_CHECK,

security/ipe/hooks.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ int ipe_kernel_read_file(struct file *file, enum kernel_read_file_id id,
118118
op = IPE_OP_FIRMWARE;
119119
break;
120120
case READING_MODULE:
121+
case READING_MODULE_COMPRESSED:
121122
op = IPE_OP_KERNEL_MODULE;
122123
break;
123124
case READING_KEXEC_INITRAMFS:

security/selinux/hooks.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4275,14 +4275,15 @@ static int selinux_kernel_read_file(struct file *file,
42754275
{
42764276
int rc = 0;
42774277

4278-
BUILD_BUG_ON_MSG(READING_MAX_ID > 7,
4278+
BUILD_BUG_ON_MSG(READING_MAX_ID > 8,
42794279
"New kernel_read_file_id introduced; update SELinux!");
42804280

42814281
switch (id) {
42824282
case READING_FIRMWARE:
42834283
rc = selinux_kernel_load_from_file(file, SYSTEM__FIRMWARE_LOAD);
42844284
break;
42854285
case READING_MODULE:
4286+
case READING_MODULE_COMPRESSED:
42864287
rc = selinux_kernel_load_from_file(file, SYSTEM__MODULE_LOAD);
42874288
break;
42884289
case READING_KEXEC_IMAGE:
@@ -4311,7 +4312,7 @@ static int selinux_kernel_load_data(enum kernel_load_data_id id, bool contents)
43114312
{
43124313
int rc = 0;
43134314

4314-
BUILD_BUG_ON_MSG(LOADING_MAX_ID > 7,
4315+
BUILD_BUG_ON_MSG(LOADING_MAX_ID > 8,
43154316
"New kernel_load_data_id introduced; update SELinux!");
43164317

43174318
switch (id) {

0 commit comments

Comments
 (0)