diff options
-rw-r--r-- | security/integrity/ima/ima.h | 19 | ||||
-rw-r--r-- | security/integrity/ima/ima_api.c | 75 | ||||
-rw-r--r-- | security/integrity/ima/ima_crypto.c | 34 | ||||
-rw-r--r-- | security/integrity/ima/ima_fs.c | 54 | ||||
-rw-r--r-- | security/integrity/ima/ima_template.c | 22 |
5 files changed, 107 insertions, 97 deletions
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index e1f081d65dbf..72d013e190b1 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
@@ -72,17 +72,11 @@ struct ima_template_desc { | |||
72 | struct ima_template_field **fields; | 72 | struct ima_template_field **fields; |
73 | }; | 73 | }; |
74 | 74 | ||
75 | /* IMA inode template definition */ | ||
76 | struct ima_template_data { | ||
77 | u8 digest[IMA_DIGEST_SIZE]; /* sha1/md5 measurement hash */ | ||
78 | char file_name[IMA_EVENT_NAME_LEN_MAX + 1]; /* name + \0 */ | ||
79 | }; | ||
80 | |||
81 | struct ima_template_entry { | 75 | struct ima_template_entry { |
82 | u8 digest[TPM_DIGEST_SIZE]; /* sha1 or md5 measurement hash */ | 76 | u8 digest[TPM_DIGEST_SIZE]; /* sha1 or md5 measurement hash */ |
83 | const char *template_name; | 77 | struct ima_template_desc *template_desc; /* template descriptor */ |
84 | int template_len; | 78 | u32 template_data_len; |
85 | struct ima_template_data template; | 79 | struct ima_field_data template_data[0]; /* template related data */ |
86 | }; | 80 | }; |
87 | 81 | ||
88 | struct ima_queue_entry { | 82 | struct ima_queue_entry { |
@@ -102,14 +96,16 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, | |||
102 | const char *op, struct inode *inode, | 96 | const char *op, struct inode *inode, |
103 | const unsigned char *filename); | 97 | const unsigned char *filename); |
104 | int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash); | 98 | int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash); |
105 | int ima_calc_buffer_hash(const void *data, int len, | 99 | int ima_calc_field_array_hash(struct ima_field_data *field_data, int num_fields, |
106 | struct ima_digest_data *hash); | 100 | struct ima_digest_data *hash); |
107 | int __init ima_calc_boot_aggregate(struct ima_digest_data *hash); | 101 | int __init ima_calc_boot_aggregate(struct ima_digest_data *hash); |
108 | void ima_add_violation(struct file *file, const unsigned char *filename, | 102 | void ima_add_violation(struct file *file, const unsigned char *filename, |
109 | const char *op, const char *cause); | 103 | const char *op, const char *cause); |
110 | int ima_init_crypto(void); | 104 | int ima_init_crypto(void); |
111 | void ima_putc(struct seq_file *m, void *data, int datalen); | 105 | void ima_putc(struct seq_file *m, void *data, int datalen); |
112 | void ima_print_digest(struct seq_file *m, u8 *digest, int size); | 106 | void ima_print_digest(struct seq_file *m, u8 *digest, int size); |
107 | struct ima_template_desc *ima_template_desc_current(void); | ||
108 | int ima_init_template(void); | ||
113 | 109 | ||
114 | int ima_init_template(void); | 110 | int ima_init_template(void); |
115 | 111 | ||
@@ -146,7 +142,6 @@ int ima_alloc_init_template(struct integrity_iint_cache *iint, | |||
146 | struct ima_template_entry **entry); | 142 | struct ima_template_entry **entry); |
147 | int ima_store_template(struct ima_template_entry *entry, int violation, | 143 | int ima_store_template(struct ima_template_entry *entry, int violation, |
148 | struct inode *inode, const unsigned char *filename); | 144 | struct inode *inode, const unsigned char *filename); |
149 | void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show); | ||
150 | const char *ima_d_path(struct path *path, char **pathbuf); | 145 | const char *ima_d_path(struct path *path, char **pathbuf); |
151 | 146 | ||
152 | /* rbtree tree calls to lookup, insert, delete | 147 | /* rbtree tree calls to lookup, insert, delete |
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 29dd43de823a..baa348179527 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c | |||
@@ -21,8 +21,6 @@ | |||
21 | #include <crypto/hash_info.h> | 21 | #include <crypto/hash_info.h> |
22 | #include "ima.h" | 22 | #include "ima.h" |
23 | 23 | ||
24 | static const char *IMA_TEMPLATE_NAME = "ima"; | ||
25 | |||
26 | /* | 24 | /* |
27 | * ima_alloc_init_template - create and initialize a new template entry | 25 | * ima_alloc_init_template - create and initialize a new template entry |
28 | */ | 26 | */ |
@@ -30,52 +28,32 @@ int ima_alloc_init_template(struct integrity_iint_cache *iint, | |||
30 | struct file *file, const unsigned char *filename, | 28 | struct file *file, const unsigned char *filename, |
31 | struct ima_template_entry **entry) | 29 | struct ima_template_entry **entry) |
32 | { | 30 | { |
33 | struct ima_template_entry *e; | 31 | struct ima_template_desc *template_desc = ima_template_desc_current(); |
34 | int result = 0; | 32 | int i, result = 0; |
35 | 33 | ||
36 | e = kzalloc(sizeof(**entry), GFP_NOFS); | 34 | *entry = kzalloc(sizeof(**entry) + template_desc->num_fields * |
37 | if (!e) | 35 | sizeof(struct ima_field_data), GFP_NOFS); |
36 | if (!*entry) | ||
38 | return -ENOMEM; | 37 | return -ENOMEM; |
39 | 38 | ||
40 | memset(&(e)->template, 0, sizeof(e->template)); | 39 | for (i = 0; i < template_desc->num_fields; i++) { |
41 | if (!iint) /* IMA measurement violation entry */ | 40 | struct ima_template_field *field = template_desc->fields[i]; |
42 | goto out; | 41 | u32 len; |
43 | |||
44 | if (iint->ima_hash->algo != ima_hash_algo) { | ||
45 | struct inode *inode; | ||
46 | struct { | ||
47 | struct ima_digest_data hdr; | ||
48 | char digest[IMA_MAX_DIGEST_SIZE]; | ||
49 | } hash; | ||
50 | 42 | ||
51 | if (!file) { | 43 | result = field->field_init(iint, file, filename, |
52 | result = -EINVAL; | 44 | &((*entry)->template_data[i])); |
53 | goto out_free; | 45 | if (result != 0) |
54 | } | 46 | goto out; |
55 | 47 | ||
56 | inode = file_inode(file); | 48 | len = (*entry)->template_data[i].len; |
57 | hash.hdr.algo = ima_hash_algo; | 49 | (*entry)->template_data_len += sizeof(len); |
58 | hash.hdr.length = SHA1_DIGEST_SIZE; | 50 | (*entry)->template_data_len += len; |
59 | result = ima_calc_file_hash(file, &hash.hdr); | 51 | } |
60 | if (result) { | 52 | (*entry)->template_desc = template_desc; |
61 | integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, | ||
62 | filename, "collect_data", | ||
63 | "failed", result, 0); | ||
64 | goto out_free; | ||
65 | } else | ||
66 | memcpy(e->template.digest, hash.hdr.digest, | ||
67 | hash.hdr.length); | ||
68 | } else | ||
69 | memcpy(e->template.digest, iint->ima_hash->digest, | ||
70 | iint->ima_hash->length); | ||
71 | out: | ||
72 | strcpy(e->template.file_name, | ||
73 | (strlen(filename) > IMA_EVENT_NAME_LEN_MAX && file != NULL) ? | ||
74 | file->f_dentry->d_name.name : filename); | ||
75 | *entry = e; | ||
76 | return 0; | 53 | return 0; |
77 | out_free: | 54 | out: |
78 | kfree(e); | 55 | kfree(*entry); |
56 | *entry = NULL; | ||
79 | return result; | 57 | return result; |
80 | } | 58 | } |
81 | 59 | ||
@@ -101,24 +79,23 @@ int ima_store_template(struct ima_template_entry *entry, | |||
101 | { | 79 | { |
102 | const char *op = "add_template_measure"; | 80 | const char *op = "add_template_measure"; |
103 | const char *audit_cause = "hashing_error"; | 81 | const char *audit_cause = "hashing_error"; |
82 | char *template_name = entry->template_desc->name; | ||
104 | int result; | 83 | int result; |
105 | struct { | 84 | struct { |
106 | struct ima_digest_data hdr; | 85 | struct ima_digest_data hdr; |
107 | char digest[TPM_DIGEST_SIZE]; | 86 | char digest[TPM_DIGEST_SIZE]; |
108 | } hash; | 87 | } hash; |
109 | 88 | ||
110 | memset(entry->digest, 0, sizeof(entry->digest)); | ||
111 | entry->template_name = IMA_TEMPLATE_NAME; | ||
112 | entry->template_len = sizeof(entry->template); | ||
113 | |||
114 | if (!violation) { | 89 | if (!violation) { |
90 | int num_fields = entry->template_desc->num_fields; | ||
91 | |||
115 | /* this function uses default algo */ | 92 | /* this function uses default algo */ |
116 | hash.hdr.algo = HASH_ALGO_SHA1; | 93 | hash.hdr.algo = HASH_ALGO_SHA1; |
117 | result = ima_calc_buffer_hash(&entry->template, | 94 | result = ima_calc_field_array_hash(&entry->template_data[0], |
118 | entry->template_len, &hash.hdr); | 95 | num_fields, &hash.hdr); |
119 | if (result < 0) { | 96 | if (result < 0) { |
120 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, | 97 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, |
121 | entry->template_name, op, | 98 | template_name, op, |
122 | audit_cause, result, 0); | 99 | audit_cause, result, 0); |
123 | return result; | 100 | return result; |
124 | } | 101 | } |
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 22be23f13b3d..676e0292dfec 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c | |||
@@ -137,26 +137,46 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) | |||
137 | } | 137 | } |
138 | 138 | ||
139 | /* | 139 | /* |
140 | * Calculate the hash of a given buffer | 140 | * Calculate the hash of template data |
141 | */ | 141 | */ |
142 | static int ima_calc_buffer_hash_tfm(const void *buf, int len, | 142 | static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, |
143 | struct ima_digest_data *hash, | 143 | int num_fields, |
144 | struct crypto_shash *tfm) | 144 | struct ima_digest_data *hash, |
145 | struct crypto_shash *tfm) | ||
145 | { | 146 | { |
146 | struct { | 147 | struct { |
147 | struct shash_desc shash; | 148 | struct shash_desc shash; |
148 | char ctx[crypto_shash_descsize(tfm)]; | 149 | char ctx[crypto_shash_descsize(tfm)]; |
149 | } desc; | 150 | } desc; |
151 | int rc, i; | ||
150 | 152 | ||
151 | desc.shash.tfm = tfm; | 153 | desc.shash.tfm = tfm; |
152 | desc.shash.flags = 0; | 154 | desc.shash.flags = 0; |
153 | 155 | ||
154 | hash->length = crypto_shash_digestsize(tfm); | 156 | hash->length = crypto_shash_digestsize(tfm); |
155 | 157 | ||
156 | return crypto_shash_digest(&desc.shash, buf, len, hash->digest); | 158 | rc = crypto_shash_init(&desc.shash); |
159 | if (rc != 0) | ||
160 | return rc; | ||
161 | |||
162 | for (i = 0; i < num_fields; i++) { | ||
163 | rc = crypto_shash_update(&desc.shash, | ||
164 | (const u8 *) &field_data[i].len, | ||
165 | sizeof(field_data[i].len)); | ||
166 | rc = crypto_shash_update(&desc.shash, field_data[i].data, | ||
167 | field_data[i].len); | ||
168 | if (rc) | ||
169 | break; | ||
170 | } | ||
171 | |||
172 | if (!rc) | ||
173 | rc = crypto_shash_final(&desc.shash, hash->digest); | ||
174 | |||
175 | return rc; | ||
157 | } | 176 | } |
158 | 177 | ||
159 | int ima_calc_buffer_hash(const void *buf, int len, struct ima_digest_data *hash) | 178 | int ima_calc_field_array_hash(struct ima_field_data *field_data, int num_fields, |
179 | struct ima_digest_data *hash) | ||
160 | { | 180 | { |
161 | struct crypto_shash *tfm; | 181 | struct crypto_shash *tfm; |
162 | int rc; | 182 | int rc; |
@@ -165,7 +185,7 @@ int ima_calc_buffer_hash(const void *buf, int len, struct ima_digest_data *hash) | |||
165 | if (IS_ERR(tfm)) | 185 | if (IS_ERR(tfm)) |
166 | return PTR_ERR(tfm); | 186 | return PTR_ERR(tfm); |
167 | 187 | ||
168 | rc = ima_calc_buffer_hash_tfm(buf, len, hash, tfm); | 188 | rc = ima_calc_field_array_hash_tfm(field_data, num_fields, hash, tfm); |
169 | 189 | ||
170 | ima_free_tfm(tfm); | 190 | ima_free_tfm(tfm); |
171 | 191 | ||
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 414862e1904b..d47a7c86a21d 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c | |||
@@ -110,6 +110,7 @@ void ima_putc(struct seq_file *m, void *data, int datalen) | |||
110 | * char[20]=template digest | 110 | * char[20]=template digest |
111 | * 32bit-le=template name size | 111 | * 32bit-le=template name size |
112 | * char[n]=template name | 112 | * char[n]=template name |
113 | * [eventdata length] | ||
113 | * eventdata[n]=template specific data | 114 | * eventdata[n]=template specific data |
114 | */ | 115 | */ |
115 | static int ima_measurements_show(struct seq_file *m, void *v) | 116 | static int ima_measurements_show(struct seq_file *m, void *v) |
@@ -119,6 +120,7 @@ static int ima_measurements_show(struct seq_file *m, void *v) | |||
119 | struct ima_template_entry *e; | 120 | struct ima_template_entry *e; |
120 | int namelen; | 121 | int namelen; |
121 | u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX; | 122 | u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX; |
123 | int i; | ||
122 | 124 | ||
123 | /* get entry */ | 125 | /* get entry */ |
124 | e = qe->entry; | 126 | e = qe->entry; |
@@ -136,15 +138,22 @@ static int ima_measurements_show(struct seq_file *m, void *v) | |||
136 | ima_putc(m, e->digest, TPM_DIGEST_SIZE); | 138 | ima_putc(m, e->digest, TPM_DIGEST_SIZE); |
137 | 139 | ||
138 | /* 3rd: template name size */ | 140 | /* 3rd: template name size */ |
139 | namelen = strlen(e->template_name); | 141 | namelen = strlen(e->template_desc->name); |
140 | ima_putc(m, &namelen, sizeof namelen); | 142 | ima_putc(m, &namelen, sizeof namelen); |
141 | 143 | ||
142 | /* 4th: template name */ | 144 | /* 4th: template name */ |
143 | ima_putc(m, (void *)e->template_name, namelen); | 145 | ima_putc(m, e->template_desc->name, namelen); |
146 | |||
147 | /* 5th: template length (except for 'ima' template) */ | ||
148 | if (strcmp(e->template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0) | ||
149 | ima_putc(m, &e->template_data_len, | ||
150 | sizeof(e->template_data_len)); | ||
144 | 151 | ||
145 | /* 5th: template specific data */ | 152 | /* 6th: template specific data */ |
146 | ima_template_show(m, (struct ima_template_data *)&e->template, | 153 | for (i = 0; i < e->template_desc->num_fields; i++) { |
147 | IMA_SHOW_BINARY); | 154 | e->template_desc->fields[i]->field_show(m, IMA_SHOW_BINARY, |
155 | &e->template_data[i]); | ||
156 | } | ||
148 | return 0; | 157 | return 0; |
149 | } | 158 | } |
150 | 159 | ||
@@ -175,33 +184,13 @@ void ima_print_digest(struct seq_file *m, u8 *digest, int size) | |||
175 | seq_printf(m, "%02x", *(digest + i)); | 184 | seq_printf(m, "%02x", *(digest + i)); |
176 | } | 185 | } |
177 | 186 | ||
178 | void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show) | ||
179 | { | ||
180 | struct ima_template_data *entry = e; | ||
181 | int namelen; | ||
182 | |||
183 | switch (show) { | ||
184 | case IMA_SHOW_ASCII: | ||
185 | ima_print_digest(m, entry->digest, IMA_DIGEST_SIZE); | ||
186 | seq_printf(m, " %s\n", entry->file_name); | ||
187 | break; | ||
188 | case IMA_SHOW_BINARY: | ||
189 | ima_putc(m, entry->digest, IMA_DIGEST_SIZE); | ||
190 | |||
191 | namelen = strlen(entry->file_name); | ||
192 | ima_putc(m, &namelen, sizeof namelen); | ||
193 | ima_putc(m, entry->file_name, namelen); | ||
194 | default: | ||
195 | break; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | /* print in ascii */ | 187 | /* print in ascii */ |
200 | static int ima_ascii_measurements_show(struct seq_file *m, void *v) | 188 | static int ima_ascii_measurements_show(struct seq_file *m, void *v) |
201 | { | 189 | { |
202 | /* the list never shrinks, so we don't need a lock here */ | 190 | /* the list never shrinks, so we don't need a lock here */ |
203 | struct ima_queue_entry *qe = v; | 191 | struct ima_queue_entry *qe = v; |
204 | struct ima_template_entry *e; | 192 | struct ima_template_entry *e; |
193 | int i; | ||
205 | 194 | ||
206 | /* get entry */ | 195 | /* get entry */ |
207 | e = qe->entry; | 196 | e = qe->entry; |
@@ -215,11 +204,18 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v) | |||
215 | ima_print_digest(m, e->digest, TPM_DIGEST_SIZE); | 204 | ima_print_digest(m, e->digest, TPM_DIGEST_SIZE); |
216 | 205 | ||
217 | /* 3th: template name */ | 206 | /* 3th: template name */ |
218 | seq_printf(m, " %s ", e->template_name); | 207 | seq_printf(m, " %s", e->template_desc->name); |
219 | 208 | ||
220 | /* 4th: template specific data */ | 209 | /* 4th: template specific data */ |
221 | ima_template_show(m, (struct ima_template_data *)&e->template, | 210 | for (i = 0; i < e->template_desc->num_fields; i++) { |
222 | IMA_SHOW_ASCII); | 211 | seq_puts(m, " "); |
212 | if (e->template_data[i].len == 0) | ||
213 | continue; | ||
214 | |||
215 | e->template_desc->fields[i]->field_show(m, IMA_SHOW_ASCII, | ||
216 | &e->template_data[i]); | ||
217 | } | ||
218 | seq_puts(m, "\n"); | ||
223 | return 0; | 219 | return 0; |
224 | } | 220 | } |
225 | 221 | ||
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index bf38d1af3cfd..1c4cf194592c 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c | |||
@@ -31,6 +31,20 @@ static struct ima_template_field supported_fields[] = { | |||
31 | .field_show = ima_show_template_string}, | 31 | .field_show = ima_show_template_string}, |
32 | }; | 32 | }; |
33 | 33 | ||
34 | static struct ima_template_desc *ima_template; | ||
35 | |||
36 | static struct ima_template_desc *lookup_template_desc(const char *name) | ||
37 | { | ||
38 | int i; | ||
39 | |||
40 | for (i = 0; i < ARRAY_SIZE(defined_templates); i++) { | ||
41 | if (strcmp(defined_templates[i].name, name) == 0) | ||
42 | return defined_templates + i; | ||
43 | } | ||
44 | |||
45 | return NULL; | ||
46 | } | ||
47 | |||
34 | static struct ima_template_field *lookup_template_field(const char *field_id) | 48 | static struct ima_template_field *lookup_template_field(const char *field_id) |
35 | { | 49 | { |
36 | int i; | 50 | int i; |
@@ -110,6 +124,14 @@ static int init_defined_templates(void) | |||
110 | return result; | 124 | return result; |
111 | } | 125 | } |
112 | 126 | ||
127 | struct ima_template_desc *ima_template_desc_current(void) | ||
128 | { | ||
129 | if (!ima_template) | ||
130 | ima_template = lookup_template_desc(IMA_TEMPLATE_IMA_NAME); | ||
131 | |||
132 | return ima_template; | ||
133 | } | ||
134 | |||
113 | int ima_init_template(void) | 135 | int ima_init_template(void) |
114 | { | 136 | { |
115 | int result; | 137 | int result; |