diff --git a/include/linux/ima.h b/include/linux/ima.h index 120ccc53fcb7f85d80a3f1f0f94c2241e864fbb2..d29a6a23fc19d47e886c8ea1d906cf8b801a8bf3 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -20,6 +20,8 @@ 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_post_read_file(struct file *file, void *buf, loff_t size, + enum kernel_read_file_id id); #else static inline int ima_bprm_check(struct linux_binprm *bprm) @@ -52,6 +54,12 @@ static inline int ima_fw_from_file(struct file *file, char *buf, size_t size) return 0; } +static inline int ima_post_read_file(struct file *file, void *buf, loff_t size, + enum kernel_read_file_id id) +{ + return 0; +} + #endif /* CONFIG_IMA */ #ifdef CONFIG_IMA_APPRAISE diff --git a/include/linux/security.h b/include/linux/security.h index b68ce94e4e00137bfa4b2dce2d28d56c47035f1a..d920718dc845292d1a5f973d849fe03449436fbf 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -24,6 +24,7 @@ #include #include +#include #include #include #include diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 2c5262f2823f11931b7ee7d7d2a4791335730900..0b7134c041651eefc642e6795d46fd47eccaf17e 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -152,7 +153,8 @@ enum ima_hooks { int ima_get_action(struct inode *inode, int mask, enum ima_hooks func); int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func); int ima_collect_measurement(struct integrity_iint_cache *iint, - struct file *file, enum hash_algo algo); + struct file *file, void *buf, loff_t size, + 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, diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 8750254506a986a4a5099c9a98d0c3aaebb7c157..370e42dfc5c58bd78d88faa0116edb13d264fd72 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, enum ima_hooks func) * 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, loff_t size, + 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, size, &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 288844908788c12fdb1b763e244255b2032e7d7d..cb0d0ff1137ba8aca0c48f52ad33b13278fee2d5 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -300,7 +300,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 1be99a27a7f3711c8e59e23fabcf2902f1a239bf..7577653541584a4f04ecb4a64aa5975fd8776919 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, - enum ima_hooks func, int opened) +static int process_measurement(struct file *file, char *buf, loff_t size, + int mask, enum ima_hooks func, 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, 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, size, hash_algo); if (rc != 0) { if (file->f_flags & O_DIRECT) rc = (iint->flags & IMA_PERMIT_DIRECTIO) ? 0 : -EACCES; @@ -273,7 +273,8 @@ static int process_measurement(struct file *file, int mask, 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,34 @@ 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_post_read_file - in memory collect/appraise/audit measurement + * @file: pointer to the file to be measured/appraised/audit + * @buf: pointer to in memory file contents + * @size: size of in memory file contents + * @read_id: caller identifier + * + * Measure/appraise/audit in memory file based on policy. Policy rules + * are written in terms of a policy identifier. + * + * On success return 0. On integrity appraisal error, assuming the file + * is in policy and IMA-appraisal is in enforcing mode, return -EACCES. + */ +int ima_post_read_file(struct file *file, void *buf, loff_t size, + enum kernel_read_file_id read_id) +{ + enum ima_hooks func = FILE_CHECK; + + if (!file || !buf || size == 0) { /* should never happen */ + if (ima_appraise & IMA_APPRAISE_ENFORCE) + return -EACCES; + return 0; + } + + return process_measurement(file, buf, size, MAY_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 b089ebef66486c2f6f910138b40ed921afe66c23..cfbe86f476d0a2c7b40dbeb6fbe7b6714028a5ea 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -12,6 +12,7 @@ */ #include #include +#include #include #include #include diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 5efe2ecc538d327818e48ec7c865bb03bc63322f..9a0ea4c4e3dda1c386fe58b435643e856ca364cc 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; }; diff --git a/security/security.c b/security/security.c index 5b96eabaafd4362c1158001f8427f98775e9f4a2..ef4c65a9fd17ac2a6873ae6e4ae7c56adcbeb671 100644 --- a/security/security.c +++ b/security/security.c @@ -913,7 +913,12 @@ int security_kernel_module_from_file(struct file *file) int security_kernel_post_read_file(struct file *file, char *buf, loff_t size, enum kernel_read_file_id id) { - return call_int_hook(kernel_post_read_file, 0, file, buf, size, id); + int ret; + + ret = call_int_hook(kernel_post_read_file, 0, file, buf, size, id); + if (ret) + return ret; + return ima_post_read_file(file, buf, size, id); } EXPORT_SYMBOL_GPL(security_kernel_post_read_file);