diff options
Diffstat (limited to 'security/integrity/ima')
-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 |
14 files changed, 1185 insertions, 164 deletions
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 */ | ||