Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

LSM: Add "contents" flag to kernel_read_file hook

As with the kernel_load_data LSM hook, add a "contents" flag to the
kernel_read_file LSM hook that indicates whether the LSM can expect
a matching call to the kernel_post_read_file LSM hook with the full
contents of the file. With the coming addition of partial file read
support for kernel_read_file*() API, the LSM will no longer be able
to always see the entire contents of a file during the read calls.

For cases where the LSM must read examine the complete file contents,
it will need to do so on its own every time the kernel_read_file
hook is called with contents=false (or reject such cases). Adjust all
existing LSMs to retain existing behavior.

Signed-off-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Link: https://lore.kernel.org/r/20201002173828.2099543-12-keescook@chromium.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Kees Cook and committed by
Greg Kroah-Hartman
2039bda1 38f90173

+41 -14
+1 -1
fs/kernel_read_file.c
··· 39 39 if (ret) 40 40 return ret; 41 41 42 - ret = security_kernel_read_file(file, id); 42 + ret = security_kernel_read_file(file, id, true); 43 43 if (ret) 44 44 goto out; 45 45
+4 -2
include/linux/ima.h
··· 23 23 extern int ima_load_data(enum kernel_load_data_id id, bool contents); 24 24 extern int ima_post_load_data(char *buf, loff_t size, 25 25 enum kernel_load_data_id id, char *description); 26 - extern int ima_read_file(struct file *file, enum kernel_read_file_id id); 26 + extern int ima_read_file(struct file *file, enum kernel_read_file_id id, 27 + bool contents); 27 28 extern int ima_post_read_file(struct file *file, void *buf, loff_t size, 28 29 enum kernel_read_file_id id); 29 30 extern void ima_post_path_mknod(struct dentry *dentry); ··· 93 92 return 0; 94 93 } 95 94 96 - static inline int ima_read_file(struct file *file, enum kernel_read_file_id id) 95 + static inline int ima_read_file(struct file *file, enum kernel_read_file_id id, 96 + bool contents) 97 97 { 98 98 return 0; 99 99 }
+1 -1
include/linux/lsm_hook_defs.h
··· 188 188 LSM_HOOK(int, 0, kernel_post_load_data, char *buf, loff_t size, 189 189 enum kernel_read_file_id id, char *description) 190 190 LSM_HOOK(int, 0, kernel_read_file, struct file *file, 191 - enum kernel_read_file_id id) 191 + enum kernel_read_file_id id, bool contents) 192 192 LSM_HOOK(int, 0, kernel_post_read_file, struct file *file, char *buf, 193 193 loff_t size, enum kernel_read_file_id id) 194 194 LSM_HOOK(int, 0, task_fix_setuid, struct cred *new, const struct cred *old,
+3
include/linux/lsm_hooks.h
··· 651 651 * @file contains the file structure pointing to the file being read 652 652 * by the kernel. 653 653 * @id kernel read file identifier 654 + * @contents if a subsequent @kernel_post_read_file will be called. 654 655 * Return 0 if permission is granted. 655 656 * @kernel_post_read_file: 656 657 * Read a file specified by userspace. ··· 660 659 * @buf pointer to buffer containing the file contents. 661 660 * @size length of the file contents. 662 661 * @id kernel read file identifier 662 + * This must be paired with a prior @kernel_read_file call that had 663 + * @contents set to true. 663 664 * Return 0 if permission is granted. 664 665 * @task_fix_setuid: 665 666 * Update the module's state after setting one or more of the user
+4 -2
include/linux/security.h
··· 391 391 int security_kernel_post_load_data(char *buf, loff_t size, 392 392 enum kernel_load_data_id id, 393 393 char *description); 394 - int security_kernel_read_file(struct file *file, enum kernel_read_file_id id); 394 + int security_kernel_read_file(struct file *file, enum kernel_read_file_id id, 395 + bool contents); 395 396 int security_kernel_post_read_file(struct file *file, char *buf, loff_t size, 396 397 enum kernel_read_file_id id); 397 398 int security_task_fix_setuid(struct cred *new, const struct cred *old, ··· 1031 1030 } 1032 1031 1033 1032 static inline int security_kernel_read_file(struct file *file, 1034 - enum kernel_read_file_id id) 1033 + enum kernel_read_file_id id, 1034 + bool contents) 1035 1035 { 1036 1036 return 0; 1037 1037 }
+9 -1
security/integrity/ima/ima_main.c
··· 602 602 * ima_read_file - pre-measure/appraise hook decision based on policy 603 603 * @file: pointer to the file to be measured/appraised/audit 604 604 * @read_id: caller identifier 605 + * @contents: whether a subsequent call will be made to ima_post_read_file() 605 606 * 606 607 * Permit reading a file based on policy. The policy rules are written 607 608 * in terms of the policy identifier. Appraising the integrity of ··· 610 609 * 611 610 * For permission return 0, otherwise return -EACCES. 612 611 */ 613 - int ima_read_file(struct file *file, enum kernel_read_file_id read_id) 612 + int ima_read_file(struct file *file, enum kernel_read_file_id read_id, 613 + bool contents) 614 614 { 615 + /* Reject all partial reads during appraisal. */ 616 + if (!contents) { 617 + if (ima_appraise & IMA_APPRAISE_ENFORCE) 618 + return -EACCES; 619 + } 620 + 615 621 /* 616 622 * Do devices using pre-allocated memory run the risk of the 617 623 * firmware being accessible to the device prior to the completion
+12 -2
security/loadpin/loadpin.c
··· 118 118 } 119 119 } 120 120 121 - static int loadpin_read_file(struct file *file, enum kernel_read_file_id id) 121 + static int loadpin_read_file(struct file *file, enum kernel_read_file_id id, 122 + bool contents) 122 123 { 123 124 struct super_block *load_root; 124 125 const char *origin = kernel_read_file_id_str(id); 126 + 127 + /* 128 + * If we will not know that we'll be seeing the full contents 129 + * then we cannot trust a load will be complete and unchanged 130 + * off disk. Treat all contents=false hooks as if there were 131 + * no associated file struct. 132 + */ 133 + if (!contents) 134 + file = NULL; 125 135 126 136 /* If the file id is excluded, ignore the pinning. */ 127 137 if ((unsigned int)id < ARRAY_SIZE(ignore_read_file_id) && ··· 189 179 190 180 static int loadpin_load_data(enum kernel_load_data_id id, bool contents) 191 181 { 192 - return loadpin_read_file(NULL, (enum kernel_read_file_id) id); 182 + return loadpin_read_file(NULL, (enum kernel_read_file_id) id, contents); 193 183 } 194 184 195 185 static struct security_hook_list loadpin_hooks[] __lsm_ro_after_init = {
+4 -3
security/security.c
··· 1672 1672 return integrity_kernel_module_request(kmod_name); 1673 1673 } 1674 1674 1675 - int security_kernel_read_file(struct file *file, enum kernel_read_file_id id) 1675 + int security_kernel_read_file(struct file *file, enum kernel_read_file_id id, 1676 + bool contents) 1676 1677 { 1677 1678 int ret; 1678 1679 1679 - ret = call_int_hook(kernel_read_file, 0, file, id); 1680 + ret = call_int_hook(kernel_read_file, 0, file, id, contents); 1680 1681 if (ret) 1681 1682 return ret; 1682 - return ima_read_file(file, id); 1683 + return ima_read_file(file, id, contents); 1683 1684 } 1684 1685 EXPORT_SYMBOL_GPL(security_kernel_read_file); 1685 1686
+3 -2
security/selinux/hooks.c
··· 4003 4003 } 4004 4004 4005 4005 static int selinux_kernel_read_file(struct file *file, 4006 - enum kernel_read_file_id id) 4006 + enum kernel_read_file_id id, 4007 + bool contents) 4007 4008 { 4008 4009 int rc = 0; 4009 4010 4010 4011 switch (id) { 4011 4012 case READING_MODULE: 4012 - rc = selinux_kernel_module_from_file(file); 4013 + rc = selinux_kernel_module_from_file(contents ? file : NULL); 4013 4014 break; 4014 4015 default: 4015 4016 break;