Hi, Mimi CCing kexec list, not all kexec people subscribed to IMA list. I just subscribed to it since Vivek CCed me last time about the V1 of this series. On 12/23/15 at 06:55pm, Mimi Zohar wrote: > This patch defines a new IMA hook ima_hash_and_process_file() for > measuring and appraising files read by the kernel. The caller loads > the file into memory before calling this function, which calculates > the hash followed by the normal IMA policy based processing. > > Two new IMA policy functions named KEXEC_CHECK and INITRAMFS_CHECK > are defined for measuring, appraising or auditing the kexec image > and initramfs. Could you help us understand why do we need it first. I think I do not really understand the purpose of the IMA handling about kexec kernel and initramfs. * Does the files in disk space have already contains some hash values and when kernel load it IMA functions will do some checking? But seems I do not see such handling.. * Does it try to calculate the hash of the file buffer after copying, and IMA will avoid future modification based on the hash calculated? If this is the purpose I think it should be wrong because kexe file buffers will be freed at the end of kexec_file_load syscall. > > Changelog v2: > - Calculate the file hash from the in memory buffer (suggested by Dave Young) > - Rename ima_read_and_process_file() to ima_hash_and_process_file() > - replace individual case statements with range: > KEXEC_CHECK ... IMA_MAX_READ_CHECK - 1 > v1: > - Instead of ima_read_and_process_file() allocating memory, the caller > allocates and frees the memory. > - Moved the kexec measurement/appraisal call to copy_file_from_fd(). The > same call now measures and appraises both the kexec image and initramfs. > > Signed-off-by: Mimi Zohar <zohar at linux.vnet.ibm.com> > --- > Documentation/ABI/testing/ima_policy | 2 +- > include/linux/ima.h | 16 ++++++++++++++ > kernel/kexec_file.c | 24 ++++++++++++-------- > security/integrity/iint.c | 1 + > security/integrity/ima/ima.h | 21 ++++++++++++------ > security/integrity/ima/ima_api.c | 6 +++-- > security/integrity/ima/ima_appraise.c | 11 ++++++++-- > security/integrity/ima/ima_main.c | 41 ++++++++++++++++++++++++++++------- > security/integrity/ima/ima_policy.c | 38 ++++++++++++++++++++++++-------- > security/integrity/integrity.h | 7 ++++-- > 10 files changed, 127 insertions(+), 40 deletions(-) > > diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy > index 0a378a8..e80f767 100644 > --- a/Documentation/ABI/testing/ima_policy > +++ b/Documentation/ABI/testing/ima_policy > @@ -26,7 +26,7 @@ Description: > option: [[appraise_type=]] [permit_directio] > > base: func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK] > - [FIRMWARE_CHECK] > + [FIRMWARE_CHECK] [KEXEC_CHECK] [INITRAMFS_CHECK] > mask:= [[^]MAY_READ] [[^]MAY_WRITE] [[^]MAY_APPEND] > [[^]MAY_EXEC] > fsmagic:= hex value > diff --git a/include/linux/ima.h b/include/linux/ima.h > index 120ccc5..020de0f 100644 > --- a/include/linux/ima.h > +++ b/include/linux/ima.h > @@ -13,6 +13,12 @@ > #include <linux/fs.h> > struct linux_binprm; > > +enum ima_read_hooks { > + KEXEC_CHECK = 1, > + INITRAMFS_CHECK, > + IMA_MAX_READ_CHECK > +}; > + > #ifdef CONFIG_IMA > extern int ima_bprm_check(struct linux_binprm *bprm); > extern int ima_file_check(struct file *file, int mask, int opened); > @@ -20,6 +26,9 @@ extern void ima_file_free(struct file *file); > extern int ima_file_mmap(struct file *file, unsigned long prot); > extern int ima_module_check(struct file *file); > extern int ima_fw_from_file(struct file *file, char *buf, size_t size); > +extern int ima_hash_and_process_file(struct file *file, > + void *buf, size_t size, > + enum ima_read_hooks read_func); > > #else > static inline int ima_bprm_check(struct linux_binprm *bprm) > @@ -52,6 +61,13 @@ static inline int ima_fw_from_file(struct file *file, char *buf, size_t size) > return 0; > } > > +static inline int ima_hash_and_process_file(struct file *file, > + void *buf, size_t size, > + enum ima_read_hooks read_func) > +{ > + return 0; > +} > + > #endif /* CONFIG_IMA */ > > #ifdef CONFIG_IMA_APPRAISE > diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c > index b70ada0..1d0d998 100644 > --- a/kernel/kexec_file.c > +++ b/kernel/kexec_file.c > @@ -18,6 +18,7 @@ > #include <linux/kexec.h> > #include <linux/mutex.h> > #include <linux/list.h> > +#include <linux/ima.h> > #include <crypto/hash.h> > #include <crypto/sha.h> > #include <linux/syscalls.h> > @@ -33,7 +34,8 @@ size_t __weak kexec_purgatory_size = 0; > > static int kexec_calculate_store_digests(struct kimage *image); > > -static int copy_file_from_fd(int fd, void **buf, unsigned long *buf_len) > +static int copy_file_from_fd(int fd, void **buf, unsigned long *buf_len, > + enum ima_read_hooks read_func) > { > struct fd f = fdget(fd); > int ret; > @@ -70,9 +72,8 @@ static int copy_file_from_fd(int fd, void **buf, unsigned long *buf_len) > bytes = kernel_read(f.file, pos, (char *)(*buf) + pos, > stat.size - pos); > if (bytes < 0) { > - vfree(*buf); > ret = bytes; > - goto out; > + goto out_free; > } > > if (bytes == 0) > @@ -80,13 +81,17 @@ static int copy_file_from_fd(int fd, void **buf, unsigned long *buf_len) > pos += bytes; > } > > - if (pos != stat.size) { > + if (pos != stat.size) > ret = -EBADF; > + > + ret = ima_hash_and_process_file(f.file, *buf, stat.size, read_func); > + if (!ret) > + *buf_len = pos; > +out_free: > + if (ret < 0) { > vfree(*buf); > - goto out; > + *buf = NULL; > } > - > - *buf_len = pos; > out: > fdput(f); > return ret; > @@ -182,7 +187,7 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd, > void *ldata; > > ret = copy_file_from_fd(kernel_fd, &image->kernel_buf, > - &image->kernel_buf_len); > + &image->kernel_buf_len, KEXEC_CHECK); > if (ret) > return ret; > > @@ -205,7 +210,8 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd, > /* It is possible that there no initramfs is being loaded */ > if (!(flags & KEXEC_FILE_NO_INITRAMFS)) { > ret = copy_file_from_fd(initrd_fd, &image->initrd_buf, > - &image->initrd_buf_len); > + &image->initrd_buf_len, > + INITRAMFS_CHECK); > if (ret) > goto out; > } > diff --git a/security/integrity/iint.c b/security/integrity/iint.c > index 54b51a4..8a45576 100644 > --- a/security/integrity/iint.c > +++ b/security/integrity/iint.c > @@ -158,6 +158,7 @@ static void init_once(void *foo) > iint->ima_mmap_status = INTEGRITY_UNKNOWN; > iint->ima_bprm_status = INTEGRITY_UNKNOWN; > iint->ima_module_status = INTEGRITY_UNKNOWN; > + iint->ima_read_status = INTEGRITY_UNKNOWN; > iint->evm_status = INTEGRITY_UNKNOWN; > } > > diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h > index e3a5b7b..fa801fa 100644 > --- a/security/integrity/ima/ima.h > +++ b/security/integrity/ima/ima.h > @@ -20,6 +20,7 @@ > #include <linux/types.h> > #include <linux/crypto.h> > #include <linux/security.h> > +#include <linux/ima.h> > #include <linux/hash.h> > #include <linux/tpm.h> > #include <linux/audit.h> > @@ -143,7 +144,8 @@ static inline unsigned long ima_hash_key(u8 *digest) > int ima_get_action(struct inode *inode, int mask, int function); > int ima_must_measure(struct inode *inode, int mask, int function); > int ima_collect_measurement(struct integrity_iint_cache *iint, > - struct file *file, enum hash_algo algo); > + struct file *file, void *buf, size_t buf_len, > + enum hash_algo algo); > void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, > const unsigned char *filename, > struct evm_ima_xattr_data *xattr_value, > @@ -158,10 +160,16 @@ void ima_free_template_entry(struct ima_template_entry *entry); > const char *ima_d_path(struct path *path, char **pathbuf); > > /* IMA policy related functions */ > -enum ima_hooks { FILE_CHECK = 1, MMAP_CHECK, BPRM_CHECK, MODULE_CHECK, FIRMWARE_CHECK, POST_SETATTR }; > +enum ima_hooks { > + FILE_CHECK = IMA_MAX_READ_CHECK, > + MMAP_CHECK, > + BPRM_CHECK, > + MODULE_CHECK, > + FIRMWARE_CHECK, > + POST_SETATTR > +}; > > -int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, > - int flags); > +int ima_match_policy(struct inode *inode, int func, int mask, int flags); > void ima_init_policy(void); > void ima_update_policy(void); > void ima_update_policy_flag(void); > @@ -184,7 +192,7 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, > struct file *file, const unsigned char *filename, > struct evm_ima_xattr_data *xattr_value, > int xattr_len, int opened); > -int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func); > +int ima_must_appraise(struct inode *inode, int mask, int func); > void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); > enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, > int func); > @@ -204,8 +212,7 @@ static inline int ima_appraise_measurement(int func, > return INTEGRITY_UNKNOWN; > } > > -static inline int ima_must_appraise(struct inode *inode, int mask, > - enum ima_hooks func) > +static inline int ima_must_appraise(struct inode *inode, int mask, int func) > { > return 0; > } > diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c > index e7c7a5d..f3a5b0b 100644 > --- a/security/integrity/ima/ima_api.c > +++ b/security/integrity/ima/ima_api.c > @@ -188,7 +188,8 @@ int ima_get_action(struct inode *inode, int mask, int function) > * Return 0 on success, error code otherwise > */ > int ima_collect_measurement(struct integrity_iint_cache *iint, > - struct file *file, enum hash_algo algo) > + struct file *file, void *buf, unsigned long buf_len, > + enum hash_algo algo) > { > const char *audit_cause = "failed"; > struct inode *inode = file_inode(file); > @@ -210,7 +211,8 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, > > hash.hdr.algo = algo; > > - result = ima_calc_file_hash(file, &hash.hdr); > + result = (!buf) ? ima_calc_file_hash(file, &hash.hdr) : > + ima_calc_buffer_hash(buf, buf_len, &hash.hdr); > if (!result) { > int length = sizeof(hash.hdr) + hash.hdr.length; > void *tmpbuf = krealloc(iint->ima_hash, length, > diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c > index 9c2b46b..3adf937 100644 > --- a/security/integrity/ima/ima_appraise.c > +++ b/security/integrity/ima/ima_appraise.c > @@ -36,7 +36,7 @@ __setup("ima_appraise=", default_appraise_setup); > * > * Return 1 to appraise > */ > -int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func) > +int ima_must_appraise(struct inode *inode, int mask, int func) > { > if (!ima_appraise) > return 0; > @@ -78,6 +78,8 @@ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, > return iint->ima_module_status; > case FIRMWARE_CHECK: > return iint->ima_firmware_status; > + case KEXEC_CHECK ... IMA_MAX_READ_CHECK - 1: > + return iint->ima_read_status; > case FILE_CHECK: > default: > return iint->ima_file_status; > @@ -100,6 +102,9 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint, > case FIRMWARE_CHECK: > iint->ima_firmware_status = status; > break; > + case KEXEC_CHECK ... IMA_MAX_READ_CHECK - 1: > + iint->ima_read_status = status; > + break; > case FILE_CHECK: > default: > iint->ima_file_status = status; > @@ -122,6 +127,8 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func) > case FIRMWARE_CHECK: > iint->flags |= (IMA_FIRMWARE_APPRAISED | IMA_APPRAISED); > break; > + case KEXEC_CHECK ... IMA_MAX_READ_CHECK - 1: > + break; > case FILE_CHECK: > default: > iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED); > @@ -299,7 +306,7 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) > if (iint->flags & IMA_DIGSIG) > return; > > - rc = ima_collect_measurement(iint, file, ima_hash_algo); > + rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo); > if (rc < 0) > return; > > diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c > index d9fc463..cd9c576 100644 > --- a/security/integrity/ima/ima_main.c > +++ b/security/integrity/ima/ima_main.c > @@ -153,8 +153,8 @@ void ima_file_free(struct file *file) > ima_check_last_writer(iint, inode, file); > } > > -static int process_measurement(struct file *file, int mask, int function, > - int opened) > +static int process_measurement(struct file *file, char *buf, size_t buf_len, > + int mask, int function, int opened) > { > struct inode *inode = file_inode(file); > struct integrity_iint_cache *iint = NULL; > @@ -226,7 +226,7 @@ static int process_measurement(struct file *file, int mask, int function, > > hash_algo = ima_get_hash_algo(xattr_value, xattr_len); > > - rc = ima_collect_measurement(iint, file, hash_algo); > + rc = ima_collect_measurement(iint, file, buf, buf_len, hash_algo); > if (rc != 0) { > if (file->f_flags & O_DIRECT) > rc = (iint->flags & IMA_PERMIT_DIRECTIO) ? 0 : -EACCES; > @@ -273,7 +273,8 @@ out: > int ima_file_mmap(struct file *file, unsigned long prot) > { > if (file && (prot & PROT_EXEC)) > - return process_measurement(file, MAY_EXEC, MMAP_CHECK, 0); > + return process_measurement(file, NULL, 0, MAY_EXEC, > + MMAP_CHECK, 0); > return 0; > } > > @@ -292,7 +293,8 @@ int ima_file_mmap(struct file *file, unsigned long prot) > */ > int ima_bprm_check(struct linux_binprm *bprm) > { > - return process_measurement(bprm->file, MAY_EXEC, BPRM_CHECK, 0); > + return process_measurement(bprm->file, NULL, 0, MAY_EXEC, > + BPRM_CHECK, 0); > } > > /** > @@ -307,7 +309,7 @@ int ima_bprm_check(struct linux_binprm *bprm) > */ > int ima_file_check(struct file *file, int mask, int opened) > { > - return process_measurement(file, > + return process_measurement(file, NULL, 0, > mask & (MAY_READ | MAY_WRITE | MAY_EXEC), > FILE_CHECK, opened); > } > @@ -332,7 +334,7 @@ int ima_module_check(struct file *file) > #endif > return 0; /* We rely on module signature checking */ > } > - return process_measurement(file, MAY_EXEC, MODULE_CHECK, 0); > + return process_measurement(file, NULL, 0, MAY_EXEC, MODULE_CHECK, 0); > } > > int ima_fw_from_file(struct file *file, char *buf, size_t size) > @@ -343,7 +345,30 @@ int ima_fw_from_file(struct file *file, char *buf, size_t size) > return -EACCES; /* INTEGRITY_UNKNOWN */ > return 0; > } > - return process_measurement(file, MAY_EXEC, FIRMWARE_CHECK, 0); > + return process_measurement(file, NULL, 0, MAY_EXEC, FIRMWARE_CHECK, 0); > +} > + > +/** > + * ima_hash_and_process_file - in memory collect/appraise/audit measurement > + * @file: pointer to the file to be measured/appraised/audit > + * @buf: pointer to in memory file contents > + * @buf_len: size of in memory file contents > + * @read_func: caller identifier > + * > + * Measure/appraise/audit in memory file based on policy. Policy rules > + * are written in terms of the read_func identifier (eg. KEXEC_CHECK, > + * INITRAMFS_CHECK) > + */ > +int ima_hash_and_process_file(struct file *file, void *buf, size_t buf_len, > + enum ima_read_hooks read_func) > +{ > + if (!file || !buf || buf_len == 0) { /* should never happen */ > + if (ima_appraise & IMA_APPRAISE_ENFORCE) > + return -EACCES; > + return 0; > + } > + > + return process_measurement(file, buf, buf_len, MAY_READ, read_func, 0); > } > > static int __init init_ima(void) > diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c > index ba5d2fc..26e24df 100644 > --- a/security/integrity/ima/ima_policy.c > +++ b/security/integrity/ima/ima_policy.c > @@ -53,7 +53,10 @@ struct ima_rule_entry { > struct list_head list; > int action; > unsigned int flags; > - enum ima_hooks func; > + union { > + enum ima_hooks func; > + enum ima_read_hooks read_func; > + }; > int mask; > unsigned long fsmagic; > u8 fsuuid[16]; > @@ -208,7 +211,7 @@ static void ima_lsm_update_rules(void) > * Returns true on rule match, false on failure. > */ > static bool ima_match_rules(struct ima_rule_entry *rule, > - struct inode *inode, enum ima_hooks func, int mask) > + struct inode *inode, int func, int mask) > { > struct task_struct *tsk = current; > const struct cred *cred = current_cred(); > @@ -303,6 +306,8 @@ static int get_subaction(struct ima_rule_entry *rule, int func) > return IMA_MODULE_APPRAISE; > case FIRMWARE_CHECK: > return IMA_FIRMWARE_APPRAISE; > + case KEXEC_CHECK ... IMA_MAX_READ_CHECK - 1: > + return IMA_READ_APPRAISE; > case FILE_CHECK: > default: > return IMA_FILE_APPRAISE; > @@ -322,8 +327,7 @@ static int get_subaction(struct ima_rule_entry *rule, int func) > * list when walking it. Reads are many orders of magnitude more numerous > * than writes so ima_match_policy() is classical RCU candidate. > */ > -int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, > - int flags) > +int ima_match_policy(struct inode *inode, int func, int mask, int flags) > { > struct ima_rule_entry *entry; > int action = 0, actmask = flags | (flags << 1); > @@ -604,6 +608,10 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) > entry->func = MMAP_CHECK; > else if (strcmp(args[0].from, "BPRM_CHECK") == 0) > entry->func = BPRM_CHECK; > + else if (strcmp(args[0].from, "KEXEC_CHECK") == 0) > + entry->read_func = KEXEC_CHECK; > + else if (strcmp(args[0].from, "INITRAMFS_CHECK") == 0) > + entry->read_func = INITRAMFS_CHECK; > else > result = -EINVAL; > if (!result) > @@ -847,7 +855,8 @@ static char *mask_tokens[] = { > > enum { > func_file = 0, func_mmap, func_bprm, > - func_module, func_firmware, func_post > + func_module, func_firmware, func_post, > + func_kexec, func_initramfs > }; > > static char *func_tokens[] = { > @@ -856,7 +865,9 @@ static char *func_tokens[] = { > "BPRM_CHECK", > "MODULE_CHECK", > "FIRMWARE_CHECK", > - "POST_SETATTR" > + "POST_SETATTR", > + "KEXEC_CHECK", > + "INITRAMFS_CHECK", > }; > > void *ima_policy_start(struct seq_file *m, loff_t *pos) > @@ -937,9 +948,18 @@ int ima_policy_show(struct seq_file *m, void *v) > seq_printf(m, pt(Opt_func), ft(func_post)); > break; > default: > - snprintf(tbuf, sizeof(tbuf), "%d", entry->func); > - seq_printf(m, pt(Opt_func), tbuf); > - break; > + switch (entry->read_func) { > + case KEXEC_CHECK: > + seq_printf(m, pt(Opt_func), ft(func_kexec)); > + break; > + case INITRAMFS_CHECK: > + seq_printf(m, pt(Opt_func), ft(func_initramfs)); > + break; > + default: > + snprintf(tbuf, sizeof(tbuf), "%d", entry->func); > + seq_printf(m, pt(Opt_func), tbuf); > + break; > + } > } > seq_puts(m, " "); > } > diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h > index 5413f22..645d5be 100644 > --- a/security/integrity/integrity.h > +++ b/security/integrity/integrity.h > @@ -49,12 +49,14 @@ > #define IMA_MODULE_APPRAISED 0x00008000 > #define IMA_FIRMWARE_APPRAISE 0x00010000 > #define IMA_FIRMWARE_APPRAISED 0x00020000 > +#define IMA_READ_APPRAISE 0x00040000 > +#define IMA_READ_APPRAISED 0x00080000 > #define IMA_APPRAISE_SUBMASK (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \ > IMA_BPRM_APPRAISE | IMA_MODULE_APPRAISE | \ > - IMA_FIRMWARE_APPRAISE) > + IMA_FIRMWARE_APPRAISE | IMA_READ_APPRAISE) > #define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \ > IMA_BPRM_APPRAISED | IMA_MODULE_APPRAISED | \ > - IMA_FIRMWARE_APPRAISED) > + IMA_FIRMWARE_APPRAISED | IMA_READ_APPRAISED) > > enum evm_ima_xattr_type { > IMA_XATTR_DIGEST = 0x01, > @@ -111,6 +113,7 @@ struct integrity_iint_cache { > enum integrity_status ima_bprm_status:4; > enum integrity_status ima_module_status:4; > enum integrity_status ima_firmware_status:4; > + enum integrity_status ima_read_status:4; > enum integrity_status evm_status:4; > struct ima_digest_data *ima_hash; > }; > -- > 2.1.0 > > > ------------------------------------------------------------------------------ > _______________________________________________ > Linux-ima-devel mailing list > Linux-ima-devel at lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/linux-ima-devel Thanks Dave