diff options
Diffstat (limited to 'security/integrity')
| -rw-r--r-- | security/integrity/digsig.c | 7 | ||||
| -rw-r--r-- | security/integrity/digsig_asymmetric.c | 11 | ||||
| -rw-r--r-- | security/integrity/evm/evm_main.c | 4 | ||||
| -rw-r--r-- | security/integrity/evm/evm_posix_acl.c | 3 | ||||
| -rw-r--r-- | security/integrity/iint.c | 2 | ||||
| -rw-r--r-- | security/integrity/ima/Kconfig | 64 | ||||
| -rw-r--r-- | security/integrity/ima/Makefile | 2 | ||||
| -rw-r--r-- | security/integrity/ima/ima.h | 106 | ||||
| -rw-r--r-- | security/integrity/ima/ima_api.c | 154 | ||||
| -rw-r--r-- | security/integrity/ima/ima_appraise.c | 106 | ||||
| -rw-r--r-- | security/integrity/ima/ima_crypto.c | 141 | ||||
| -rw-r--r-- | security/integrity/ima/ima_fs.c | 75 | ||||
| -rw-r--r-- | security/integrity/ima/ima_init.c | 40 | ||||
| -rw-r--r-- | security/integrity/ima/ima_main.c | 63 | ||||
| -rw-r--r-- | security/integrity/ima/ima_policy.c | 1 | ||||
| -rw-r--r-- | security/integrity/ima/ima_queue.c | 10 | ||||
| -rw-r--r-- | security/integrity/ima/ima_template.c | 187 | ||||
| -rw-r--r-- | security/integrity/ima/ima_template_lib.c | 351 | ||||
| -rw-r--r-- | security/integrity/ima/ima_template_lib.h | 49 | ||||
| -rw-r--r-- | security/integrity/integrity.h | 40 |
20 files changed, 1231 insertions, 185 deletions
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index 0b759e17a131..b4af4ebc5be2 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c | |||
| @@ -28,7 +28,7 @@ static const char *keyring_name[INTEGRITY_KEYRING_MAX] = { | |||
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, | 30 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, |
| 31 | const char *digest, int digestlen) | 31 | const char *digest, int digestlen) |
| 32 | { | 32 | { |
| 33 | if (id >= INTEGRITY_KEYRING_MAX) | 33 | if (id >= INTEGRITY_KEYRING_MAX) |
| 34 | return -EINVAL; | 34 | return -EINVAL; |
| @@ -44,9 +44,10 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, | |||
| 44 | } | 44 | } |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | switch (sig[0]) { | 47 | switch (sig[1]) { |
| 48 | case 1: | 48 | case 1: |
| 49 | return digsig_verify(keyring[id], sig, siglen, | 49 | /* v1 API expect signature without xattr type */ |
| 50 | return digsig_verify(keyring[id], sig + 1, siglen - 1, | ||
| 50 | digest, digestlen); | 51 | digest, digestlen); |
| 51 | case 2: | 52 | case 2: |
| 52 | return asymmetric_verify(keyring[id], sig, siglen, | 53 | return asymmetric_verify(keyring[id], sig, siglen, |
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c index b4754667659d..9eae4809006b 100644 --- a/security/integrity/digsig_asymmetric.c +++ b/security/integrity/digsig_asymmetric.c | |||
| @@ -20,17 +20,6 @@ | |||
| 20 | #include "integrity.h" | 20 | #include "integrity.h" |
| 21 | 21 | ||
| 22 | /* | 22 | /* |
| 23 | * signature format v2 - for using with asymmetric keys | ||
| 24 | */ | ||
| 25 | struct signature_v2_hdr { | ||
| 26 | uint8_t version; /* signature format version */ | ||
| 27 | uint8_t hash_algo; /* Digest algorithm [enum pkey_hash_algo] */ | ||
| 28 | uint32_t keyid; /* IMA key identifier - not X509/PGP specific*/ | ||
| 29 | uint16_t sig_size; /* signature size */ | ||
| 30 | uint8_t sig[0]; /* signature payload */ | ||
| 31 | } __packed; | ||
| 32 | |||
| 33 | /* | ||
| 34 | * Request an asymmetric key. | 23 | * Request an asymmetric key. |
| 35 | */ | 24 | */ |
| 36 | static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid) | 25 | static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid) |
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index af9b6852f4e1..336b3ddfe63f 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c | |||
| @@ -123,7 +123,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, | |||
| 123 | goto out; | 123 | goto out; |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | xattr_len = rc - 1; | 126 | xattr_len = rc; |
| 127 | 127 | ||
| 128 | /* check value type */ | 128 | /* check value type */ |
| 129 | switch (xattr_data->type) { | 129 | switch (xattr_data->type) { |
| @@ -143,7 +143,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, | |||
| 143 | if (rc) | 143 | if (rc) |
| 144 | break; | 144 | break; |
| 145 | rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM, | 145 | rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM, |
| 146 | xattr_data->digest, xattr_len, | 146 | (const char *)xattr_data, xattr_len, |
| 147 | calc.digest, sizeof(calc.digest)); | 147 | calc.digest, sizeof(calc.digest)); |
| 148 | if (!rc) { | 148 | if (!rc) { |
| 149 | /* we probably want to replace rsa with hmac here */ | 149 | /* we probably want to replace rsa with hmac here */ |
diff --git a/security/integrity/evm/evm_posix_acl.c b/security/integrity/evm/evm_posix_acl.c index b1753e98bf9a..46408b9e62e8 100644 --- a/security/integrity/evm/evm_posix_acl.c +++ b/security/integrity/evm/evm_posix_acl.c | |||
| @@ -11,8 +11,9 @@ | |||
| 11 | 11 | ||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/xattr.h> | 13 | #include <linux/xattr.h> |
| 14 | #include <linux/evm.h> | ||
| 14 | 15 | ||
| 15 | int posix_xattr_acl(char *xattr) | 16 | int posix_xattr_acl(const char *xattr) |
| 16 | { | 17 | { |
| 17 | int xattr_len = strlen(xattr); | 18 | int xattr_len = strlen(xattr); |
| 18 | 19 | ||
diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 74522dbd10a6..c49d3f14cbec 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c | |||
| @@ -70,6 +70,8 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode) | |||
| 70 | 70 | ||
| 71 | static void iint_free(struct integrity_iint_cache *iint) | 71 | static void iint_free(struct integrity_iint_cache *iint) |
| 72 | { | 72 | { |
| 73 | kfree(iint->ima_hash); | ||
| 74 | iint->ima_hash = NULL; | ||
| 73 | iint->version = 0; | 75 | iint->version = 0; |
| 74 | iint->flags = 0UL; | 76 | iint->flags = 0UL; |
| 75 | iint->ima_file_status = INTEGRITY_UNKNOWN; | 77 | iint->ima_file_status = INTEGRITY_UNKNOWN; |
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 39196abaff0d..81a27971d884 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig | |||
| @@ -9,6 +9,7 @@ config IMA | |||
| 9 | select CRYPTO_HMAC | 9 | select CRYPTO_HMAC |
| 10 | select CRYPTO_MD5 | 10 | select CRYPTO_MD5 |
| 11 | select CRYPTO_SHA1 | 11 | select CRYPTO_SHA1 |
| 12 | select CRYPTO_HASH_INFO | ||
| 12 | select TCG_TPM if HAS_IOMEM && !UML | 13 | select TCG_TPM if HAS_IOMEM && !UML |
| 13 | select TCG_TIS if TCG_TPM && X86 | 14 | select TCG_TIS if TCG_TPM && X86 |
| 14 | select TCG_IBMVTPM if TCG_TPM && PPC64 | 15 | select TCG_IBMVTPM if TCG_TPM && PPC64 |
| @@ -45,6 +46,69 @@ config IMA_LSM_RULES | |||
| 45 | help | 46 | help |
| 46 | Disabling this option will disregard LSM based policy rules. | 47 | Disabling this option will disregard LSM based policy rules. |
| 47 | 48 | ||
| 49 | choice | ||
| 50 | prompt "Default template" | ||
| 51 | default IMA_NG_TEMPLATE | ||
| 52 | depends on IMA | ||
| 53 | help | ||
| 54 | Select the default IMA measurement template. | ||
| 55 | |||
| 56 | The original 'ima' measurement list template contains a | ||
| 57 | hash, defined as 20 bytes, and a null terminated pathname, | ||
| 58 | limited to 255 characters. The 'ima-ng' measurement list | ||
| 59 | template permits both larger hash digests and longer | ||
| 60 | pathnames. | ||
| 61 | |||
| 62 | config IMA_TEMPLATE | ||
| 63 | bool "ima" | ||
| 64 | config IMA_NG_TEMPLATE | ||
| 65 | bool "ima-ng (default)" | ||
| 66 | config IMA_SIG_TEMPLATE | ||
| 67 | bool "ima-sig" | ||
| 68 | endchoice | ||
| 69 | |||
| 70 | config IMA_DEFAULT_TEMPLATE | ||
| 71 | string | ||
| 72 | depends on IMA | ||
| 73 | default "ima" if IMA_TEMPLATE | ||
| 74 | default "ima-ng" if IMA_NG_TEMPLATE | ||
| 75 | default "ima-sig" if IMA_SIG_TEMPLATE | ||
| 76 | |||
| 77 | choice | ||
| 78 | prompt "Default integrity hash algorithm" | ||
| 79 | default IMA_DEFAULT_HASH_SHA1 | ||
| 80 | depends on IMA | ||
| 81 | help | ||
| 82 | Select the default hash algorithm used for the measurement | ||
| 83 | list, integrity appraisal and audit log. The compiled default | ||
| 84 | hash algorithm can be overwritten using the kernel command | ||
| 85 | line 'ima_hash=' option. | ||
| 86 | |||
| 87 | config IMA_DEFAULT_HASH_SHA1 | ||
| 88 | bool "SHA1 (default)" | ||
| 89 | depends on CRYPTO_SHA1 | ||
| 90 | |||
| 91 | config IMA_DEFAULT_HASH_SHA256 | ||
| 92 | bool "SHA256" | ||
| 93 | depends on CRYPTO_SHA256 && !IMA_TEMPLATE | ||
| 94 | |||
| 95 | config IMA_DEFAULT_HASH_SHA512 | ||
| 96 | bool "SHA512" | ||
| 97 | depends on CRYPTO_SHA512 && !IMA_TEMPLATE | ||
| 98 | |||
| 99 | config IMA_DEFAULT_HASH_WP512 | ||
| 100 | bool "WP512" | ||
| 101 | depends on CRYPTO_WP512 && !IMA_TEMPLATE | ||
| 102 | endchoice | ||
| 103 | |||
| 104 | config IMA_DEFAULT_HASH | ||
| 105 | string | ||
| 106 | depends on IMA | ||
| 107 | default "sha1" if IMA_DEFAULT_HASH_SHA1 | ||
| 108 | default "sha256" if IMA_DEFAULT_HASH_SHA256 | ||
| 109 | default "sha512" if IMA_DEFAULT_HASH_SHA512 | ||
| 110 | default "wp512" if IMA_DEFAULT_HASH_WP512 | ||
| 111 | |||
| 48 | config IMA_APPRAISE | 112 | config IMA_APPRAISE |
| 49 | bool "Appraise integrity measurements" | 113 | bool "Appraise integrity measurements" |
| 50 | depends on IMA | 114 | depends on IMA |
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile index 56dfee7cbf61..d79263d2fdbf 100644 --- a/security/integrity/ima/Makefile +++ b/security/integrity/ima/Makefile | |||
| @@ -6,5 +6,5 @@ | |||
| 6 | obj-$(CONFIG_IMA) += ima.o | 6 | obj-$(CONFIG_IMA) += ima.o |
| 7 | 7 | ||
| 8 | ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ | 8 | ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ |
| 9 | ima_policy.o | 9 | ima_policy.o ima_template.o ima_template_lib.o |
| 10 | ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o | 10 | ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o |
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index b3dd616560f7..0356e1d437ca 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
| @@ -26,7 +26,8 @@ | |||
| 26 | 26 | ||
| 27 | #include "../integrity.h" | 27 | #include "../integrity.h" |
| 28 | 28 | ||
| 29 | enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_ASCII }; | 29 | enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_BINARY_NO_FIELD_LEN, |
| 30 | IMA_SHOW_ASCII }; | ||
| 30 | enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; | 31 | enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; |
| 31 | 32 | ||
| 32 | /* digest size for IMA, fits SHA1 or MD5 */ | 33 | /* digest size for IMA, fits SHA1 or MD5 */ |
| @@ -36,23 +37,48 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; | |||
| 36 | #define IMA_HASH_BITS 9 | 37 | #define IMA_HASH_BITS 9 |
| 37 | #define IMA_MEASURE_HTABLE_SIZE (1 << IMA_HASH_BITS) | 38 | #define IMA_MEASURE_HTABLE_SIZE (1 << IMA_HASH_BITS) |
| 38 | 39 | ||
| 40 | #define IMA_TEMPLATE_FIELD_ID_MAX_LEN 16 | ||
| 41 | #define IMA_TEMPLATE_NUM_FIELDS_MAX 15 | ||
| 42 | |||
| 43 | #define IMA_TEMPLATE_IMA_NAME "ima" | ||
| 44 | #define IMA_TEMPLATE_IMA_FMT "d|n" | ||
| 45 | |||
| 39 | /* set during initialization */ | 46 | /* set during initialization */ |
| 40 | extern int ima_initialized; | 47 | extern int ima_initialized; |
| 41 | extern int ima_used_chip; | 48 | extern int ima_used_chip; |
| 42 | extern char *ima_hash; | 49 | extern int ima_hash_algo; |
| 43 | extern int ima_appraise; | 50 | extern int ima_appraise; |
| 44 | 51 | ||
| 45 | /* IMA inode template definition */ | 52 | /* IMA template field data definition */ |
| 46 | struct ima_template_data { | 53 | struct ima_field_data { |
| 47 | u8 digest[IMA_DIGEST_SIZE]; /* sha1/md5 measurement hash */ | 54 | u8 *data; |
| 48 | char file_name[IMA_EVENT_NAME_LEN_MAX + 1]; /* name + \0 */ | 55 | u32 len; |
| 56 | }; | ||
| 57 | |||
| 58 | /* IMA template field definition */ | ||
| 59 | struct ima_template_field { | ||
| 60 | const char field_id[IMA_TEMPLATE_FIELD_ID_MAX_LEN]; | ||
| 61 | int (*field_init) (struct integrity_iint_cache *iint, struct file *file, | ||
| 62 | const unsigned char *filename, | ||
| 63 | struct evm_ima_xattr_data *xattr_value, | ||
| 64 | int xattr_len, struct ima_field_data *field_data); | ||
| 65 | void (*field_show) (struct seq_file *m, enum ima_show_type show, | ||
| 66 | struct ima_field_data *field_data); | ||
| 67 | }; | ||
| 68 | |||
| 69 | /* IMA template descriptor definition */ | ||
| 70 | struct ima_template_desc { | ||
| 71 | char *name; | ||
| 72 | char *fmt; | ||
| 73 | int num_fields; | ||
| 74 | struct ima_template_field **fields; | ||
| 49 | }; | 75 | }; |
| 50 | 76 | ||
| 51 | struct ima_template_entry { | 77 | struct ima_template_entry { |
| 52 | u8 digest[IMA_DIGEST_SIZE]; /* sha1 or md5 measurement hash */ | 78 | u8 digest[TPM_DIGEST_SIZE]; /* sha1 or md5 measurement hash */ |
| 53 | const char *template_name; | 79 | struct ima_template_desc *template_desc; /* template descriptor */ |
| 54 | int template_len; | 80 | u32 template_data_len; |
| 55 | struct ima_template_data template; | 81 | struct ima_field_data template_data[0]; /* template related data */ |
| 56 | }; | 82 | }; |
| 57 | 83 | ||
| 58 | struct ima_queue_entry { | 84 | struct ima_queue_entry { |
| @@ -69,13 +95,22 @@ int ima_fs_init(void); | |||
| 69 | void ima_fs_cleanup(void); | 95 | void ima_fs_cleanup(void); |
| 70 | int ima_inode_alloc(struct inode *inode); | 96 | int ima_inode_alloc(struct inode *inode); |
| 71 | int ima_add_template_entry(struct ima_template_entry *entry, int violation, | 97 | int ima_add_template_entry(struct ima_template_entry *entry, int violation, |
| 72 | const char *op, struct inode *inode); | 98 | const char *op, struct inode *inode, |
| 73 | int ima_calc_file_hash(struct file *file, char *digest); | 99 | const unsigned char *filename); |
| 74 | int ima_calc_buffer_hash(const void *data, int len, char *digest); | 100 | int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash); |
| 75 | int ima_calc_boot_aggregate(char *digest); | 101 | int ima_calc_field_array_hash(struct ima_field_data *field_data, |
| 76 | void ima_add_violation(struct inode *inode, const unsigned char *filename, | 102 | struct ima_template_desc *desc, int num_fields, |
| 103 | struct ima_digest_data *hash); | ||
| 104 | int __init ima_calc_boot_aggregate(struct ima_digest_data *hash); | ||
| 105 | void ima_add_violation(struct file *file, const unsigned char *filename, | ||
| 77 | const char *op, const char *cause); | 106 | const char *op, const char *cause); |
| 78 | int ima_init_crypto(void); | 107 | int ima_init_crypto(void); |
| 108 | void ima_putc(struct seq_file *m, void *data, int datalen); | ||
| 109 | void ima_print_digest(struct seq_file *m, u8 *digest, int size); | ||
| 110 | struct ima_template_desc *ima_template_desc_current(void); | ||
| 111 | int ima_init_template(void); | ||
| 112 | |||
| 113 | int ima_init_template(void); | ||
| 79 | 114 | ||
| 80 | /* | 115 | /* |
| 81 | * used to protect h_table and sha_table | 116 | * used to protect h_table and sha_table |
| @@ -98,14 +133,22 @@ static inline unsigned long ima_hash_key(u8 *digest) | |||
| 98 | int ima_get_action(struct inode *inode, int mask, int function); | 133 | int ima_get_action(struct inode *inode, int mask, int function); |
| 99 | int ima_must_measure(struct inode *inode, int mask, int function); | 134 | int ima_must_measure(struct inode *inode, int mask, int function); |
| 100 | int ima_collect_measurement(struct integrity_iint_cache *iint, | 135 | int ima_collect_measurement(struct integrity_iint_cache *iint, |
| 101 | struct file *file); | 136 | struct file *file, |
| 137 | struct evm_ima_xattr_data **xattr_value, | ||
| 138 | int *xattr_len); | ||
| 102 | void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, | 139 | void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, |
| 103 | const unsigned char *filename); | 140 | const unsigned char *filename, |
| 141 | struct evm_ima_xattr_data *xattr_value, | ||
| 142 | int xattr_len); | ||
| 104 | void ima_audit_measurement(struct integrity_iint_cache *iint, | 143 | void ima_audit_measurement(struct integrity_iint_cache *iint, |
| 105 | const unsigned char *filename); | 144 | const unsigned char *filename); |
| 145 | int ima_alloc_init_template(struct integrity_iint_cache *iint, | ||
| 146 | struct file *file, const unsigned char *filename, | ||
| 147 | struct evm_ima_xattr_data *xattr_value, | ||
| 148 | int xattr_len, struct ima_template_entry **entry); | ||
| 106 | int ima_store_template(struct ima_template_entry *entry, int violation, | 149 | int ima_store_template(struct ima_template_entry *entry, int violation, |
| 107 | struct inode *inode); | 150 | struct inode *inode, const unsigned char *filename); |
| 108 | void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show); | 151 | void ima_free_template_entry(struct ima_template_entry *entry); |
| 109 | const char *ima_d_path(struct path *path, char **pathbuf); | 152 | const char *ima_d_path(struct path *path, char **pathbuf); |
| 110 | 153 | ||
| 111 | /* rbtree tree calls to lookup, insert, delete | 154 | /* rbtree tree calls to lookup, insert, delete |
| @@ -131,17 +174,25 @@ void ima_delete_rules(void); | |||
| 131 | 174 | ||
| 132 | #ifdef CONFIG_IMA_APPRAISE | 175 | #ifdef CONFIG_IMA_APPRAISE |
| 133 | int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, | 176 | int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, |
| 134 | struct file *file, const unsigned char *filename); | 177 | struct file *file, const unsigned char *filename, |
| 178 | struct evm_ima_xattr_data *xattr_value, | ||
| 179 | int xattr_len); | ||
| 135 | int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func); | 180 | int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func); |
| 136 | void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); | 181 | void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); |
| 137 | enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, | 182 | enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, |
| 138 | int func); | 183 | int func); |
| 184 | void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len, | ||
| 185 | struct ima_digest_data *hash); | ||
| 186 | int ima_read_xattr(struct dentry *dentry, | ||
| 187 | struct evm_ima_xattr_data **xattr_value); | ||
| 139 | 188 | ||
| 140 | #else | 189 | #else |
| 141 | static inline int ima_appraise_measurement(int func, | 190 | static inline int ima_appraise_measurement(int func, |
| 142 | struct integrity_iint_cache *iint, | 191 | struct integrity_iint_cache *iint, |
| 143 | struct file *file, | 192 | struct file *file, |
| 144 | const unsigned char *filename) | 193 | const unsigned char *filename, |
| 194 | struct evm_ima_xattr_data *xattr_value, | ||
| 195 | int xattr_len) | ||
| 145 | { | 196 | { |
| 146 | return INTEGRITY_UNKNOWN; | 197 | return INTEGRITY_UNKNOWN; |
| 147 | } | 198 | } |
| @@ -162,6 +213,19 @@ static inline enum integrity_status ima_get_cache_status(struct integrity_iint_c | |||
| 162 | { | 213 | { |
| 163 | return INTEGRITY_UNKNOWN; | 214 | return INTEGRITY_UNKNOWN; |
| 164 | } | 215 | } |
| 216 | |||
| 217 | static inline void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, | ||
| 218 | int xattr_len, | ||
| 219 | struct ima_digest_data *hash) | ||
| 220 | { | ||
| 221 | } | ||
| 222 | |||
| 223 | static inline int ima_read_xattr(struct dentry *dentry, | ||
| 224 | struct evm_ima_xattr_data **xattr_value) | ||
| 225 | { | ||
| 226 | return 0; | ||
| 227 | } | ||
| 228 | |||
| 165 | #endif | 229 | #endif |
| 166 | 230 | ||
| 167 | /* LSM based policy rules require audit */ | 231 | /* LSM based policy rules require audit */ |
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 1c03e8f1e0e1..c38bbce8c6a6 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c | |||
| @@ -18,9 +18,59 @@ | |||
| 18 | #include <linux/fs.h> | 18 | #include <linux/fs.h> |
| 19 | #include <linux/xattr.h> | 19 | #include <linux/xattr.h> |
| 20 | #include <linux/evm.h> | 20 | #include <linux/evm.h> |
| 21 | #include <crypto/hash_info.h> | ||
| 21 | #include "ima.h" | 22 | #include "ima.h" |
| 22 | 23 | ||
| 23 | static const char *IMA_TEMPLATE_NAME = "ima"; | 24 | /* |
| 25 | * ima_free_template_entry - free an existing template entry | ||
| 26 | */ | ||
| 27 | void ima_free_template_entry(struct ima_template_entry *entry) | ||
| 28 | { | ||
| 29 | int i; | ||
| 30 | |||
| 31 | for (i = 0; i < entry->template_desc->num_fields; i++) | ||
| 32 | kfree(entry->template_data[i].data); | ||
| 33 | |||
| 34 | kfree(entry); | ||
| 35 | } | ||
| 36 | |||
| 37 | /* | ||
| 38 | * ima_alloc_init_template - create and initialize a new template entry | ||
| 39 | */ | ||
| 40 | int ima_alloc_init_template(struct integrity_iint_cache *iint, | ||
| 41 | struct file *file, const unsigned char *filename, | ||
| 42 | struct evm_ima_xattr_data *xattr_value, | ||
| 43 | int xattr_len, struct ima_template_entry **entry) | ||
| 44 | { | ||
| 45 | struct ima_template_desc *template_desc = ima_template_desc_current(); | ||
| 46 | int i, result = 0; | ||
| 47 | |||
| 48 | *entry = kzalloc(sizeof(**entry) + template_desc->num_fields * | ||
| 49 | sizeof(struct ima_field_data), GFP_NOFS); | ||
| 50 | if (!*entry) | ||
| 51 | return -ENOMEM; | ||
| 52 | |||
| 53 | (*entry)->template_desc = template_desc; | ||
| 54 | for (i = 0; i < template_desc->num_fields; i++) { | ||
| 55 | struct ima_template_field *field = template_desc->fields[i]; | ||
| 56 | u32 len; | ||
| 57 | |||
| 58 | result = field->field_init(iint, file, filename, | ||
| 59 | xattr_value, xattr_len, | ||
| 60 | &((*entry)->template_data[i])); | ||
| 61 | if (result != 0) | ||
| 62 | goto out; | ||
| 63 | |||
| 64 | len = (*entry)->template_data[i].len; | ||
| 65 | (*entry)->template_data_len += sizeof(len); | ||
| 66 | (*entry)->template_data_len += len; | ||
| 67 | } | ||
| 68 | return 0; | ||
| 69 | out: | ||
| 70 | ima_free_template_entry(*entry); | ||
| 71 | *entry = NULL; | ||
| 72 | return result; | ||
| 73 | } | ||
| 24 | 74 | ||
| 25 | /* | 75 | /* |
| 26 | * ima_store_template - store ima template measurements | 76 | * ima_store_template - store ima template measurements |
| @@ -39,28 +89,35 @@ static const char *IMA_TEMPLATE_NAME = "ima"; | |||
| 39 | * Returns 0 on success, error code otherwise | 89 | * Returns 0 on success, error code otherwise |
| 40 | */ | 90 | */ |
| 41 | int ima_store_template(struct ima_template_entry *entry, | 91 | int ima_store_template(struct ima_template_entry *entry, |
| 42 | int violation, struct inode *inode) | 92 | int violation, struct inode *inode, |
| 93 | const unsigned char *filename) | ||
| 43 | { | 94 | { |
| 44 | const char *op = "add_template_measure"; | 95 | const char *op = "add_template_measure"; |
| 45 | const char *audit_cause = "hashing_error"; | 96 | const char *audit_cause = "hashing_error"; |
| 97 | char *template_name = entry->template_desc->name; | ||
| 46 | int result; | 98 | int result; |
| 47 | 99 | struct { | |
| 48 | memset(entry->digest, 0, sizeof(entry->digest)); | 100 | struct ima_digest_data hdr; |
| 49 | entry->template_name = IMA_TEMPLATE_NAME; | 101 | char digest[TPM_DIGEST_SIZE]; |
| 50 | entry->template_len = sizeof(entry->template); | 102 | } hash; |
| 51 | 103 | ||
| 52 | if (!violation) { | 104 | if (!violation) { |
| 53 | result = ima_calc_buffer_hash(&entry->template, | 105 | int num_fields = entry->template_desc->num_fields; |
| 54 | entry->template_len, | 106 | |
| 55 | entry->digest); | 107 | /* this function uses default algo */ |
| 108 | hash.hdr.algo = HASH_ALGO_SHA1; | ||
| 109 | result = ima_calc_field_array_hash(&entry->template_data[0], | ||
| 110 | entry->template_desc, | ||
| 111 | num_fields, &hash.hdr); | ||
| 56 | if (result < 0) { | 112 | if (result < 0) { |
| 57 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, | 113 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, |
| 58 | entry->template_name, op, | 114 | template_name, op, |
| 59 | audit_cause, result, 0); | 115 | audit_cause, result, 0); |
| 60 | return result; | 116 | return result; |
| 61 | } | 117 | } |
| 118 | memcpy(entry->digest, hash.hdr.digest, hash.hdr.length); | ||
| 62 | } | 119 | } |
| 63 | result = ima_add_template_entry(entry, violation, op, inode); | 120 | result = ima_add_template_entry(entry, violation, op, inode, filename); |
| 64 | return result; | 121 | return result; |
| 65 | } | 122 | } |
| 66 | 123 | ||
| @@ -71,26 +128,26 @@ int ima_store_template(struct ima_template_entry *entry, | |||
| 71 | * By extending the PCR with 0xFF's instead of with zeroes, the PCR | 128 | * By extending the PCR with 0xFF's instead of with zeroes, the PCR |
| 72 | * value is invalidated. | 129 | * value is invalidated. |
| 73 | */ | 130 | */ |
| 74 | void ima_add_violation(struct inode *inode, const unsigned char *filename, | 131 | void ima_add_violation(struct file *file, const unsigned char *filename, |
| 75 | const char *op, const char *cause) | 132 | const char *op, const char *cause) |
| 76 | { | 133 | { |
| 77 | struct ima_template_entry *entry; | 134 | struct ima_template_entry *entry; |
| 135 | struct inode *inode = file->f_dentry->d_inode; | ||
| 78 | int violation = 1; | 136 | int violation = 1; |
| 79 | int result; | 137 | int result; |
| 80 | 138 | ||
| 81 | /* can overflow, only indicator */ | 139 | /* can overflow, only indicator */ |
| 82 | atomic_long_inc(&ima_htable.violations); | 140 | atomic_long_inc(&ima_htable.violations); |
| 83 | 141 | ||
| 84 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | 142 | result = ima_alloc_init_template(NULL, file, filename, |
| 85 | if (!entry) { | 143 | NULL, 0, &entry); |
| 144 | if (result < 0) { | ||
| 86 | result = -ENOMEM; | 145 | result = -ENOMEM; |
| 87 | goto err_out; | 146 | goto err_out; |
| 88 | } | 147 | } |
| 89 | memset(&entry->template, 0, sizeof(entry->template)); | 148 | result = ima_store_template(entry, violation, inode, filename); |
| 90 | strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX); | ||
| 91 | result = ima_store_template(entry, violation, inode); | ||
| 92 | if (result < 0) | 149 | if (result < 0) |
| 93 | kfree(entry); | 150 | ima_free_template_entry(entry); |
| 94 | err_out: | 151 | err_out: |
| 95 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, | 152 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, |
| 96 | op, cause, result, 0); | 153 | op, cause, result, 0); |
| @@ -138,20 +195,42 @@ int ima_must_measure(struct inode *inode, int mask, int function) | |||
| 138 | * Return 0 on success, error code otherwise | 195 | * Return 0 on success, error code otherwise |
| 139 | */ | 196 | */ |
| 140 | int ima_collect_measurement(struct integrity_iint_cache *iint, | 197 | int ima_collect_measurement(struct integrity_iint_cache *iint, |
| 141 | struct file *file) | 198 | struct file *file, |
| 199 | struct evm_ima_xattr_data **xattr_value, | ||
| 200 | int *xattr_len) | ||
| 142 | { | 201 | { |
| 143 | struct inode *inode = file_inode(file); | 202 | struct inode *inode = file_inode(file); |
| 144 | const char *filename = file->f_dentry->d_name.name; | 203 | const char *filename = file->f_dentry->d_name.name; |
| 145 | int result = 0; | 204 | int result = 0; |
| 205 | struct { | ||
| 206 | struct ima_digest_data hdr; | ||
| 207 | char digest[IMA_MAX_DIGEST_SIZE]; | ||
| 208 | } hash; | ||
| 209 | |||
| 210 | if (xattr_value) | ||
| 211 | *xattr_len = ima_read_xattr(file->f_dentry, xattr_value); | ||
| 146 | 212 | ||
| 147 | if (!(iint->flags & IMA_COLLECTED)) { | 213 | if (!(iint->flags & IMA_COLLECTED)) { |
| 148 | u64 i_version = file_inode(file)->i_version; | 214 | u64 i_version = file_inode(file)->i_version; |
| 149 | 215 | ||
| 150 | iint->ima_xattr.type = IMA_XATTR_DIGEST; | 216 | /* use default hash algorithm */ |
| 151 | result = ima_calc_file_hash(file, iint->ima_xattr.digest); | 217 | hash.hdr.algo = ima_hash_algo; |
| 218 | |||
| 219 | if (xattr_value) | ||
| 220 | ima_get_hash_algo(*xattr_value, *xattr_len, &hash.hdr); | ||
| 221 | |||
| 222 | result = ima_calc_file_hash(file, &hash.hdr); | ||
| 152 | if (!result) { | 223 | if (!result) { |
| 153 | iint->version = i_version; | 224 | int length = sizeof(hash.hdr) + hash.hdr.length; |
| 154 | iint->flags |= IMA_COLLECTED; | 225 | void *tmpbuf = krealloc(iint->ima_hash, length, |
| 226 | GFP_NOFS); | ||
| 227 | if (tmpbuf) { | ||
| 228 | iint->ima_hash = tmpbuf; | ||
| 229 | memcpy(iint->ima_hash, &hash, length); | ||
| 230 | iint->version = i_version; | ||
| 231 | iint->flags |= IMA_COLLECTED; | ||
| 232 | } else | ||
| 233 | result = -ENOMEM; | ||
| 155 | } | 234 | } |
| 156 | } | 235 | } |
| 157 | if (result) | 236 | if (result) |
| @@ -177,7 +256,9 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, | |||
| 177 | * Must be called with iint->mutex held. | 256 | * Must be called with iint->mutex held. |
| 178 | */ | 257 | */ |
| 179 | void ima_store_measurement(struct integrity_iint_cache *iint, | 258 | void ima_store_measurement(struct integrity_iint_cache *iint, |
| 180 | struct file *file, const unsigned char *filename) | 259 | struct file *file, const unsigned char *filename, |
| 260 | struct evm_ima_xattr_data *xattr_value, | ||
| 261 | int xattr_len) | ||
| 181 | { | 262 | { |
| 182 | const char *op = "add_template_measure"; | 263 | const char *op = "add_template_measure"; |
| 183 | const char *audit_cause = "ENOMEM"; | 264 | const char *audit_cause = "ENOMEM"; |
| @@ -189,37 +270,35 @@ void ima_store_measurement(struct integrity_iint_cache *iint, | |||
| 189 | if (iint->flags & IMA_MEASURED) | 270 | if (iint->flags & IMA_MEASURED) |
| 190 | return; | 271 | return; |
| 191 | 272 | ||
| 192 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | 273 | result = ima_alloc_init_template(iint, file, filename, |
| 193 | if (!entry) { | 274 | xattr_value, xattr_len, &entry); |
| 275 | if (result < 0) { | ||
| 194 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, | 276 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, |
| 195 | op, audit_cause, result, 0); | 277 | op, audit_cause, result, 0); |
| 196 | return; | 278 | return; |
| 197 | } | 279 | } |
| 198 | memset(&entry->template, 0, sizeof(entry->template)); | ||
| 199 | memcpy(entry->template.digest, iint->ima_xattr.digest, IMA_DIGEST_SIZE); | ||
| 200 | strcpy(entry->template.file_name, | ||
| 201 | (strlen(filename) > IMA_EVENT_NAME_LEN_MAX) ? | ||
| 202 | file->f_dentry->d_name.name : filename); | ||
| 203 | 280 | ||
| 204 | result = ima_store_template(entry, violation, inode); | 281 | result = ima_store_template(entry, violation, inode, filename); |
| 205 | if (!result || result == -EEXIST) | 282 | if (!result || result == -EEXIST) |
| 206 | iint->flags |= IMA_MEASURED; | 283 | iint->flags |= IMA_MEASURED; |
| 207 | if (result < 0) | 284 | if (result < 0) |
| 208 | kfree(entry); | 285 | ima_free_template_entry(entry); |
| 209 | } | 286 | } |
| 210 | 287 | ||
| 211 | void ima_audit_measurement(struct integrity_iint_cache *iint, | 288 | void ima_audit_measurement(struct integrity_iint_cache *iint, |
| 212 | const unsigned char *filename) | 289 | const unsigned char *filename) |
| 213 | { | 290 | { |
| 214 | struct audit_buffer *ab; | 291 | struct audit_buffer *ab; |
| 215 | char hash[(IMA_DIGEST_SIZE * 2) + 1]; | 292 | char hash[(iint->ima_hash->length * 2) + 1]; |
| 293 | const char *algo_name = hash_algo_name[iint->ima_hash->algo]; | ||
| 294 | char algo_hash[sizeof(hash) + strlen(algo_name) + 2]; | ||
| 216 | int i; | 295 | int i; |
| 217 | 296 | ||
| 218 | if (iint->flags & IMA_AUDITED) | 297 | if (iint->flags & IMA_AUDITED) |
| 219 | return; | 298 | return; |
| 220 | 299 | ||
| 221 | for (i = 0; i < IMA_DIGEST_SIZE; i++) | 300 | for (i = 0; i < iint->ima_hash->length; i++) |
| 222 | hex_byte_pack(hash + (i * 2), iint->ima_xattr.digest[i]); | 301 | hex_byte_pack(hash + (i * 2), iint->ima_hash->digest[i]); |
| 223 | hash[i * 2] = '\0'; | 302 | hash[i * 2] = '\0'; |
| 224 | 303 | ||
| 225 | ab = audit_log_start(current->audit_context, GFP_KERNEL, | 304 | ab = audit_log_start(current->audit_context, GFP_KERNEL, |
| @@ -230,7 +309,8 @@ void ima_audit_measurement(struct integrity_iint_cache *iint, | |||
| 230 | audit_log_format(ab, "file="); | 309 | audit_log_format(ab, "file="); |
| 231 | audit_log_untrustedstring(ab, filename); | 310 | audit_log_untrustedstring(ab, filename); |
| 232 | audit_log_format(ab, " hash="); | 311 | audit_log_format(ab, " hash="); |
| 233 | audit_log_untrustedstring(ab, hash); | 312 | snprintf(algo_hash, sizeof(algo_hash), "%s:%s", algo_name, hash); |
| 313 | audit_log_untrustedstring(ab, algo_hash); | ||
| 234 | 314 | ||
| 235 | audit_log_task_info(ab, current); | 315 | audit_log_task_info(ab, current); |
| 236 | audit_log_end(ab); | 316 | audit_log_end(ab); |
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 2d4becab8918..734e9468aca0 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/magic.h> | 15 | #include <linux/magic.h> |
| 16 | #include <linux/ima.h> | 16 | #include <linux/ima.h> |
| 17 | #include <linux/evm.h> | 17 | #include <linux/evm.h> |
| 18 | #include <crypto/hash_info.h> | ||
| 18 | 19 | ||
| 19 | #include "ima.h" | 20 | #include "ima.h" |
| 20 | 21 | ||
| @@ -43,19 +44,31 @@ int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func) | |||
| 43 | } | 44 | } |
| 44 | 45 | ||
| 45 | static int ima_fix_xattr(struct dentry *dentry, | 46 | static int ima_fix_xattr(struct dentry *dentry, |
| 46 | struct integrity_iint_cache *iint) | 47 | struct integrity_iint_cache *iint) |
| 47 | { | 48 | { |
| 48 | iint->ima_xattr.type = IMA_XATTR_DIGEST; | 49 | int rc, offset; |
| 49 | return __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, | 50 | u8 algo = iint->ima_hash->algo; |
| 50 | (u8 *)&iint->ima_xattr, | 51 | |
| 51 | sizeof(iint->ima_xattr), 0); | 52 | if (algo <= HASH_ALGO_SHA1) { |
| 53 | offset = 1; | ||
| 54 | iint->ima_hash->xattr.sha1.type = IMA_XATTR_DIGEST; | ||
| 55 | } else { | ||
| 56 | offset = 0; | ||
| 57 | iint->ima_hash->xattr.ng.type = IMA_XATTR_DIGEST_NG; | ||
| 58 | iint->ima_hash->xattr.ng.algo = algo; | ||
| 59 | } | ||
| 60 | rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, | ||
| 61 | &iint->ima_hash->xattr.data[offset], | ||
| 62 | (sizeof(iint->ima_hash->xattr) - offset) + | ||
| 63 | iint->ima_hash->length, 0); | ||
| 64 | return rc; | ||
| 52 | } | 65 | } |
| 53 | 66 | ||
| 54 | /* Return specific func appraised cached result */ | 67 | /* Return specific func appraised cached result */ |
| 55 | enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, | 68 | enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, |
| 56 | int func) | 69 | int func) |
| 57 | { | 70 | { |
| 58 | switch(func) { | 71 | switch (func) { |
| 59 | case MMAP_CHECK: | 72 | case MMAP_CHECK: |
| 60 | return iint->ima_mmap_status; | 73 | return iint->ima_mmap_status; |
| 61 | case BPRM_CHECK: | 74 | case BPRM_CHECK: |
| @@ -71,7 +84,7 @@ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, | |||
| 71 | static void ima_set_cache_status(struct integrity_iint_cache *iint, | 84 | static void ima_set_cache_status(struct integrity_iint_cache *iint, |
| 72 | int func, enum integrity_status status) | 85 | int func, enum integrity_status status) |
| 73 | { | 86 | { |
| 74 | switch(func) { | 87 | switch (func) { |
| 75 | case MMAP_CHECK: | 88 | case MMAP_CHECK: |
| 76 | iint->ima_mmap_status = status; | 89 | iint->ima_mmap_status = status; |
| 77 | break; | 90 | break; |
| @@ -90,7 +103,7 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint, | |||
| 90 | 103 | ||
| 91 | static void ima_cache_flags(struct integrity_iint_cache *iint, int func) | 104 | static void ima_cache_flags(struct integrity_iint_cache *iint, int func) |
| 92 | { | 105 | { |
| 93 | switch(func) { | 106 | switch (func) { |
| 94 | case MMAP_CHECK: | 107 | case MMAP_CHECK: |
| 95 | iint->flags |= (IMA_MMAP_APPRAISED | IMA_APPRAISED); | 108 | iint->flags |= (IMA_MMAP_APPRAISED | IMA_APPRAISED); |
| 96 | break; | 109 | break; |
| @@ -107,6 +120,50 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func) | |||
| 107 | } | 120 | } |
| 108 | } | 121 | } |
| 109 | 122 | ||
| 123 | void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len, | ||
| 124 | struct ima_digest_data *hash) | ||
| 125 | { | ||
| 126 | struct signature_v2_hdr *sig; | ||
| 127 | |||
| 128 | if (!xattr_value || xattr_len < 2) | ||
| 129 | return; | ||
| 130 | |||
| 131 | switch (xattr_value->type) { | ||
| 132 | case EVM_IMA_XATTR_DIGSIG: | ||
| 133 | sig = (typeof(sig))xattr_value; | ||
| 134 | if (sig->version != 2 || xattr_len <= sizeof(*sig)) | ||
| 135 | return; | ||
| 136 | hash->algo = sig->hash_algo; | ||
| 137 | break; | ||
| 138 | case IMA_XATTR_DIGEST_NG: | ||
| 139 | hash->algo = xattr_value->digest[0]; | ||
| 140 | break; | ||
| 141 | case IMA_XATTR_DIGEST: | ||
| 142 | /* this is for backward compatibility */ | ||
| 143 | if (xattr_len == 21) { | ||
| 144 | unsigned int zero = 0; | ||
| 145 | if (!memcmp(&xattr_value->digest[16], &zero, 4)) | ||
| 146 | hash->algo = HASH_ALGO_MD5; | ||
| 147 | else | ||
| 148 | hash->algo = HASH_ALGO_SHA1; | ||
| 149 | } else if (xattr_len == 17) | ||
| 150 | hash->algo = HASH_ALGO_MD5; | ||
| 151 | break; | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | int ima_read_xattr(struct dentry *dentry, | ||
| 156 | struct evm_ima_xattr_data **xattr_value) | ||
| 157 | { | ||
| 158 | struct inode *inode = dentry->d_inode; | ||
| 159 | |||
| 160 | if (!inode->i_op->getxattr) | ||
| 161 | return 0; | ||
| 162 | |||
| 163 | return vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value, | ||
| 164 | 0, GFP_NOFS); | ||
| 165 | } | ||
| 166 | |||
| 110 | /* | 167 | /* |
| 111 | * ima_appraise_measurement - appraise file measurement | 168 | * ima_appraise_measurement - appraise file measurement |
| 112 | * | 169 | * |
| @@ -116,23 +173,22 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func) | |||
| 116 | * Return 0 on success, error code otherwise | 173 | * Return 0 on success, error code otherwise |
| 117 | */ | 174 | */ |
| 118 | int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, | 175 | int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, |
| 119 | struct file *file, const unsigned char *filename) | 176 | struct file *file, const unsigned char *filename, |
| 177 | struct evm_ima_xattr_data *xattr_value, | ||
| 178 | int xattr_len) | ||
| 120 | { | 179 | { |
| 121 | struct dentry *dentry = file->f_dentry; | 180 | struct dentry *dentry = file->f_dentry; |
| 122 | struct inode *inode = dentry->d_inode; | 181 | struct inode *inode = dentry->d_inode; |
| 123 | struct evm_ima_xattr_data *xattr_value = NULL; | ||
| 124 | enum integrity_status status = INTEGRITY_UNKNOWN; | 182 | enum integrity_status status = INTEGRITY_UNKNOWN; |
| 125 | const char *op = "appraise_data"; | 183 | const char *op = "appraise_data"; |
| 126 | char *cause = "unknown"; | 184 | char *cause = "unknown"; |
| 127 | int rc; | 185 | int rc = xattr_len, hash_start = 0; |
| 128 | 186 | ||
| 129 | if (!ima_appraise) | 187 | if (!ima_appraise) |
| 130 | return 0; | 188 | return 0; |
| 131 | if (!inode->i_op->getxattr) | 189 | if (!inode->i_op->getxattr) |
| 132 | return INTEGRITY_UNKNOWN; | 190 | return INTEGRITY_UNKNOWN; |
| 133 | 191 | ||
| 134 | rc = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)&xattr_value, | ||
| 135 | 0, GFP_NOFS); | ||
| 136 | if (rc <= 0) { | 192 | if (rc <= 0) { |
| 137 | if (rc && rc != -ENODATA) | 193 | if (rc && rc != -ENODATA) |
| 138 | goto out; | 194 | goto out; |
| @@ -153,14 +209,25 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, | |||
| 153 | goto out; | 209 | goto out; |
| 154 | } | 210 | } |
| 155 | switch (xattr_value->type) { | 211 | switch (xattr_value->type) { |
| 212 | case IMA_XATTR_DIGEST_NG: | ||
| 213 | /* first byte contains algorithm id */ | ||
| 214 | hash_start = 1; | ||
| 156 | case IMA_XATTR_DIGEST: | 215 | case IMA_XATTR_DIGEST: |
| 157 | if (iint->flags & IMA_DIGSIG_REQUIRED) { | 216 | if (iint->flags & IMA_DIGSIG_REQUIRED) { |
| 158 | cause = "IMA signature required"; | 217 | cause = "IMA signature required"; |
| 159 | status = INTEGRITY_FAIL; | 218 | status = INTEGRITY_FAIL; |
| 160 | break; | 219 | break; |
| 161 | } | 220 | } |
| 162 | rc = memcmp(xattr_value->digest, iint->ima_xattr.digest, | 221 | if (xattr_len - sizeof(xattr_value->type) - hash_start >= |
| 163 | IMA_DIGEST_SIZE); | 222 | iint->ima_hash->length) |
| 223 | /* xattr length may be longer. md5 hash in previous | ||
| 224 | version occupied 20 bytes in xattr, instead of 16 | ||
| 225 | */ | ||
| 226 | rc = memcmp(&xattr_value->digest[hash_start], | ||
| 227 | iint->ima_hash->digest, | ||
| 228 | iint->ima_hash->length); | ||
| 229 | else | ||
| 230 | rc = -EINVAL; | ||
| 164 | if (rc) { | 231 | if (rc) { |
| 165 | cause = "invalid-hash"; | 232 | cause = "invalid-hash"; |
| 166 | status = INTEGRITY_FAIL; | 233 | status = INTEGRITY_FAIL; |
| @@ -171,9 +238,9 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, | |||
| 171 | case EVM_IMA_XATTR_DIGSIG: | 238 | case EVM_IMA_XATTR_DIGSIG: |
| 172 | iint->flags |= IMA_DIGSIG; | 239 | iint->flags |= IMA_DIGSIG; |
| 173 | rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, | 240 | rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, |
| 174 | xattr_value->digest, rc - 1, | 241 | (const char *)xattr_value, rc, |
| 175 | iint->ima_xattr.digest, | 242 | iint->ima_hash->digest, |
| 176 | IMA_DIGEST_SIZE); | 243 | iint->ima_hash->length); |
| 177 | if (rc == -EOPNOTSUPP) { | 244 | if (rc == -EOPNOTSUPP) { |
| 178 | status = INTEGRITY_UNKNOWN; | 245 | status = INTEGRITY_UNKNOWN; |
| 179 | } else if (rc) { | 246 | } else if (rc) { |
| @@ -203,7 +270,6 @@ out: | |||
| 203 | ima_cache_flags(iint, func); | 270 | ima_cache_flags(iint, func); |
| 204 | } | 271 | } |
| 205 | ima_set_cache_status(iint, func, status); | 272 | ima_set_cache_status(iint, func, status); |
| 206 | kfree(xattr_value); | ||
| 207 | return status; | 273 | return status; |
| 208 | } | 274 | } |
| 209 | 275 | ||
| @@ -219,7 +285,7 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) | |||
| 219 | if (iint->flags & IMA_DIGSIG) | 285 | if (iint->flags & IMA_DIGSIG) |
| 220 | return; | 286 | return; |
| 221 | 287 | ||
| 222 | rc = ima_collect_measurement(iint, file); | 288 | rc = ima_collect_measurement(iint, file, NULL, NULL); |
| 223 | if (rc < 0) | 289 | if (rc < 0) |
| 224 | return; | 290 | return; |
| 225 | 291 | ||
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index a02e0791cf15..fdf60def52e9 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/err.h> | 20 | #include <linux/err.h> |
| 21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
| 22 | #include <crypto/hash.h> | 22 | #include <crypto/hash.h> |
| 23 | #include <crypto/hash_info.h> | ||
| 23 | #include "ima.h" | 24 | #include "ima.h" |
| 24 | 25 | ||
| 25 | static struct crypto_shash *ima_shash_tfm; | 26 | static struct crypto_shash *ima_shash_tfm; |
| @@ -28,31 +29,58 @@ int ima_init_crypto(void) | |||
| 28 | { | 29 | { |
| 29 | long rc; | 30 | long rc; |
| 30 | 31 | ||
| 31 | ima_shash_tfm = crypto_alloc_shash(ima_hash, 0, 0); | 32 | ima_shash_tfm = crypto_alloc_shash(hash_algo_name[ima_hash_algo], 0, 0); |
| 32 | if (IS_ERR(ima_shash_tfm)) { | 33 | if (IS_ERR(ima_shash_tfm)) { |
| 33 | rc = PTR_ERR(ima_shash_tfm); | 34 | rc = PTR_ERR(ima_shash_tfm); |
| 34 | pr_err("Can not allocate %s (reason: %ld)\n", ima_hash, rc); | 35 | pr_err("Can not allocate %s (reason: %ld)\n", |
| 36 | hash_algo_name[ima_hash_algo], rc); | ||
| 35 | return rc; | 37 | return rc; |
| 36 | } | 38 | } |
| 37 | return 0; | 39 | return 0; |
| 38 | } | 40 | } |
| 39 | 41 | ||
| 42 | static struct crypto_shash *ima_alloc_tfm(enum hash_algo algo) | ||
| 43 | { | ||
| 44 | struct crypto_shash *tfm = ima_shash_tfm; | ||
| 45 | int rc; | ||
| 46 | |||
| 47 | if (algo != ima_hash_algo && algo < HASH_ALGO__LAST) { | ||
| 48 | tfm = crypto_alloc_shash(hash_algo_name[algo], 0, 0); | ||
| 49 | if (IS_ERR(tfm)) { | ||
| 50 | rc = PTR_ERR(tfm); | ||
| 51 | pr_err("Can not allocate %s (reason: %d)\n", | ||
| 52 | hash_algo_name[algo], rc); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | return tfm; | ||
| 56 | } | ||
| 57 | |||
| 58 | static void ima_free_tfm(struct crypto_shash *tfm) | ||
| 59 | { | ||
| 60 | if (tfm != ima_shash_tfm) | ||
| 61 | crypto_free_shash(tfm); | ||
| 62 | } | ||
| 63 | |||
| 40 | /* | 64 | /* |
| 41 | * Calculate the MD5/SHA1 file digest | 65 | * Calculate the MD5/SHA1 file digest |
| 42 | */ | 66 | */ |
| 43 | int ima_calc_file_hash(struct file *file, char *digest) | 67 | static int ima_calc_file_hash_tfm(struct file *file, |
| 68 | struct ima_digest_data *hash, | ||
| 69 | struct crypto_shash *tfm) | ||
| 44 | { | 70 | { |
| 45 | loff_t i_size, offset = 0; | 71 | loff_t i_size, offset = 0; |
| 46 | char *rbuf; | 72 | char *rbuf; |
| 47 | int rc, read = 0; | 73 | int rc, read = 0; |
| 48 | struct { | 74 | struct { |
| 49 | struct shash_desc shash; | 75 | struct shash_desc shash; |
| 50 | char ctx[crypto_shash_descsize(ima_shash_tfm)]; | 76 | char ctx[crypto_shash_descsize(tfm)]; |
| 51 | } desc; | 77 | } desc; |
| 52 | 78 | ||
| 53 | desc.shash.tfm = ima_shash_tfm; | 79 | desc.shash.tfm = tfm; |
| 54 | desc.shash.flags = 0; | 80 | desc.shash.flags = 0; |
| 55 | 81 | ||
| 82 | hash->length = crypto_shash_digestsize(tfm); | ||
| 83 | |||
| 56 | rc = crypto_shash_init(&desc.shash); | 84 | rc = crypto_shash_init(&desc.shash); |
| 57 | if (rc != 0) | 85 | if (rc != 0) |
| 58 | return rc; | 86 | return rc; |
| @@ -85,27 +113,90 @@ int ima_calc_file_hash(struct file *file, char *digest) | |||
| 85 | } | 113 | } |
| 86 | kfree(rbuf); | 114 | kfree(rbuf); |
| 87 | if (!rc) | 115 | if (!rc) |
| 88 | rc = crypto_shash_final(&desc.shash, digest); | 116 | rc = crypto_shash_final(&desc.shash, hash->digest); |
| 89 | if (read) | 117 | if (read) |
| 90 | file->f_mode &= ~FMODE_READ; | 118 | file->f_mode &= ~FMODE_READ; |
| 91 | out: | 119 | out: |
| 92 | return rc; | 120 | return rc; |
| 93 | } | 121 | } |
| 94 | 122 | ||
| 123 | int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) | ||
| 124 | { | ||
| 125 | struct crypto_shash *tfm; | ||
| 126 | int rc; | ||
| 127 | |||
| 128 | tfm = ima_alloc_tfm(hash->algo); | ||
| 129 | if (IS_ERR(tfm)) | ||
| 130 | return PTR_ERR(tfm); | ||
| 131 | |||
| 132 | rc = ima_calc_file_hash_tfm(file, hash, tfm); | ||
| 133 | |||
| 134 | ima_free_tfm(tfm); | ||
| 135 | |||
| 136 | return rc; | ||
| 137 | } | ||
| 138 | |||
| 95 | /* | 139 | /* |
| 96 | * Calculate the hash of a given buffer | 140 | * Calculate the hash of template data |
| 97 | */ | 141 | */ |
| 98 | int ima_calc_buffer_hash(const void *data, int len, char *digest) | 142 | static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, |
| 143 | struct ima_template_desc *td, | ||
| 144 | int num_fields, | ||
| 145 | struct ima_digest_data *hash, | ||
| 146 | struct crypto_shash *tfm) | ||
| 99 | { | 147 | { |
| 100 | struct { | 148 | struct { |
| 101 | struct shash_desc shash; | 149 | struct shash_desc shash; |
| 102 | char ctx[crypto_shash_descsize(ima_shash_tfm)]; | 150 | char ctx[crypto_shash_descsize(tfm)]; |
| 103 | } desc; | 151 | } desc; |
| 152 | int rc, i; | ||
| 104 | 153 | ||
| 105 | desc.shash.tfm = ima_shash_tfm; | 154 | desc.shash.tfm = tfm; |
| 106 | desc.shash.flags = 0; | 155 | desc.shash.flags = 0; |
| 107 | 156 | ||
| 108 | return crypto_shash_digest(&desc.shash, data, len, digest); | 157 | hash->length = crypto_shash_digestsize(tfm); |
| 158 | |||
| 159 | rc = crypto_shash_init(&desc.shash); | ||
| 160 | if (rc != 0) | ||
| 161 | return rc; | ||
| 162 | |||
| 163 | for (i = 0; i < num_fields; i++) { | ||
| 164 | if (strcmp(td->name, IMA_TEMPLATE_IMA_NAME) != 0) { | ||
| 165 | rc = crypto_shash_update(&desc.shash, | ||
| 166 | (const u8 *) &field_data[i].len, | ||
| 167 | sizeof(field_data[i].len)); | ||
| 168 | if (rc) | ||
| 169 | break; | ||
| 170 | } | ||
| 171 | rc = crypto_shash_update(&desc.shash, field_data[i].data, | ||
| 172 | field_data[i].len); | ||
| 173 | if (rc) | ||
| 174 | break; | ||
| 175 | } | ||
| 176 | |||
| 177 | if (!rc) | ||
| 178 | rc = crypto_shash_final(&desc.shash, hash->digest); | ||
| 179 | |||
| 180 | return rc; | ||
| 181 | } | ||
| 182 | |||
| 183 | int ima_calc_field_array_hash(struct ima_field_data *field_data, | ||
| 184 | struct ima_template_desc *desc, int num_fields, | ||
| 185 | struct ima_digest_data *hash) | ||
| 186 | { | ||
| 187 | struct crypto_shash *tfm; | ||
| 188 | int rc; | ||
| 189 | |||
| 190 | tfm = ima_alloc_tfm(hash->algo); | ||
| 191 | if (IS_ERR(tfm)) | ||
| 192 | return PTR_ERR(tfm); | ||
| 193 | |||
| 194 | rc = ima_calc_field_array_hash_tfm(field_data, desc, num_fields, | ||
| 195 | hash, tfm); | ||
| 196 | |||
| 197 | ima_free_tfm(tfm); | ||
| 198 | |||
| 199 | return rc; | ||
| 109 | } | 200 | } |
| 110 | 201 | ||
| 111 | static void __init ima_pcrread(int idx, u8 *pcr) | 202 | static void __init ima_pcrread(int idx, u8 *pcr) |
| @@ -120,16 +211,17 @@ static void __init ima_pcrread(int idx, u8 *pcr) | |||
| 120 | /* | 211 | /* |
| 121 | * Calculate the boot aggregate hash | 212 | * Calculate the boot aggregate hash |
| 122 | */ | 213 | */ |
| 123 | int __init ima_calc_boot_aggregate(char *digest) | 214 | static int __init ima_calc_boot_aggregate_tfm(char *digest, |
| 215 | struct crypto_shash *tfm) | ||
| 124 | { | 216 | { |
| 125 | u8 pcr_i[IMA_DIGEST_SIZE]; | 217 | u8 pcr_i[TPM_DIGEST_SIZE]; |
| 126 | int rc, i; | 218 | int rc, i; |
| 127 | struct { | 219 | struct { |
| 128 | struct shash_desc shash; | 220 | struct shash_desc shash; |
| 129 | char ctx[crypto_shash_descsize(ima_shash_tfm)]; | 221 | char ctx[crypto_shash_descsize(tfm)]; |
| 130 | } desc; | 222 | } desc; |
| 131 | 223 | ||
| 132 | desc.shash.tfm = ima_shash_tfm; | 224 | desc.shash.tfm = tfm; |
| 133 | desc.shash.flags = 0; | 225 | desc.shash.flags = 0; |
| 134 | 226 | ||
| 135 | rc = crypto_shash_init(&desc.shash); | 227 | rc = crypto_shash_init(&desc.shash); |
| @@ -140,9 +232,26 @@ int __init ima_calc_boot_aggregate(char *digest) | |||
| 140 | for (i = TPM_PCR0; i < TPM_PCR8; i++) { | 232 | for (i = TPM_PCR0; i < TPM_PCR8; i++) { |
| 141 | ima_pcrread(i, pcr_i); | 233 | ima_pcrread(i, pcr_i); |
| 142 | /* now accumulate with current aggregate */ | 234 | /* now accumulate with current aggregate */ |
| 143 | rc = crypto_shash_update(&desc.shash, pcr_i, IMA_DIGEST_SIZE); | 235 | rc = crypto_shash_update(&desc.shash, pcr_i, TPM_DIGEST_SIZE); |
| 144 | } | 236 | } |
| 145 | if (!rc) | 237 | if (!rc) |
| 146 | crypto_shash_final(&desc.shash, digest); | 238 | crypto_shash_final(&desc.shash, digest); |
| 147 | return rc; | 239 | return rc; |
| 148 | } | 240 | } |
| 241 | |||
| 242 | int __init ima_calc_boot_aggregate(struct ima_digest_data *hash) | ||
| 243 | { | ||
| 244 | struct crypto_shash *tfm; | ||
| 245 | int rc; | ||
| 246 | |||
| 247 | tfm = ima_alloc_tfm(hash->algo); | ||
| 248 | if (IS_ERR(tfm)) | ||
| 249 | return PTR_ERR(tfm); | ||
| 250 | |||
| 251 | hash->length = crypto_shash_digestsize(tfm); | ||
| 252 | rc = ima_calc_boot_aggregate_tfm(hash->digest, tfm); | ||
| 253 | |||
| 254 | ima_free_tfm(tfm); | ||
| 255 | |||
| 256 | return rc; | ||
| 257 | } | ||
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 38477c9c3415..db01125926bd 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c | |||
| @@ -88,8 +88,7 @@ static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos) | |||
| 88 | * against concurrent list-extension | 88 | * against concurrent list-extension |
| 89 | */ | 89 | */ |
| 90 | rcu_read_lock(); | 90 | rcu_read_lock(); |
| 91 | qe = list_entry_rcu(qe->later.next, | 91 | qe = list_entry_rcu(qe->later.next, struct ima_queue_entry, later); |
| 92 | struct ima_queue_entry, later); | ||
| 93 | rcu_read_unlock(); | 92 | rcu_read_unlock(); |
| 94 | (*pos)++; | 93 | (*pos)++; |
| 95 | 94 | ||
| @@ -100,7 +99,7 @@ static void ima_measurements_stop(struct seq_file *m, void *v) | |||
| 100 | { | 99 | { |
| 101 | } | 100 | } |
| 102 | 101 | ||
| 103 | static void ima_putc(struct seq_file *m, void *data, int datalen) | 102 | void ima_putc(struct seq_file *m, void *data, int datalen) |
| 104 | { | 103 | { |
| 105 | while (datalen--) | 104 | while (datalen--) |
| 106 | seq_putc(m, *(char *)data++); | 105 | seq_putc(m, *(char *)data++); |
| @@ -111,6 +110,7 @@ static void ima_putc(struct seq_file *m, void *data, int datalen) | |||
| 111 | * char[20]=template digest | 110 | * char[20]=template digest |
| 112 | * 32bit-le=template name size | 111 | * 32bit-le=template name size |
| 113 | * char[n]=template name | 112 | * char[n]=template name |
| 113 | * [eventdata length] | ||
| 114 | * eventdata[n]=template specific data | 114 | * eventdata[n]=template specific data |
| 115 | */ | 115 | */ |
| 116 | static int ima_measurements_show(struct seq_file *m, void *v) | 116 | static int ima_measurements_show(struct seq_file *m, void *v) |
| @@ -120,6 +120,8 @@ static int ima_measurements_show(struct seq_file *m, void *v) | |||
| 120 | struct ima_template_entry *e; | 120 | struct ima_template_entry *e; |
| 121 | int namelen; | 121 | int namelen; |
| 122 | u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX; | 122 | u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX; |
| 123 | bool is_ima_template = false; | ||
| 124 | int i; | ||
| 123 | 125 | ||
| 124 | /* get entry */ | 126 | /* get entry */ |
| 125 | e = qe->entry; | 127 | e = qe->entry; |
| @@ -134,18 +136,32 @@ static int ima_measurements_show(struct seq_file *m, void *v) | |||
| 134 | ima_putc(m, &pcr, sizeof pcr); | 136 | ima_putc(m, &pcr, sizeof pcr); |
| 135 | 137 | ||
| 136 | /* 2nd: template digest */ | 138 | /* 2nd: template digest */ |
| 137 | ima_putc(m, e->digest, IMA_DIGEST_SIZE); | 139 | ima_putc(m, e->digest, TPM_DIGEST_SIZE); |
| 138 | 140 | ||
| 139 | /* 3rd: template name size */ | 141 | /* 3rd: template name size */ |
| 140 | namelen = strlen(e->template_name); | 142 | namelen = strlen(e->template_desc->name); |
| 141 | ima_putc(m, &namelen, sizeof namelen); | 143 | ima_putc(m, &namelen, sizeof namelen); |
| 142 | 144 | ||
| 143 | /* 4th: template name */ | 145 | /* 4th: template name */ |
| 144 | ima_putc(m, (void *)e->template_name, namelen); | 146 | ima_putc(m, e->template_desc->name, namelen); |
| 147 | |||
| 148 | /* 5th: template length (except for 'ima' template) */ | ||
| 149 | if (strcmp(e->template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) | ||
| 150 | is_ima_template = true; | ||
| 151 | |||
| 152 | if (!is_ima_template) | ||
| 153 | ima_putc(m, &e->template_data_len, | ||
| 154 | sizeof(e->template_data_len)); | ||
| 155 | |||
| 156 | /* 6th: template specific data */ | ||
| 157 | for (i = 0; i < e->template_desc->num_fields; i++) { | ||
| 158 | enum ima_show_type show = IMA_SHOW_BINARY; | ||
| 159 | struct ima_template_field *field = e->template_desc->fields[i]; | ||
| 145 | 160 | ||
| 146 | /* 5th: template specific data */ | 161 | if (is_ima_template && strcmp(field->field_id, "d") == 0) |
| 147 | ima_template_show(m, (struct ima_template_data *)&e->template, | 162 | show = IMA_SHOW_BINARY_NO_FIELD_LEN; |
| 148 | IMA_SHOW_BINARY); | 163 | field->field_show(m, show, &e->template_data[i]); |
| 164 | } | ||
| 149 | return 0; | 165 | return 0; |
| 150 | } | 166 | } |
| 151 | 167 | ||
| @@ -168,41 +184,21 @@ static const struct file_operations ima_measurements_ops = { | |||
| 168 | .release = seq_release, | 184 | .release = seq_release, |
| 169 | }; | 185 | }; |
| 170 | 186 | ||
| 171 | static void ima_print_digest(struct seq_file *m, u8 *digest) | 187 | void ima_print_digest(struct seq_file *m, u8 *digest, int size) |
| 172 | { | 188 | { |
| 173 | int i; | 189 | int i; |
| 174 | 190 | ||
| 175 | for (i = 0; i < IMA_DIGEST_SIZE; i++) | 191 | for (i = 0; i < size; i++) |
| 176 | seq_printf(m, "%02x", *(digest + i)); | 192 | seq_printf(m, "%02x", *(digest + i)); |
| 177 | } | 193 | } |
| 178 | 194 | ||
| 179 | void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show) | ||
| 180 | { | ||
| 181 | struct ima_template_data *entry = e; | ||
| 182 | int namelen; | ||
| 183 | |||
| 184 | switch (show) { | ||
| 185 | case IMA_SHOW_ASCII: | ||
| 186 | ima_print_digest(m, entry->digest); | ||
| 187 | seq_printf(m, " %s\n", entry->file_name); | ||
| 188 | break; | ||
| 189 | case IMA_SHOW_BINARY: | ||
| 190 | ima_putc(m, entry->digest, IMA_DIGEST_SIZE); | ||
| 191 | |||
| 192 | namelen = strlen(entry->file_name); | ||
| 193 | ima_putc(m, &namelen, sizeof namelen); | ||
| 194 | ima_putc(m, entry->file_name, namelen); | ||
| 195 | default: | ||
| 196 | break; | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | /* print in ascii */ | 195 | /* print in ascii */ |
| 201 | static int ima_ascii_measurements_show(struct seq_file *m, void *v) | 196 | static int ima_ascii_measurements_show(struct seq_file *m, void *v) |
| 202 | { | 197 | { |
| 203 | /* the list never shrinks, so we don't need a lock here */ | 198 | /* the list never shrinks, so we don't need a lock here */ |
| 204 | struct ima_queue_entry *qe = v; | 199 | struct ima_queue_entry *qe = v; |
| 205 | struct ima_template_entry *e; | 200 | struct ima_template_entry *e; |
| 201 | int i; | ||
| 206 | 202 | ||
| 207 | /* get entry */ | 203 | /* get entry */ |
| 208 | e = qe->entry; | 204 | e = qe->entry; |
| @@ -213,14 +209,21 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v) | |||
| 213 | seq_printf(m, "%2d ", CONFIG_IMA_MEASURE_PCR_IDX); | 209 | seq_printf(m, "%2d ", CONFIG_IMA_MEASURE_PCR_IDX); |
| 214 | 210 | ||
| 215 | /* 2nd: SHA1 template hash */ | 211 | /* 2nd: SHA1 template hash */ |
| 216 | ima_print_digest(m, e->digest); | 212 | ima_print_digest(m, e->digest, TPM_DIGEST_SIZE); |
| 217 | 213 | ||
| 218 | /* 3th: template name */ | 214 | /* 3th: template name */ |
| 219 | seq_printf(m, " %s ", e->template_name); | 215 | seq_printf(m, " %s", e->template_desc->name); |
| 220 | 216 | ||
| 221 | /* 4th: template specific data */ | 217 | /* 4th: template specific data */ |
| 222 | ima_template_show(m, (struct ima_template_data *)&e->template, | 218 | for (i = 0; i < e->template_desc->num_fields; i++) { |
| 223 | IMA_SHOW_ASCII); | 219 | seq_puts(m, " "); |
| 220 | if (e->template_data[i].len == 0) | ||
| 221 | continue; | ||
| 222 | |||
| 223 | e->template_desc->fields[i]->field_show(m, IMA_SHOW_ASCII, | ||
| 224 | &e->template_data[i]); | ||
| 225 | } | ||
| 226 | seq_puts(m, "\n"); | ||
| 224 | return 0; | 227 | return 0; |
| 225 | } | 228 | } |
| 226 | 229 | ||
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 162ea723db3d..37122768554a 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <linux/scatterlist.h> | 18 | #include <linux/scatterlist.h> |
| 19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
| 20 | #include <linux/err.h> | 20 | #include <linux/err.h> |
| 21 | #include <crypto/hash_info.h> | ||
| 21 | #include "ima.h" | 22 | #include "ima.h" |
| 22 | 23 | ||
| 23 | /* name for boot aggregate entry */ | 24 | /* name for boot aggregate entry */ |
| @@ -42,30 +43,39 @@ int ima_used_chip; | |||
| 42 | static void __init ima_add_boot_aggregate(void) | 43 | static void __init ima_add_boot_aggregate(void) |
| 43 | { | 44 | { |
| 44 | struct ima_template_entry *entry; | 45 | struct ima_template_entry *entry; |
| 46 | struct integrity_iint_cache tmp_iint, *iint = &tmp_iint; | ||
| 45 | const char *op = "add_boot_aggregate"; | 47 | const char *op = "add_boot_aggregate"; |
| 46 | const char *audit_cause = "ENOMEM"; | 48 | const char *audit_cause = "ENOMEM"; |
| 47 | int result = -ENOMEM; | 49 | int result = -ENOMEM; |
| 48 | int violation = 1; | 50 | int violation = 0; |
| 51 | struct { | ||
| 52 | struct ima_digest_data hdr; | ||
| 53 | char digest[TPM_DIGEST_SIZE]; | ||
| 54 | } hash; | ||
| 49 | 55 | ||
| 50 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | 56 | memset(iint, 0, sizeof(*iint)); |
| 51 | if (!entry) | 57 | memset(&hash, 0, sizeof(hash)); |
| 52 | goto err_out; | 58 | iint->ima_hash = &hash.hdr; |
| 59 | iint->ima_hash->algo = HASH_ALGO_SHA1; | ||
| 60 | iint->ima_hash->length = SHA1_DIGEST_SIZE; | ||
| 53 | 61 | ||
| 54 | memset(&entry->template, 0, sizeof(entry->template)); | ||
| 55 | strncpy(entry->template.file_name, boot_aggregate_name, | ||
| 56 | IMA_EVENT_NAME_LEN_MAX); | ||
| 57 | if (ima_used_chip) { | 62 | if (ima_used_chip) { |
| 58 | violation = 0; | 63 | result = ima_calc_boot_aggregate(&hash.hdr); |
| 59 | result = ima_calc_boot_aggregate(entry->template.digest); | ||
| 60 | if (result < 0) { | 64 | if (result < 0) { |
| 61 | audit_cause = "hashing_error"; | 65 | audit_cause = "hashing_error"; |
| 62 | kfree(entry); | ||
| 63 | goto err_out; | 66 | goto err_out; |
| 64 | } | 67 | } |
| 65 | } | 68 | } |
| 66 | result = ima_store_template(entry, violation, NULL); | 69 | |
| 70 | result = ima_alloc_init_template(iint, NULL, boot_aggregate_name, | ||
| 71 | NULL, 0, &entry); | ||
| 72 | if (result < 0) | ||
| 73 | return; | ||
| 74 | |||
| 75 | result = ima_store_template(entry, violation, NULL, | ||
| 76 | boot_aggregate_name); | ||
| 67 | if (result < 0) | 77 | if (result < 0) |
| 68 | kfree(entry); | 78 | ima_free_template_entry(entry); |
| 69 | return; | 79 | return; |
| 70 | err_out: | 80 | err_out: |
| 71 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op, | 81 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op, |
| @@ -74,7 +84,7 @@ err_out: | |||
| 74 | 84 | ||
| 75 | int __init ima_init(void) | 85 | int __init ima_init(void) |
| 76 | { | 86 | { |
| 77 | u8 pcr_i[IMA_DIGEST_SIZE]; | 87 | u8 pcr_i[TPM_DIGEST_SIZE]; |
| 78 | int rc; | 88 | int rc; |
| 79 | 89 | ||
| 80 | ima_used_chip = 0; | 90 | ima_used_chip = 0; |
| @@ -88,6 +98,10 @@ int __init ima_init(void) | |||
| 88 | rc = ima_init_crypto(); | 98 | rc = ima_init_crypto(); |
| 89 | if (rc) | 99 | if (rc) |
| 90 | return rc; | 100 | return rc; |
| 101 | rc = ima_init_template(); | ||
| 102 | if (rc != 0) | ||
| 103 | return rc; | ||
| 104 | |||
| 91 | ima_add_boot_aggregate(); /* boot aggregate must be first entry */ | 105 | ima_add_boot_aggregate(); /* boot aggregate must be first entry */ |
| 92 | ima_init_policy(); | 106 | ima_init_policy(); |
| 93 | 107 | ||
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index e9508d5bbfcf..149ee1119f87 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
| 25 | #include <linux/xattr.h> | 25 | #include <linux/xattr.h> |
| 26 | #include <linux/ima.h> | 26 | #include <linux/ima.h> |
| 27 | #include <crypto/hash_info.h> | ||
| 27 | 28 | ||
| 28 | #include "ima.h" | 29 | #include "ima.h" |
| 29 | 30 | ||
| @@ -35,11 +36,33 @@ int ima_appraise = IMA_APPRAISE_ENFORCE; | |||
| 35 | int ima_appraise; | 36 | int ima_appraise; |
| 36 | #endif | 37 | #endif |
| 37 | 38 | ||
| 38 | char *ima_hash = "sha1"; | 39 | int ima_hash_algo = HASH_ALGO_SHA1; |
| 40 | static int hash_setup_done; | ||
| 41 | |||
| 39 | static int __init hash_setup(char *str) | 42 | static int __init hash_setup(char *str) |
| 40 | { | 43 | { |
| 41 | if (strncmp(str, "md5", 3) == 0) | 44 | struct ima_template_desc *template_desc = ima_template_desc_current(); |
| 42 | ima_hash = "md5"; | 45 | int i; |
| 46 | |||
| 47 | if (hash_setup_done) | ||
| 48 | return 1; | ||
| 49 | |||
| 50 | if (strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) { | ||
| 51 | if (strncmp(str, "sha1", 4) == 0) | ||
| 52 | ima_hash_algo = HASH_ALGO_SHA1; | ||
| 53 | else if (strncmp(str, "md5", 3) == 0) | ||
| 54 | ima_hash_algo = HASH_ALGO_MD5; | ||
| 55 | goto out; | ||
| 56 | } | ||
| 57 | |||
| 58 | for (i = 0; i < HASH_ALGO__LAST; i++) { | ||
| 59 | if (strcmp(str, hash_algo_name[i]) == 0) { | ||
| 60 | ima_hash_algo = i; | ||
| 61 | break; | ||
| 62 | } | ||
| 63 | } | ||
| 64 | out: | ||
| 65 | hash_setup_done = 1; | ||
| 43 | return 1; | 66 | return 1; |
| 44 | } | 67 | } |
| 45 | __setup("ima_hash=", hash_setup); | 68 | __setup("ima_hash=", hash_setup); |
| @@ -92,10 +115,9 @@ out: | |||
| 92 | pathname = dentry->d_name.name; | 115 | pathname = dentry->d_name.name; |
| 93 | 116 | ||
| 94 | if (send_tomtou) | 117 | if (send_tomtou) |
| 95 | ima_add_violation(inode, pathname, | 118 | ima_add_violation(file, pathname, "invalid_pcr", "ToMToU"); |
| 96 | "invalid_pcr", "ToMToU"); | ||
| 97 | if (send_writers) | 119 | if (send_writers) |
| 98 | ima_add_violation(inode, pathname, | 120 | ima_add_violation(file, pathname, |
| 99 | "invalid_pcr", "open_writers"); | 121 | "invalid_pcr", "open_writers"); |
| 100 | kfree(pathbuf); | 122 | kfree(pathbuf); |
| 101 | } | 123 | } |
| @@ -144,9 +166,12 @@ static int process_measurement(struct file *file, const char *filename, | |||
| 144 | { | 166 | { |
| 145 | struct inode *inode = file_inode(file); | 167 | struct inode *inode = file_inode(file); |
| 146 | struct integrity_iint_cache *iint; | 168 | struct integrity_iint_cache *iint; |
| 169 | struct ima_template_desc *template_desc = ima_template_desc_current(); | ||
| 147 | char *pathbuf = NULL; | 170 | char *pathbuf = NULL; |
| 148 | const char *pathname = NULL; | 171 | const char *pathname = NULL; |
| 149 | int rc = -ENOMEM, action, must_appraise, _func; | 172 | int rc = -ENOMEM, action, must_appraise, _func; |
| 173 | struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL; | ||
| 174 | int xattr_len = 0; | ||
| 150 | 175 | ||
| 151 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | 176 | if (!ima_initialized || !S_ISREG(inode->i_mode)) |
| 152 | return 0; | 177 | return 0; |
| @@ -185,7 +210,13 @@ static int process_measurement(struct file *file, const char *filename, | |||
| 185 | goto out_digsig; | 210 | goto out_digsig; |
| 186 | } | 211 | } |
| 187 | 212 | ||
| 188 | rc = ima_collect_measurement(iint, file); | 213 | if (strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) { |
| 214 | if (action & IMA_APPRAISE_SUBMASK) | ||
| 215 | xattr_ptr = &xattr_value; | ||
| 216 | } else | ||
| 217 | xattr_ptr = &xattr_value; | ||
| 218 | |||
| 219 | rc = ima_collect_measurement(iint, file, xattr_ptr, &xattr_len); | ||
| 189 | if (rc != 0) | 220 | if (rc != 0) |
| 190 | goto out_digsig; | 221 | goto out_digsig; |
| 191 | 222 | ||
| @@ -194,9 +225,11 @@ static int process_measurement(struct file *file, const char *filename, | |||
| 194 | pathname = (const char *)file->f_dentry->d_name.name; | 225 | pathname = (const char *)file->f_dentry->d_name.name; |
| 195 | 226 | ||
| 196 | if (action & IMA_MEASURE) | 227 | if (action & IMA_MEASURE) |
| 197 | ima_store_measurement(iint, file, pathname); | 228 | ima_store_measurement(iint, file, pathname, |
| 229 | xattr_value, xattr_len); | ||
| 198 | if (action & IMA_APPRAISE_SUBMASK) | 230 | if (action & IMA_APPRAISE_SUBMASK) |
| 199 | rc = ima_appraise_measurement(_func, iint, file, pathname); | 231 | rc = ima_appraise_measurement(_func, iint, file, pathname, |
| 232 | xattr_value, xattr_len); | ||
| 200 | if (action & IMA_AUDIT) | 233 | if (action & IMA_AUDIT) |
| 201 | ima_audit_measurement(iint, pathname); | 234 | ima_audit_measurement(iint, pathname); |
| 202 | kfree(pathbuf); | 235 | kfree(pathbuf); |
| @@ -205,6 +238,7 @@ out_digsig: | |||
| 205 | rc = -EACCES; | 238 | rc = -EACCES; |
| 206 | out: | 239 | out: |
| 207 | mutex_unlock(&inode->i_mutex); | 240 | mutex_unlock(&inode->i_mutex); |
| 241 | kfree(xattr_value); | ||
| 208 | if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) | 242 | if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) |
| 209 | return -EACCES; | 243 | return -EACCES; |
| 210 | return 0; | 244 | return 0; |
| @@ -244,9 +278,9 @@ int ima_file_mmap(struct file *file, unsigned long prot) | |||
| 244 | int ima_bprm_check(struct linux_binprm *bprm) | 278 | int ima_bprm_check(struct linux_binprm *bprm) |
| 245 | { | 279 | { |
| 246 | return process_measurement(bprm->file, | 280 | return process_measurement(bprm->file, |
| 247 | (strcmp(bprm->filename, bprm->interp) == 0) ? | 281 | (strcmp(bprm->filename, bprm->interp) == 0) ? |
| 248 | bprm->filename : bprm->interp, | 282 | bprm->filename : bprm->interp, |
| 249 | MAY_EXEC, BPRM_CHECK); | 283 | MAY_EXEC, BPRM_CHECK); |
| 250 | } | 284 | } |
| 251 | 285 | ||
| 252 | /** | 286 | /** |
| @@ -263,8 +297,8 @@ int ima_file_check(struct file *file, int mask) | |||
| 263 | { | 297 | { |
| 264 | ima_rdwr_violation_check(file); | 298 | ima_rdwr_violation_check(file); |
| 265 | return process_measurement(file, NULL, | 299 | return process_measurement(file, NULL, |
| 266 | mask & (MAY_READ | MAY_WRITE | MAY_EXEC), | 300 | mask & (MAY_READ | MAY_WRITE | MAY_EXEC), |
| 267 | FILE_CHECK); | 301 | FILE_CHECK); |
| 268 | } | 302 | } |
| 269 | EXPORT_SYMBOL_GPL(ima_file_check); | 303 | EXPORT_SYMBOL_GPL(ima_file_check); |
| 270 | 304 | ||
| @@ -294,6 +328,7 @@ static int __init init_ima(void) | |||
| 294 | { | 328 | { |
| 295 | int error; | 329 | int error; |
| 296 | 330 | ||
| 331 | hash_setup(CONFIG_IMA_DEFAULT_HASH); | ||
| 297 | error = ima_init(); | 332 | error = ima_init(); |
| 298 | if (!error) | 333 | if (!error) |
| 299 | ima_initialized = 1; | 334 | ima_initialized = 1; |
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 399433ad614e..a9c3d3cd1990 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
| @@ -73,7 +73,6 @@ static struct ima_rule_entry default_rules[] = { | |||
| 73 | {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, | 73 | {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, |
| 74 | {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, | 74 | {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, |
| 75 | {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, | 75 | {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, |
| 76 | {.action = DONT_MEASURE,.fsmagic = RAMFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
| 77 | {.action = DONT_MEASURE,.fsmagic = DEVPTS_SUPER_MAGIC,.flags = IMA_FSMAGIC}, | 76 | {.action = DONT_MEASURE,.fsmagic = DEVPTS_SUPER_MAGIC,.flags = IMA_FSMAGIC}, |
| 78 | {.action = DONT_MEASURE,.fsmagic = BINFMTFS_MAGIC,.flags = IMA_FSMAGIC}, | 77 | {.action = DONT_MEASURE,.fsmagic = BINFMTFS_MAGIC,.flags = IMA_FSMAGIC}, |
| 79 | {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC}, | 78 | {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC}, |
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index ff63fe00c195..d85e99761f4f 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c | |||
| @@ -50,7 +50,7 @@ static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value) | |||
| 50 | key = ima_hash_key(digest_value); | 50 | key = ima_hash_key(digest_value); |
| 51 | rcu_read_lock(); | 51 | rcu_read_lock(); |
| 52 | hlist_for_each_entry_rcu(qe, &ima_htable.queue[key], hnext) { | 52 | hlist_for_each_entry_rcu(qe, &ima_htable.queue[key], hnext) { |
| 53 | rc = memcmp(qe->entry->digest, digest_value, IMA_DIGEST_SIZE); | 53 | rc = memcmp(qe->entry->digest, digest_value, TPM_DIGEST_SIZE); |
| 54 | if (rc == 0) { | 54 | if (rc == 0) { |
| 55 | ret = qe; | 55 | ret = qe; |
| 56 | break; | 56 | break; |
| @@ -104,9 +104,10 @@ static int ima_pcr_extend(const u8 *hash) | |||
| 104 | * and extend the pcr. | 104 | * and extend the pcr. |
| 105 | */ | 105 | */ |
| 106 | int ima_add_template_entry(struct ima_template_entry *entry, int violation, | 106 | int ima_add_template_entry(struct ima_template_entry *entry, int violation, |
| 107 | const char *op, struct inode *inode) | 107 | const char *op, struct inode *inode, |
| 108 | const unsigned char *filename) | ||
| 108 | { | 109 | { |
| 109 | u8 digest[IMA_DIGEST_SIZE]; | 110 | u8 digest[TPM_DIGEST_SIZE]; |
| 110 | const char *audit_cause = "hash_added"; | 111 | const char *audit_cause = "hash_added"; |
| 111 | char tpm_audit_cause[AUDIT_CAUSE_LEN_MAX]; | 112 | char tpm_audit_cause[AUDIT_CAUSE_LEN_MAX]; |
| 112 | int audit_info = 1; | 113 | int audit_info = 1; |
| @@ -141,8 +142,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, | |||
| 141 | } | 142 | } |
| 142 | out: | 143 | out: |
| 143 | mutex_unlock(&ima_extend_list_mutex); | 144 | mutex_unlock(&ima_extend_list_mutex); |
| 144 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, | 145 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, |
| 145 | entry->template.file_name, | ||
| 146 | op, audit_cause, result, audit_info); | 146 | op, audit_cause, result, audit_info); |
| 147 | return result; | 147 | return result; |
| 148 | } | 148 | } |
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c new file mode 100644 index 000000000000..635695f6a185 --- /dev/null +++ b/security/integrity/ima/ima_template.c | |||
| @@ -0,0 +1,187 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2013 Politecnico di Torino, Italy | ||
| 3 | * TORSEC group -- http://security.polito.it | ||
| 4 | * | ||
| 5 | * Author: Roberto Sassu <roberto.sassu@polito.it> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License as | ||
| 9 | * published by the Free Software Foundation, version 2 of the | ||
| 10 | * License. | ||
| 11 | * | ||
| 12 | * File: ima_template.c | ||
| 13 | * Helpers to manage template descriptors. | ||
| 14 | */ | ||
| 15 | #include <crypto/hash_info.h> | ||
| 16 | |||
| 17 | #include "ima.h" | ||
| 18 | #include "ima_template_lib.h" | ||
| 19 | |||
| 20 | static struct ima_template_desc defined_templates[] = { | ||
| 21 | {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT}, | ||
| 22 | {.name = "ima-ng",.fmt = "d-ng|n-ng"}, | ||
| 23 | {.name = "ima-sig",.fmt = "d-ng|n-ng|sig"}, | ||
| 24 | }; | ||
| 25 | |||
| 26 | static struct ima_template_field supported_fields[] = { | ||
| 27 | {.field_id = "d",.field_init = ima_eventdigest_init, | ||
| 28 | .field_show = ima_show_template_digest}, | ||
| 29 | {.field_id = "n",.field_init = ima_eventname_init, | ||
| 30 | .field_show = ima_show_template_string}, | ||
| 31 | {.field_id = "d-ng",.field_init = ima_eventdigest_ng_init, | ||
| 32 | .field_show = ima_show_template_digest_ng}, | ||
| 33 | {.field_id = "n-ng",.field_init = ima_eventname_ng_init, | ||
| 34 | .field_show = ima_show_template_string}, | ||
| 35 | {.field_id = "sig",.field_init = ima_eventsig_init, | ||
| 36 | .field_show = ima_show_template_sig}, | ||
| 37 | }; | ||
| 38 | |||
| 39 | static struct ima_template_desc *ima_template; | ||
| 40 | static struct ima_template_desc *lookup_template_desc(const char *name); | ||
| 41 | |||
| 42 | static int __init ima_template_setup(char *str) | ||
| 43 | { | ||
| 44 | struct ima_template_desc *template_desc; | ||
| 45 | int template_len = strlen(str); | ||
| 46 | |||
| 47 | /* | ||
| 48 | * Verify that a template with the supplied name exists. | ||
| 49 | * If not, use CONFIG_IMA_DEFAULT_TEMPLATE. | ||
| 50 | */ | ||
| 51 | template_desc = lookup_template_desc(str); | ||
| 52 | if (!template_desc) | ||
| 53 | return 1; | ||
| 54 | |||
| 55 | /* | ||
| 56 | * Verify whether the current hash algorithm is supported | ||
| 57 | * by the 'ima' template. | ||
| 58 | */ | ||
| 59 | if (template_len == 3 && strcmp(str, IMA_TEMPLATE_IMA_NAME) == 0 && | ||
| 60 | ima_hash_algo != HASH_ALGO_SHA1 && ima_hash_algo != HASH_ALGO_MD5) { | ||
| 61 | pr_err("IMA: template does not support hash alg\n"); | ||
| 62 | return 1; | ||
| 63 | } | ||
| 64 | |||
| 65 | ima_template = template_desc; | ||
| 66 | return 1; | ||
| 67 | } | ||
| 68 | __setup("ima_template=", ima_template_setup); | ||
| 69 | |||
| 70 | static struct ima_template_desc *lookup_template_desc(const char *name) | ||
| 71 | { | ||
| 72 | int i; | ||
| 73 | |||
| 74 | for (i = 0; i < ARRAY_SIZE(defined_templates); i++) { | ||
| 75 | if (strcmp(defined_templates[i].name, name) == 0) | ||
| 76 | return defined_templates + i; | ||
| 77 | } | ||
| 78 | |||
| 79 | return NULL; | ||
| 80 | } | ||
| 81 | |||
| 82 | static struct ima_template_field *lookup_template_field(const char *field_id) | ||
| 83 | { | ||
| 84 | int i; | ||
| 85 | |||
| 86 | for (i = 0; i < ARRAY_SIZE(supported_fields); i++) | ||
| 87 | if (strncmp(supported_fields[i].field_id, field_id, | ||
| 88 | IMA_TEMPLATE_FIELD_ID_MAX_LEN) == 0) | ||
| 89 | return &supported_fields[i]; | ||
| 90 | return NULL; | ||
| 91 | } | ||
| 92 | |||
| 93 | static int template_fmt_size(const char *template_fmt) | ||
| 94 | { | ||
| 95 | char c; | ||
| 96 | int template_fmt_len = strlen(template_fmt); | ||
| 97 | int i = 0, j = 0; | ||
| 98 | |||
| 99 | while (i < template_fmt_len) { | ||
| 100 | c = template_fmt[i]; | ||
| 101 | if (c == '|') | ||
| 102 | j++; | ||
| 103 | i++; | ||
| 104 | } | ||
| 105 | |||
| 106 | return j + 1; | ||
| 107 | } | ||
| 108 | |||
| 109 | static int template_desc_init_fields(const char *template_fmt, | ||
| 110 | struct ima_template_field ***fields, | ||
| 111 | int *num_fields) | ||
| 112 | { | ||
| 113 | char *c, *template_fmt_copy, *template_fmt_ptr; | ||
| 114 | int template_num_fields = template_fmt_size(template_fmt); | ||
| 115 | int i, result = 0; | ||
| 116 | |||
| 117 | if (template_num_fields > IMA_TEMPLATE_NUM_FIELDS_MAX) | ||
| 118 | return -EINVAL; | ||
| 119 | |||
| 120 | /* copying is needed as strsep() modifies the original buffer */ | ||
| 121 | template_fmt_copy = kstrdup(template_fmt, GFP_KERNEL); | ||
| 122 | if (template_fmt_copy == NULL) | ||
| 123 | return -ENOMEM; | ||
| 124 | |||
| 125 | *fields = kzalloc(template_num_fields * sizeof(*fields), GFP_KERNEL); | ||
| 126 | if (*fields == NULL) { | ||
| 127 | result = -ENOMEM; | ||
| 128 | goto out; | ||
| 129 | } | ||
| 130 | |||
| 131 | template_fmt_ptr = template_fmt_copy; | ||
| 132 | for (i = 0; (c = strsep(&template_fmt_ptr, "|")) != NULL && | ||
| 133 | i < template_num_fields; i++) { | ||
| 134 | struct ima_template_field *f = lookup_template_field(c); | ||
| 135 | |||
| 136 | if (!f) { | ||
| 137 | result = -ENOENT; | ||
| 138 | goto out; | ||
| 139 | } | ||
| 140 | (*fields)[i] = f; | ||
| 141 | } | ||
| 142 | *num_fields = i; | ||
| 143 | out: | ||
| 144 | if (result < 0) { | ||
| 145 | kfree(*fields); | ||
| 146 | *fields = NULL; | ||
| 147 | } | ||
| 148 | kfree(template_fmt_copy); | ||
| 149 | return result; | ||
| 150 | } | ||
| 151 | |||
| 152 | static int init_defined_templates(void) | ||
| 153 | { | ||
| 154 | int i = 0; | ||
| 155 | int result = 0; | ||
| 156 | |||
| 157 | /* Init defined templates. */ | ||
| 158 | for (i = 0; i < ARRAY_SIZE(defined_templates); i++) { | ||
| 159 | struct ima_template_desc *template = &defined_templates[i]; | ||
| 160 | |||
| 161 | result = template_desc_init_fields(template->fmt, | ||
| 162 | &(template->fields), | ||
| 163 | &(template->num_fields)); | ||
| 164 | if (result < 0) | ||
| 165 | return result; | ||
| 166 | } | ||
| 167 | return result; | ||
| 168 | } | ||
| 169 | |||
| 170 | struct ima_template_desc *ima_template_desc_current(void) | ||
| 171 | { | ||
| 172 | if (!ima_template) | ||
| 173 | ima_template = | ||
| 174 | lookup_template_desc(CONFIG_IMA_DEFAULT_TEMPLATE); | ||
| 175 | return ima_template; | ||
| 176 | } | ||
| 177 | |||
| 178 | int ima_init_template(void) | ||
| 179 | { | ||
| 180 | int result; | ||
| 181 | |||
| 182 | result = init_defined_templates(); | ||
| 183 | if (result < 0) | ||
| 184 | return result; | ||
| 185 | |||
| 186 | return 0; | ||
| 187 | } | ||
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c new file mode 100644 index 000000000000..c38adcc910fb --- /dev/null +++ b/security/integrity/ima/ima_template_lib.c | |||
| @@ -0,0 +1,351 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2013 Politecnico di Torino, Italy | ||
| 3 | * TORSEC group -- http://security.polito.it | ||
| 4 | * | ||
| 5 | * Author: Roberto Sassu <roberto.sassu@polito.it> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License as | ||
| 9 | * published by the Free Software Foundation, version 2 of the | ||
| 10 | * License. | ||
| 11 | * | ||
| 12 | * File: ima_template_lib.c | ||
| 13 | * Library of supported template fields. | ||
| 14 | */ | ||
| 15 | #include <crypto/hash_info.h> | ||
| 16 | |||
| 17 | #include "ima_template_lib.h" | ||
| 18 | |||
| 19 | static bool ima_template_hash_algo_allowed(u8 algo) | ||
| 20 | { | ||
| 21 | if (algo == HASH_ALGO_SHA1 || algo == HASH_ALGO_MD5) | ||
| 22 | return true; | ||
| 23 | |||
| 24 | return false; | ||
| 25 | } | ||
| 26 | |||
| 27 | enum data_formats { | ||
| 28 | DATA_FMT_DIGEST = 0, | ||
| 29 | DATA_FMT_DIGEST_WITH_ALGO, | ||
| 30 | DATA_FMT_EVENT_NAME, | ||
| 31 | DATA_FMT_STRING, | ||
| 32 | DATA_FMT_HEX | ||
| 33 | }; | ||
| 34 | |||
| 35 | static int ima_write_template_field_data(const void *data, const u32 datalen, | ||
| 36 | enum data_formats datafmt, | ||
| 37 | struct ima_field_data *field_data) | ||
| 38 | { | ||
| 39 | u8 *buf, *buf_ptr; | ||
| 40 | u32 buflen; | ||
| 41 | |||
| 42 | switch (datafmt) { | ||
| 43 | case DATA_FMT_EVENT_NAME: | ||
| 44 | buflen = IMA_EVENT_NAME_LEN_MAX + 1; | ||
| 45 | break; | ||
| 46 | case DATA_FMT_STRING: | ||
| 47 | buflen = datalen + 1; | ||
| 48 | break; | ||
| 49 | default: | ||
| 50 | buflen = datalen; | ||
| 51 | } | ||
| 52 | |||
| 53 | buf = kzalloc(buflen, GFP_KERNEL); | ||
| 54 | if (!buf) | ||
| 55 | return -ENOMEM; | ||
| 56 | |||
| 57 | memcpy(buf, data, datalen); | ||
| 58 | |||
| 59 | /* | ||
| 60 | * Replace all space characters with underscore for event names and | ||
| 61 | * strings. This avoid that, during the parsing of a measurements list, | ||
| 62 | * filenames with spaces or that end with the suffix ' (deleted)' are | ||
| 63 | * split into multiple template fields (the space is the delimitator | ||
| 64 | * character for measurements lists in ASCII format). | ||
| 65 | */ | ||
| 66 | if (datafmt == DATA_FMT_EVENT_NAME || datafmt == DATA_FMT_STRING) { | ||
| 67 | for (buf_ptr = buf; buf_ptr - buf < datalen; buf_ptr++) | ||
| 68 | if (*buf_ptr == ' ') | ||
| 69 | *buf_ptr = '_'; | ||
| 70 | } | ||
| 71 | |||
| 72 | field_data->data = buf; | ||
| 73 | field_data->len = buflen; | ||
| 74 | return 0; | ||
| 75 | } | ||
| 76 | |||
| 77 | static void ima_show_template_data_ascii(struct seq_file *m, | ||
| 78 | enum ima_show_type show, | ||
| 79 | enum data_formats datafmt, | ||
| 80 | struct ima_field_data *field_data) | ||
| 81 | { | ||
| 82 | u8 *buf_ptr = field_data->data, buflen = field_data->len; | ||
| 83 | |||
| 84 | switch (datafmt) { | ||
| 85 | case DATA_FMT_DIGEST_WITH_ALGO: | ||
| 86 | buf_ptr = strnchr(field_data->data, buflen, ':'); | ||
| 87 | if (buf_ptr != field_data->data) | ||
| 88 | seq_printf(m, "%s", field_data->data); | ||
| 89 | |||
| 90 | /* skip ':' and '\0' */ | ||
| 91 | buf_ptr += 2; | ||
| 92 | buflen -= buf_ptr - field_data->data; | ||
| 93 | case DATA_FMT_DIGEST: | ||
| 94 | case DATA_FMT_HEX: | ||
| 95 | if (!buflen) | ||
| 96 | break; | ||
| 97 | ima_print_digest(m, buf_ptr, buflen); | ||
| 98 | break; | ||
| 99 | case DATA_FMT_STRING: | ||
| 100 | seq_printf(m, "%s", buf_ptr); | ||
| 101 | break; | ||
| 102 | default: | ||
| 103 | break; | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | static void ima_show_template_data_binary(struct seq_file *m, | ||
| 108 | enum ima_show_type show, | ||
| 109 | enum data_formats datafmt, | ||
| 110 | struct ima_field_data *field_data) | ||
| 111 | { | ||
| 112 | if (show != IMA_SHOW_BINARY_NO_FIELD_LEN) | ||
| 113 | ima_putc(m, &field_data->len, sizeof(u32)); | ||
| 114 | |||
| 115 | if (!field_data->len) | ||
| 116 | return; | ||
| 117 | |||
| 118 | ima_putc(m, field_data->data, field_data->len); | ||
| 119 | } | ||
| 120 | |||
| 121 | static void ima_show_template_field_data(struct seq_file *m, | ||
| 122 | enum ima_show_type show, | ||
| 123 | enum data_formats datafmt, | ||
| 124 | struct ima_field_data *field_data) | ||
| 125 | { | ||
| 126 | switch (show) { | ||
| 127 | case IMA_SHOW_ASCII: | ||
| 128 | ima_show_template_data_ascii(m, show, datafmt, field_data); | ||
| 129 | break; | ||
| 130 | case IMA_SHOW_BINARY: | ||
| 131 | case IMA_SHOW_BINARY_NO_FIELD_LEN: | ||
| 132 | ima_show_template_data_binary(m, show, datafmt, field_data); | ||
| 133 | break; | ||
| 134 | default: | ||
| 135 | break; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | void ima_show_template_digest(struct seq_file *m, enum ima_show_type show, | ||
| 140 | struct ima_field_data *field_data) | ||
| 141 | { | ||
| 142 | ima_show_template_field_data(m, show, DATA_FMT_DIGEST, field_data); | ||
| 143 | } | ||
| 144 | |||
| 145 | void ima_show_template_digest_ng(struct seq_file *m, enum ima_show_type show, | ||
| 146 | struct ima_field_data *field_data) | ||
| 147 | { | ||
| 148 | ima_show_template_field_data(m, show, DATA_FMT_DIGEST_WITH_ALGO, | ||
| 149 | field_data); | ||
| 150 | } | ||
| 151 | |||
| 152 | void ima_show_template_string(struct seq_file *m, enum ima_show_type show, | ||
| 153 | struct ima_field_data *field_data) | ||
| 154 | { | ||
| 155 | ima_show_template_field_data(m, show, DATA_FMT_STRING, field_data); | ||
| 156 | } | ||
| 157 | |||
| 158 | void ima_show_template_sig(struct seq_file *m, enum ima_show_type show, | ||
| 159 | struct ima_field_data *field_data) | ||
| 160 | { | ||
| 161 | ima_show_template_field_data(m, show, DATA_FMT_HEX, field_data); | ||
| 162 | } | ||
| 163 | |||
| 164 | static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo, | ||
| 165 | struct ima_field_data *field_data, | ||
| 166 | bool size_limit) | ||
| 167 | { | ||
| 168 | /* | ||
| 169 | * digest formats: | ||
| 170 | * - DATA_FMT_DIGEST: digest | ||
| 171 | * - DATA_FMT_DIGEST_WITH_ALGO: [<hash algo>] + ':' + '\0' + digest, | ||
| 172 | * where <hash algo> is provided if the hash algoritm is not | ||
| 173 | * SHA1 or MD5 | ||
| 174 | */ | ||
| 175 | u8 buffer[CRYPTO_MAX_ALG_NAME + 2 + IMA_MAX_DIGEST_SIZE] = { 0 }; | ||
| 176 | enum data_formats fmt = DATA_FMT_DIGEST; | ||
| 177 | u32 offset = 0; | ||
| 178 | |||
| 179 | if (!size_limit) { | ||
| 180 | fmt = DATA_FMT_DIGEST_WITH_ALGO; | ||
| 181 | if (hash_algo < HASH_ALGO__LAST) | ||
| 182 | offset += snprintf(buffer, CRYPTO_MAX_ALG_NAME + 1, | ||
| 183 | "%s", hash_algo_name[hash_algo]); | ||
| 184 | buffer[offset] = ':'; | ||
| 185 | offset += 2; | ||
| 186 | } | ||
| 187 | |||
| 188 | if (digest) | ||
| 189 | memcpy(buffer + offset, digest, digestsize); | ||
| 190 | else | ||
| 191 | /* | ||
| 192 | * If digest is NULL, the event being recorded is a violation. | ||
| 193 | * Make room for the digest by increasing the offset of | ||
| 194 | * IMA_DIGEST_SIZE. | ||
| 195 | */ | ||
| 196 | offset += IMA_DIGEST_SIZE; | ||
| 197 | |||
| 198 | return ima_write_template_field_data(buffer, offset + digestsize, | ||
| 199 | fmt, field_data); | ||
| 200 | } | ||
| 201 | |||
| 202 | /* | ||
| 203 | * This function writes the digest of an event (with size limit). | ||
| 204 | */ | ||
| 205 | int ima_eventdigest_init(struct integrity_iint_cache *iint, struct file *file, | ||
| 206 | const unsigned char *filename, | ||
| 207 | struct evm_ima_xattr_data *xattr_value, int xattr_len, | ||
| 208 | struct ima_field_data *field_data) | ||
| 209 | { | ||
| 210 | struct { | ||
| 211 | struct ima_digest_data hdr; | ||
| 212 | char digest[IMA_MAX_DIGEST_SIZE]; | ||
| 213 | } hash; | ||
| 214 | u8 *cur_digest = NULL; | ||
| 215 | u32 cur_digestsize = 0; | ||
| 216 | struct inode *inode; | ||
| 217 | int result; | ||
| 218 | |||
| 219 | memset(&hash, 0, sizeof(hash)); | ||
| 220 | |||
| 221 | if (!iint) /* recording a violation. */ | ||
| 222 | goto out; | ||
| 223 | |||
| 224 | if (ima_template_hash_algo_allowed(iint->ima_hash->algo)) { | ||
| 225 | cur_digest = iint->ima_hash->digest; | ||
| 226 | cur_digestsize = iint->ima_hash->length; | ||
| 227 | goto out; | ||
| 228 | } | ||
| 229 | |||
| 230 | if (!file) /* missing info to re-calculate the digest */ | ||
| 231 | return -EINVAL; | ||
| 232 | |||
| 233 | inode = file_inode(file); | ||
| 234 | hash.hdr.algo = ima_template_hash_algo_allowed(ima_hash_algo) ? | ||
| 235 | ima_hash_algo : HASH_ALGO_SHA1; | ||
| 236 | result = ima_calc_file_hash(file, &hash.hdr); | ||
| 237 | if (result) { | ||
| 238 | integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, | ||
| 239 | filename, "collect_data", | ||
| 240 | "failed", result, 0); | ||
| 241 | return result; | ||
| 242 | } | ||
| 243 | cur_digest = hash.hdr.digest; | ||
| 244 | cur_digestsize = hash.hdr.length; | ||
| 245 | out: | ||
| 246 | return ima_eventdigest_init_common(cur_digest, cur_digestsize, -1, | ||
| 247 | field_data, true); | ||
| 248 | } | ||
| 249 | |||
| 250 | /* | ||
| 251 | * This function writes the digest of an event (without size limit). | ||
| 252 | */ | ||
| 253 | int ima_eventdigest_ng_init(struct integrity_iint_cache *iint, | ||
| 254 | struct file *file, const unsigned char *filename, | ||
| 255 | struct evm_ima_xattr_data *xattr_value, | ||
| 256 | int xattr_len, struct ima_field_data *field_data) | ||
| 257 | { | ||
| 258 | u8 *cur_digest = NULL, hash_algo = HASH_ALGO__LAST; | ||
| 259 | u32 cur_digestsize = 0; | ||
| 260 | |||
| 261 | /* If iint is NULL, we are recording a violation. */ | ||
| 262 | if (!iint) | ||
| 263 | goto out; | ||
| 264 | |||
| 265 | cur_digest = iint->ima_hash->digest; | ||
| 266 | cur_digestsize = iint->ima_hash->length; | ||
| 267 | |||
| 268 | hash_algo = iint->ima_hash->algo; | ||
| 269 | out: | ||
| 270 | return ima_eventdigest_init_common(cur_digest, cur_digestsize, | ||
| 271 | hash_algo, field_data, false); | ||
| 272 | } | ||
| 273 | |||
| 274 | static int ima_eventname_init_common(struct integrity_iint_cache *iint, | ||
| 275 | struct file *file, | ||
| 276 | const unsigned char *filename, | ||
| 277 | struct ima_field_data *field_data, | ||
| 278 | bool size_limit) | ||
| 279 | { | ||
| 280 | const char *cur_filename = NULL; | ||
| 281 | u32 cur_filename_len = 0; | ||
| 282 | enum data_formats fmt = size_limit ? | ||
| 283 | DATA_FMT_EVENT_NAME : DATA_FMT_STRING; | ||
| 284 | |||
| 285 | BUG_ON(filename == NULL && file == NULL); | ||
| 286 | |||
| 287 | if (filename) { | ||
| 288 | cur_filename = filename; | ||
| 289 | cur_filename_len = strlen(filename); | ||
| 290 | |||
| 291 | if (!size_limit || cur_filename_len <= IMA_EVENT_NAME_LEN_MAX) | ||
| 292 | goto out; | ||
| 293 | } | ||
| 294 | |||
| 295 | if (file) { | ||
| 296 | cur_filename = file->f_dentry->d_name.name; | ||
| 297 | cur_filename_len = strlen(cur_filename); | ||
| 298 | } else | ||
| 299 | /* | ||
| 300 | * Truncate filename if the latter is too long and | ||
| 301 | * the file descriptor is not available. | ||
| 302 | */ | ||
| 303 | cur_filename_len = IMA_EVENT_NAME_LEN_MAX; | ||
| 304 | out: | ||
| 305 | return ima_write_template_field_data(cur_filename, cur_filename_len, | ||
| 306 | fmt, field_data); | ||
| 307 | } | ||
| 308 | |||
| 309 | /* | ||
| 310 | * This function writes the name of an event (with size limit). | ||
| 311 | */ | ||
| 312 | int ima_eventname_init(struct integrity_iint_cache *iint, struct file *file, | ||
| 313 | const unsigned char *filename, | ||
| 314 | struct evm_ima_xattr_data *xattr_value, int xattr_len, | ||
| 315 | struct ima_field_data *field_data) | ||
| 316 | { | ||
| 317 | return ima_eventname_init_common(iint, file, filename, | ||
| 318 | field_data, true); | ||
| 319 | } | ||
| 320 | |||
| 321 | /* | ||
| 322 | * This function writes the name of an event (without size limit). | ||
| 323 | */ | ||
| 324 | int ima_eventname_ng_init(struct integrity_iint_cache *iint, struct file *file, | ||
| 325 | const unsigned char *filename, | ||
| 326 | struct evm_ima_xattr_data *xattr_value, int xattr_len, | ||
| 327 | struct ima_field_data *field_data) | ||
| 328 | { | ||
| 329 | return ima_eventname_init_common(iint, file, filename, | ||
| 330 | field_data, false); | ||
| 331 | } | ||
| 332 | |||
| 333 | /* | ||
| 334 | * ima_eventsig_init - include the file signature as part of the template data | ||
| 335 | */ | ||
| 336 | int ima_eventsig_init(struct integrity_iint_cache *iint, struct file *file, | ||
| 337 | const unsigned char *filename, | ||
| 338 | struct evm_ima_xattr_data *xattr_value, int xattr_len, | ||
| 339 | struct ima_field_data *field_data) | ||
| 340 | { | ||
| 341 | enum data_formats fmt = DATA_FMT_HEX; | ||
| 342 | int rc = 0; | ||
| 343 | |||
| 344 | if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG)) | ||
| 345 | goto out; | ||
| 346 | |||
| 347 | rc = ima_write_template_field_data(xattr_value, xattr_len, fmt, | ||
| 348 | field_data); | ||
| 349 | out: | ||
| 350 | return rc; | ||
| 351 | } | ||
diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h new file mode 100644 index 000000000000..63f6b52cb1c2 --- /dev/null +++ b/security/integrity/ima/ima_template_lib.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2013 Politecnico di Torino, Italy | ||
| 3 | * TORSEC group -- http://security.polito.it | ||
| 4 | * | ||
| 5 | * Author: Roberto Sassu <roberto.sassu@polito.it> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License as | ||
| 9 | * published by the Free Software Foundation, version 2 of the | ||
| 10 | * License. | ||
| 11 | * | ||
| 12 | * File: ima_template_lib.h | ||
| 13 | * Header for the library of supported template fields. | ||
| 14 | */ | ||
| 15 | #ifndef __LINUX_IMA_TEMPLATE_LIB_H | ||
| 16 | #define __LINUX_IMA_TEMPLATE_LIB_H | ||
| 17 | |||
| 18 | #include <linux/seq_file.h> | ||
| 19 | #include "ima.h" | ||
| 20 | |||
| 21 | void ima_show_template_digest(struct seq_file *m, enum ima_show_type show, | ||
| 22 | struct ima_field_data *field_data); | ||
| 23 | void ima_show_template_digest_ng(struct seq_file *m, enum ima_show_type show, | ||
| 24 | struct ima_field_data *field_data); | ||
| 25 | void ima_show_template_string(struct seq_file *m, enum ima_show_type show, | ||
| 26 | struct ima_field_data *field_data); | ||
| 27 | void ima_show_template_sig(struct seq_file *m, enum ima_show_type show, | ||
| 28 | struct ima_field_data *field_data); | ||
| 29 | int ima_eventdigest_init(struct integrity_iint_cache *iint, struct file *file, | ||
| 30 | const unsigned char *filename, | ||
| 31 | struct evm_ima_xattr_data *xattr_value, int xattr_len, | ||
| 32 | struct ima_field_data *field_data); | ||
| 33 | int ima_eventname_init(struct integrity_iint_cache *iint, struct file *file, | ||
| 34 | const unsigned char *filename, | ||
| 35 | struct evm_ima_xattr_data *xattr_value, int xattr_len, | ||
| 36 | struct ima_field_data *field_data); | ||
| 37 | int ima_eventdigest_ng_init(struct integrity_iint_cache *iint, | ||
| 38 | struct file *file, const unsigned char *filename, | ||
| 39 | struct evm_ima_xattr_data *xattr_value, | ||
| 40 | int xattr_len, struct ima_field_data *field_data); | ||
| 41 | int ima_eventname_ng_init(struct integrity_iint_cache *iint, struct file *file, | ||
| 42 | const unsigned char *filename, | ||
| 43 | struct evm_ima_xattr_data *xattr_value, int xattr_len, | ||
| 44 | struct ima_field_data *field_data); | ||
| 45 | int ima_eventsig_init(struct integrity_iint_cache *iint, struct file *file, | ||
| 46 | const unsigned char *filename, | ||
| 47 | struct evm_ima_xattr_data *xattr_value, int xattr_len, | ||
| 48 | struct ima_field_data *field_data); | ||
| 49 | #endif /* __LINUX_IMA_TEMPLATE_LIB_H */ | ||
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index c42fb7a70dee..2fb5e53e927f 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h | |||
| @@ -54,25 +54,57 @@ enum evm_ima_xattr_type { | |||
| 54 | IMA_XATTR_DIGEST = 0x01, | 54 | IMA_XATTR_DIGEST = 0x01, |
| 55 | EVM_XATTR_HMAC, | 55 | EVM_XATTR_HMAC, |
| 56 | EVM_IMA_XATTR_DIGSIG, | 56 | EVM_IMA_XATTR_DIGSIG, |
| 57 | IMA_XATTR_DIGEST_NG, | ||
| 57 | }; | 58 | }; |
| 58 | 59 | ||
| 59 | struct evm_ima_xattr_data { | 60 | struct evm_ima_xattr_data { |
| 60 | u8 type; | 61 | u8 type; |
| 61 | u8 digest[SHA1_DIGEST_SIZE]; | 62 | u8 digest[SHA1_DIGEST_SIZE]; |
| 62 | } __attribute__((packed)); | 63 | } __packed; |
| 64 | |||
| 65 | #define IMA_MAX_DIGEST_SIZE 64 | ||
| 66 | |||
| 67 | struct ima_digest_data { | ||
| 68 | u8 algo; | ||
| 69 | u8 length; | ||
| 70 | union { | ||
| 71 | struct { | ||
| 72 | u8 unused; | ||
| 73 | u8 type; | ||
| 74 | } sha1; | ||
| 75 | struct { | ||
| 76 | u8 type; | ||
| 77 | u8 algo; | ||
| 78 | } ng; | ||
| 79 | u8 data[2]; | ||
| 80 | } xattr; | ||
| 81 | u8 digest[0]; | ||
| 82 | } __packed; | ||
| 83 | |||
| 84 | /* | ||
| 85 | * signature format v2 - for using with asymmetric keys | ||
| 86 | */ | ||
| 87 | struct signature_v2_hdr { | ||
| 88 | uint8_t type; /* xattr type */ | ||
| 89 | uint8_t version; /* signature format version */ | ||
| 90 | uint8_t hash_algo; /* Digest algorithm [enum pkey_hash_algo] */ | ||
| 91 | uint32_t keyid; /* IMA key identifier - not X509/PGP specific */ | ||
| 92 | uint16_t sig_size; /* signature size */ | ||
| 93 | uint8_t sig[0]; /* signature payload */ | ||
| 94 | } __packed; | ||
| 63 | 95 | ||
| 64 | /* integrity data associated with an inode */ | 96 | /* integrity data associated with an inode */ |
| 65 | struct integrity_iint_cache { | 97 | struct integrity_iint_cache { |
| 66 | struct rb_node rb_node; /* rooted in integrity_iint_tree */ | 98 | struct rb_node rb_node; /* rooted in integrity_iint_tree */ |
| 67 | struct inode *inode; /* back pointer to inode in question */ | 99 | struct inode *inode; /* back pointer to inode in question */ |
| 68 | u64 version; /* track inode changes */ | 100 | u64 version; /* track inode changes */ |
| 69 | unsigned long flags; | 101 | unsigned long flags; |
| 70 | struct evm_ima_xattr_data ima_xattr; | ||
| 71 | enum integrity_status ima_file_status:4; | 102 | enum integrity_status ima_file_status:4; |
| 72 | enum integrity_status ima_mmap_status:4; | 103 | enum integrity_status ima_mmap_status:4; |
| 73 | enum integrity_status ima_bprm_status:4; | 104 | enum integrity_status ima_bprm_status:4; |
| 74 | enum integrity_status ima_module_status:4; | 105 | enum integrity_status ima_module_status:4; |
| 75 | enum integrity_status evm_status:4; | 106 | enum integrity_status evm_status:4; |
| 107 | struct ima_digest_data *ima_hash; | ||
| 76 | }; | 108 | }; |
| 77 | 109 | ||
| 78 | /* rbtree tree calls to lookup, insert, delete | 110 | /* rbtree tree calls to lookup, insert, delete |
| @@ -89,7 +121,7 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode); | |||
| 89 | #ifdef CONFIG_INTEGRITY_SIGNATURE | 121 | #ifdef CONFIG_INTEGRITY_SIGNATURE |
| 90 | 122 | ||
| 91 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, | 123 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, |
| 92 | const char *digest, int digestlen); | 124 | const char *digest, int digestlen); |
| 93 | 125 | ||
| 94 | #else | 126 | #else |
| 95 | 127 | ||
