Commit a71dc65d30a472409f05d247f4eab91b14acf2f5
Committed by
Mimi Zohar
1 parent
4d7aeee73f
Exists in
master
and in
16 other branches
ima: switch to new template management mechanism
This patch performs the switch to the new template mechanism by modifying the functions ima_alloc_init_template(), ima_measurements_show() and ima_ascii_measurements_show(). The old function ima_template_show() was removed as it is no longer needed. Also, if the template descriptor used to generate a measurement entry is not 'ima', the whole length of field data stored for an entry is provided before the data itself through the binary_runtime_measurement interface. Changelog: - unnecessary to use strncmp() (Mimi Zohar) - create new variable 'field' in ima_alloc_init_template() (Roberto Sassu) - use GFP_NOFS flag in ima_alloc_init_template() (Roberto Sassu) - new variable 'num_fields' in ima_store_template() (Roberto Sassu, proposed by Mimi Zohar) - rename ima_calc_buffer_hash/template_hash() to ima_calc_field_array_hash(), something more generic (Mimi, requested by Dmitry) - sparse error fix - Fengguang Wu - fix lindent warnings - always include the field length in the template data length - include the template field length variable size in the template data length - include both the template field data and field length in the template digest calculation. Simplifies verifying the template digest. (Mimi) Signed-off-by: Roberto Sassu <roberto.sassu@polito.it> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Showing 5 changed files with 107 additions and 97 deletions Side-by-side Diff
security/integrity/ima/ima.h
... | ... | @@ -72,17 +72,11 @@ |
72 | 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 | 75 | struct ima_template_entry { |
82 | 76 | u8 digest[TPM_DIGEST_SIZE]; /* sha1 or md5 measurement hash */ |
83 | - const char *template_name; | |
84 | - int template_len; | |
85 | - struct ima_template_data template; | |
77 | + struct ima_template_desc *template_desc; /* template descriptor */ | |
78 | + u32 template_data_len; | |
79 | + struct ima_field_data template_data[0]; /* template related data */ | |
86 | 80 | }; |
87 | 81 | |
88 | 82 | struct ima_queue_entry { |
89 | 83 | |
... | ... | @@ -102,14 +96,16 @@ |
102 | 96 | const char *op, struct inode *inode, |
103 | 97 | const unsigned char *filename); |
104 | 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, | |
106 | - struct ima_digest_data *hash); | |
99 | +int ima_calc_field_array_hash(struct ima_field_data *field_data, int num_fields, | |
100 | + struct ima_digest_data *hash); | |
107 | 101 | int __init ima_calc_boot_aggregate(struct ima_digest_data *hash); |
108 | 102 | void ima_add_violation(struct file *file, const unsigned char *filename, |
109 | 103 | const char *op, const char *cause); |
110 | 104 | int ima_init_crypto(void); |
111 | 105 | void ima_putc(struct seq_file *m, void *data, int datalen); |
112 | 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 | 110 | int ima_init_template(void); |
115 | 111 | |
... | ... | @@ -146,7 +142,6 @@ |
146 | 142 | struct ima_template_entry **entry); |
147 | 143 | int ima_store_template(struct ima_template_entry *entry, int violation, |
148 | 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 | 145 | const char *ima_d_path(struct path *path, char **pathbuf); |
151 | 146 | |
152 | 147 | /* rbtree tree calls to lookup, insert, delete |
security/integrity/ima/ima_api.c
... | ... | @@ -21,8 +21,6 @@ |
21 | 21 | #include <crypto/hash_info.h> |
22 | 22 | #include "ima.h" |
23 | 23 | |
24 | -static const char *IMA_TEMPLATE_NAME = "ima"; | |
25 | - | |
26 | 24 | /* |
27 | 25 | * ima_alloc_init_template - create and initialize a new template entry |
28 | 26 | */ |
29 | 27 | |
30 | 28 | |
31 | 29 | |
32 | 30 | |
33 | 31 | |
... | ... | @@ -30,52 +28,32 @@ |
30 | 28 | struct file *file, const unsigned char *filename, |
31 | 29 | struct ima_template_entry **entry) |
32 | 30 | { |
33 | - struct ima_template_entry *e; | |
34 | - int result = 0; | |
31 | + struct ima_template_desc *template_desc = ima_template_desc_current(); | |
32 | + int i, result = 0; | |
35 | 33 | |
36 | - e = kzalloc(sizeof(**entry), GFP_NOFS); | |
37 | - if (!e) | |
34 | + *entry = kzalloc(sizeof(**entry) + template_desc->num_fields * | |
35 | + sizeof(struct ima_field_data), GFP_NOFS); | |
36 | + if (!*entry) | |
38 | 37 | return -ENOMEM; |
39 | 38 | |
40 | - memset(&(e)->template, 0, sizeof(e->template)); | |
41 | - if (!iint) /* IMA measurement violation entry */ | |
42 | - goto out; | |
39 | + for (i = 0; i < template_desc->num_fields; i++) { | |
40 | + struct ima_template_field *field = template_desc->fields[i]; | |
41 | + u32 len; | |
43 | 42 | |
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; | |
43 | + result = field->field_init(iint, file, filename, | |
44 | + &((*entry)->template_data[i])); | |
45 | + if (result != 0) | |
46 | + goto out; | |
50 | 47 | |
51 | - if (!file) { | |
52 | - result = -EINVAL; | |
53 | - goto out_free; | |
54 | - } | |
55 | - | |
56 | - inode = file_inode(file); | |
57 | - hash.hdr.algo = ima_hash_algo; | |
58 | - hash.hdr.length = SHA1_DIGEST_SIZE; | |
59 | - result = ima_calc_file_hash(file, &hash.hdr); | |
60 | - if (result) { | |
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; | |
48 | + len = (*entry)->template_data[i].len; | |
49 | + (*entry)->template_data_len += sizeof(len); | |
50 | + (*entry)->template_data_len += len; | |
51 | + } | |
52 | + (*entry)->template_desc = template_desc; | |
76 | 53 | return 0; |
77 | -out_free: | |
78 | - kfree(e); | |
54 | +out: | |
55 | + kfree(*entry); | |
56 | + *entry = NULL; | |
79 | 57 | return result; |
80 | 58 | } |
81 | 59 | |
82 | 60 | |
83 | 61 | |
84 | 62 | |
85 | 63 | |
... | ... | @@ -101,24 +79,23 @@ |
101 | 79 | { |
102 | 80 | const char *op = "add_template_measure"; |
103 | 81 | const char *audit_cause = "hashing_error"; |
82 | + char *template_name = entry->template_desc->name; | |
104 | 83 | int result; |
105 | 84 | struct { |
106 | 85 | struct ima_digest_data hdr; |
107 | 86 | char digest[TPM_DIGEST_SIZE]; |
108 | 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 | 89 | if (!violation) { |
90 | + int num_fields = entry->template_desc->num_fields; | |
91 | + | |
115 | 92 | /* this function uses default algo */ |
116 | 93 | hash.hdr.algo = HASH_ALGO_SHA1; |
117 | - result = ima_calc_buffer_hash(&entry->template, | |
118 | - entry->template_len, &hash.hdr); | |
94 | + result = ima_calc_field_array_hash(&entry->template_data[0], | |
95 | + num_fields, &hash.hdr); | |
119 | 96 | if (result < 0) { |
120 | 97 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, |
121 | - entry->template_name, op, | |
98 | + template_name, op, | |
122 | 99 | audit_cause, result, 0); |
123 | 100 | return result; |
124 | 101 | } |
security/integrity/ima/ima_crypto.c
... | ... | @@ -137,26 +137,46 @@ |
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, | |
143 | - struct ima_digest_data *hash, | |
144 | - struct crypto_shash *tfm) | |
142 | +static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, | |
143 | + int num_fields, | |
144 | + struct ima_digest_data *hash, | |
145 | + struct crypto_shash *tfm) | |
145 | 146 | { |
146 | 147 | struct { |
147 | 148 | struct shash_desc shash; |
148 | 149 | char ctx[crypto_shash_descsize(tfm)]; |
149 | 150 | } desc; |
151 | + int rc, i; | |
150 | 152 | |
151 | 153 | desc.shash.tfm = tfm; |
152 | 154 | desc.shash.flags = 0; |
153 | 155 | |
154 | 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 | 181 | struct crypto_shash *tfm; |
162 | 182 | int rc; |
... | ... | @@ -165,7 +185,7 @@ |
165 | 185 | if (IS_ERR(tfm)) |
166 | 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 | 190 | ima_free_tfm(tfm); |
171 | 191 |
security/integrity/ima/ima_fs.c
... | ... | @@ -110,6 +110,7 @@ |
110 | 110 | * char[20]=template digest |
111 | 111 | * 32bit-le=template name size |
112 | 112 | * char[n]=template name |
113 | + * [eventdata length] | |
113 | 114 | * eventdata[n]=template specific data |
114 | 115 | */ |
115 | 116 | static int ima_measurements_show(struct seq_file *m, void *v) |
... | ... | @@ -119,6 +120,7 @@ |
119 | 120 | struct ima_template_entry *e; |
120 | 121 | int namelen; |
121 | 122 | u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX; |
123 | + int i; | |
122 | 124 | |
123 | 125 | /* get entry */ |
124 | 126 | e = qe->entry; |
125 | 127 | |
126 | 128 | |
... | ... | @@ -136,15 +138,22 @@ |
136 | 138 | ima_putc(m, e->digest, TPM_DIGEST_SIZE); |
137 | 139 | |
138 | 140 | /* 3rd: template name size */ |
139 | - namelen = strlen(e->template_name); | |
141 | + namelen = strlen(e->template_desc->name); | |
140 | 142 | ima_putc(m, &namelen, sizeof namelen); |
141 | 143 | |
142 | 144 | /* 4th: template name */ |
143 | - ima_putc(m, (void *)e->template_name, namelen); | |
145 | + ima_putc(m, e->template_desc->name, namelen); | |
144 | 146 | |
145 | - /* 5th: template specific data */ | |
146 | - ima_template_show(m, (struct ima_template_data *)&e->template, | |
147 | - IMA_SHOW_BINARY); | |
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)); | |
151 | + | |
152 | + /* 6th: template specific data */ | |
153 | + for (i = 0; i < e->template_desc->num_fields; i++) { | |
154 | + e->template_desc->fields[i]->field_show(m, IMA_SHOW_BINARY, | |
155 | + &e->template_data[i]); | |
156 | + } | |
148 | 157 | return 0; |
149 | 158 | } |
150 | 159 | |
151 | 160 | |
... | ... | @@ -175,33 +184,13 @@ |
175 | 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 | 187 | /* print in ascii */ |
200 | 188 | static int ima_ascii_measurements_show(struct seq_file *m, void *v) |
201 | 189 | { |
202 | 190 | /* the list never shrinks, so we don't need a lock here */ |
203 | 191 | struct ima_queue_entry *qe = v; |
204 | 192 | struct ima_template_entry *e; |
193 | + int i; | |
205 | 194 | |
206 | 195 | /* get entry */ |
207 | 196 | e = qe->entry; |
208 | 197 | |
... | ... | @@ -215,11 +204,18 @@ |
215 | 204 | ima_print_digest(m, e->digest, TPM_DIGEST_SIZE); |
216 | 205 | |
217 | 206 | /* 3th: template name */ |
218 | - seq_printf(m, " %s ", e->template_name); | |
207 | + seq_printf(m, " %s", e->template_desc->name); | |
219 | 208 | |
220 | 209 | /* 4th: template specific data */ |
221 | - ima_template_show(m, (struct ima_template_data *)&e->template, | |
222 | - IMA_SHOW_ASCII); | |
210 | + for (i = 0; i < e->template_desc->num_fields; i++) { | |
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 | 219 | return 0; |
224 | 220 | } |
225 | 221 |
security/integrity/ima/ima_template.c
... | ... | @@ -31,6 +31,20 @@ |
31 | 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 | 48 | static struct ima_template_field *lookup_template_field(const char *field_id) |
35 | 49 | { |
36 | 50 | int i; |
... | ... | @@ -108,6 +122,14 @@ |
108 | 122 | return result; |
109 | 123 | } |
110 | 124 | return result; |
125 | +} | |
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; | |
111 | 133 | } |
112 | 134 | |
113 | 135 | int ima_init_template(void) |