diff options
author | Thiago Jung Bauermann <bauerman@linux.ibm.com> | 2019-06-27 22:19:32 -0400 |
---|---|---|
committer | Mimi Zohar <zohar@linux.ibm.com> | 2019-08-05 18:40:25 -0400 |
commit | 3878d505aa718bcc7b1eb4089ab9b9fb27dee957 (patch) | |
tree | 94bf31dc35114d22a2c87906106074cdcb4bd021 | |
parent | 15588227e086ec662d59df144e48af82e3e592f1 (diff) |
ima: Define ima-modsig template
Define new "d-modsig" template field which holds the digest that is
expected to match the one contained in the modsig, and also new "modsig"
template field which holds the appended file signature.
Add a new "ima-modsig" defined template descriptor with the new fields as
well as the ones from the "ima-sig" descriptor.
Change ima_store_measurement() to accept a struct modsig * argument so that
it can be passed along to the templates via struct ima_event_data.
Suggested-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Thiago Jung Bauermann <bauerman@linux.ibm.com>
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
-rw-r--r-- | Documentation/security/IMA-templates.rst | 3 | ||||
-rw-r--r-- | security/integrity/ima/ima.h | 20 | ||||
-rw-r--r-- | security/integrity/ima/ima_api.c | 5 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 2 | ||||
-rw-r--r-- | security/integrity/ima/ima_modsig.c | 19 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 41 | ||||
-rw-r--r-- | security/integrity/ima/ima_template.c | 7 | ||||
-rw-r--r-- | security/integrity/ima/ima_template_lib.c | 64 | ||||
-rw-r--r-- | security/integrity/ima/ima_template_lib.h | 4 |
9 files changed, 159 insertions, 6 deletions
diff --git a/Documentation/security/IMA-templates.rst b/Documentation/security/IMA-templates.rst index 3d1cca287aa4..c5a8432972ef 100644 --- a/Documentation/security/IMA-templates.rst +++ b/Documentation/security/IMA-templates.rst | |||
@@ -68,8 +68,10 @@ descriptors by adding their identifier to the format string | |||
68 | - 'd-ng': the digest of the event, calculated with an arbitrary hash | 68 | - 'd-ng': the digest of the event, calculated with an arbitrary hash |
69 | algorithm (field format: [<hash algo>:]digest, where the digest | 69 | algorithm (field format: [<hash algo>:]digest, where the digest |
70 | prefix is shown only if the hash algorithm is not SHA1 or MD5); | 70 | prefix is shown only if the hash algorithm is not SHA1 or MD5); |
71 | - 'd-modsig': the digest of the event without the appended modsig; | ||
71 | - 'n-ng': the name of the event, without size limitations; | 72 | - 'n-ng': the name of the event, without size limitations; |
72 | - 'sig': the file signature; | 73 | - 'sig': the file signature; |
74 | - 'modsig' the appended file signature; | ||
73 | - 'buf': the buffer data that was used to generate the hash without size limitations; | 75 | - 'buf': the buffer data that was used to generate the hash without size limitations; |
74 | 76 | ||
75 | 77 | ||
@@ -79,6 +81,7 @@ Below, there is the list of defined template descriptors: | |||
79 | - "ima-ng" (default): its format is ``d-ng|n-ng``; | 81 | - "ima-ng" (default): its format is ``d-ng|n-ng``; |
80 | - "ima-sig": its format is ``d-ng|n-ng|sig``; | 82 | - "ima-sig": its format is ``d-ng|n-ng|sig``; |
81 | - "ima-buf": its format is ``d-ng|n-ng|buf``; | 83 | - "ima-buf": its format is ``d-ng|n-ng|buf``; |
84 | - "ima-modsig": its format is ``d-ng|n-ng|sig|d-modsig|modsig``; | ||
82 | 85 | ||
83 | 86 | ||
84 | Use | 87 | Use |
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 0bc764c80327..cfc8b0887776 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
@@ -60,6 +60,7 @@ struct ima_event_data { | |||
60 | const unsigned char *filename; | 60 | const unsigned char *filename; |
61 | struct evm_ima_xattr_data *xattr_value; | 61 | struct evm_ima_xattr_data *xattr_value; |
62 | int xattr_len; | 62 | int xattr_len; |
63 | const struct modsig *modsig; | ||
63 | const char *violation; | 64 | const char *violation; |
64 | const void *buf; | 65 | const void *buf; |
65 | int buf_len; | 66 | int buf_len; |
@@ -211,7 +212,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, | |||
211 | void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, | 212 | void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, |
212 | const unsigned char *filename, | 213 | const unsigned char *filename, |
213 | struct evm_ima_xattr_data *xattr_value, | 214 | struct evm_ima_xattr_data *xattr_value, |
214 | int xattr_len, int pcr, | 215 | int xattr_len, const struct modsig *modsig, int pcr, |
215 | struct ima_template_desc *template_desc); | 216 | struct ima_template_desc *template_desc); |
216 | void ima_audit_measurement(struct integrity_iint_cache *iint, | 217 | void ima_audit_measurement(struct integrity_iint_cache *iint, |
217 | const unsigned char *filename); | 218 | const unsigned char *filename); |
@@ -312,6 +313,10 @@ bool ima_hook_supports_modsig(enum ima_hooks func); | |||
312 | int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len, | 313 | int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len, |
313 | struct modsig **modsig); | 314 | struct modsig **modsig); |
314 | void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size); | 315 | void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size); |
316 | int ima_get_modsig_digest(const struct modsig *modsig, enum hash_algo *algo, | ||
317 | const u8 **digest, u32 *digest_size); | ||
318 | int ima_get_raw_modsig(const struct modsig *modsig, const void **data, | ||
319 | u32 *data_len); | ||
315 | void ima_free_modsig(struct modsig *modsig); | 320 | void ima_free_modsig(struct modsig *modsig); |
316 | #else | 321 | #else |
317 | static inline bool ima_hook_supports_modsig(enum ima_hooks func) | 322 | static inline bool ima_hook_supports_modsig(enum ima_hooks func) |
@@ -330,6 +335,19 @@ static inline void ima_collect_modsig(struct modsig *modsig, const void *buf, | |||
330 | { | 335 | { |
331 | } | 336 | } |
332 | 337 | ||
338 | static inline int ima_get_modsig_digest(const struct modsig *modsig, | ||
339 | enum hash_algo *algo, const u8 **digest, | ||
340 | u32 *digest_size) | ||
341 | { | ||
342 | return -EOPNOTSUPP; | ||
343 | } | ||
344 | |||
345 | static inline int ima_get_raw_modsig(const struct modsig *modsig, | ||
346 | const void **data, u32 *data_len) | ||
347 | { | ||
348 | return -EOPNOTSUPP; | ||
349 | } | ||
350 | |||
333 | static inline void ima_free_modsig(struct modsig *modsig) | 351 | static inline void ima_free_modsig(struct modsig *modsig) |
334 | { | 352 | { |
335 | } | 353 | } |
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index ff8b7fb03ea0..ca930e2ebc2c 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c | |||
@@ -288,7 +288,7 @@ out: | |||
288 | void ima_store_measurement(struct integrity_iint_cache *iint, | 288 | void ima_store_measurement(struct integrity_iint_cache *iint, |
289 | struct file *file, const unsigned char *filename, | 289 | struct file *file, const unsigned char *filename, |
290 | struct evm_ima_xattr_data *xattr_value, | 290 | struct evm_ima_xattr_data *xattr_value, |
291 | int xattr_len, int pcr, | 291 | int xattr_len, const struct modsig *modsig, int pcr, |
292 | struct ima_template_desc *template_desc) | 292 | struct ima_template_desc *template_desc) |
293 | { | 293 | { |
294 | static const char op[] = "add_template_measure"; | 294 | static const char op[] = "add_template_measure"; |
@@ -300,7 +300,8 @@ void ima_store_measurement(struct integrity_iint_cache *iint, | |||
300 | .file = file, | 300 | .file = file, |
301 | .filename = filename, | 301 | .filename = filename, |
302 | .xattr_value = xattr_value, | 302 | .xattr_value = xattr_value, |
303 | .xattr_len = xattr_len }; | 303 | .xattr_len = xattr_len, |
304 | .modsig = modsig }; | ||
304 | int violation = 0; | 305 | int violation = 0; |
305 | 306 | ||
306 | if (iint->measured_pcrs & (0x1 << pcr)) | 307 | if (iint->measured_pcrs & (0x1 << pcr)) |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 7c8d92cf2755..c87645c2c4c0 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -323,7 +323,7 @@ static int process_measurement(struct file *file, const struct cred *cred, | |||
323 | 323 | ||
324 | if (action & IMA_MEASURE) | 324 | if (action & IMA_MEASURE) |
325 | ima_store_measurement(iint, file, pathname, | 325 | ima_store_measurement(iint, file, pathname, |
326 | xattr_value, xattr_len, pcr, | 326 | xattr_value, xattr_len, modsig, pcr, |
327 | template_desc); | 327 | template_desc); |
328 | if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) { | 328 | if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) { |
329 | inode_lock(inode); | 329 | inode_lock(inode); |
diff --git a/security/integrity/ima/ima_modsig.c b/security/integrity/ima/ima_modsig.c index 257387ce3b70..c412e31d1714 100644 --- a/security/integrity/ima/ima_modsig.c +++ b/security/integrity/ima/ima_modsig.c | |||
@@ -138,6 +138,25 @@ int ima_modsig_verify(struct key *keyring, const struct modsig *modsig) | |||
138 | VERIFYING_MODULE_SIGNATURE, NULL, NULL); | 138 | VERIFYING_MODULE_SIGNATURE, NULL, NULL); |
139 | } | 139 | } |
140 | 140 | ||
141 | int ima_get_modsig_digest(const struct modsig *modsig, enum hash_algo *algo, | ||
142 | const u8 **digest, u32 *digest_size) | ||
143 | { | ||
144 | *algo = modsig->hash_algo; | ||
145 | *digest = modsig->digest; | ||
146 | *digest_size = modsig->digest_size; | ||
147 | |||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | int ima_get_raw_modsig(const struct modsig *modsig, const void **data, | ||
152 | u32 *data_len) | ||
153 | { | ||
154 | *data = &modsig->raw_pkcs7; | ||
155 | *data_len = modsig->raw_pkcs7_len; | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
141 | void ima_free_modsig(struct modsig *modsig) | 160 | void ima_free_modsig(struct modsig *modsig) |
142 | { | 161 | { |
143 | if (!modsig) | 162 | if (!modsig) |
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 873dd7edaa78..4badc4fcda98 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
@@ -6,6 +6,9 @@ | |||
6 | * ima_policy.c | 6 | * ima_policy.c |
7 | * - initialize default measure policy rules | 7 | * - initialize default measure policy rules |
8 | */ | 8 | */ |
9 | |||
10 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
11 | |||
9 | #include <linux/init.h> | 12 | #include <linux/init.h> |
10 | #include <linux/list.h> | 13 | #include <linux/list.h> |
11 | #include <linux/fs.h> | 14 | #include <linux/fs.h> |
@@ -845,6 +848,38 @@ static void ima_log_string(struct audit_buffer *ab, char *key, char *value) | |||
845 | ima_log_string_op(ab, key, value, NULL); | 848 | ima_log_string_op(ab, key, value, NULL); |
846 | } | 849 | } |
847 | 850 | ||
851 | /* | ||
852 | * Validating the appended signature included in the measurement list requires | ||
853 | * the file hash calculated without the appended signature (i.e., the 'd-modsig' | ||
854 | * field). Therefore, notify the user if they have the 'modsig' field but not | ||
855 | * the 'd-modsig' field in the template. | ||
856 | */ | ||
857 | static void check_template_modsig(const struct ima_template_desc *template) | ||
858 | { | ||
859 | #define MSG "template with 'modsig' field also needs 'd-modsig' field\n" | ||
860 | bool has_modsig, has_dmodsig; | ||
861 | static bool checked; | ||
862 | int i; | ||
863 | |||
864 | /* We only need to notify the user once. */ | ||
865 | if (checked) | ||
866 | return; | ||
867 | |||
868 | has_modsig = has_dmodsig = false; | ||
869 | for (i = 0; i < template->num_fields; i++) { | ||
870 | if (!strcmp(template->fields[i]->field_id, "modsig")) | ||
871 | has_modsig = true; | ||
872 | else if (!strcmp(template->fields[i]->field_id, "d-modsig")) | ||
873 | has_dmodsig = true; | ||
874 | } | ||
875 | |||
876 | if (has_modsig && !has_dmodsig) | ||
877 | pr_notice(MSG); | ||
878 | |||
879 | checked = true; | ||
880 | #undef MSG | ||
881 | } | ||
882 | |||
848 | static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) | 883 | static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) |
849 | { | 884 | { |
850 | struct audit_buffer *ab; | 885 | struct audit_buffer *ab; |
@@ -1187,6 +1222,12 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) | |||
1187 | else if (entry->action == APPRAISE) | 1222 | else if (entry->action == APPRAISE) |
1188 | temp_ima_appraise |= ima_appraise_flag(entry->func); | 1223 | temp_ima_appraise |= ima_appraise_flag(entry->func); |
1189 | 1224 | ||
1225 | if (!result && entry->flags & IMA_MODSIG_ALLOWED) { | ||
1226 | template_desc = entry->template ? entry->template : | ||
1227 | ima_template_desc_current(); | ||
1228 | check_template_modsig(template_desc); | ||
1229 | } | ||
1230 | |||
1190 | audit_log_format(ab, "res=%d", !result); | 1231 | audit_log_format(ab, "res=%d", !result); |
1191 | audit_log_end(ab); | 1232 | audit_log_end(ab); |
1192 | return result; | 1233 | return result; |
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index cb349d7b2601..88d494ca6248 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c | |||
@@ -23,6 +23,7 @@ static struct ima_template_desc builtin_templates[] = { | |||
23 | {.name = "ima-ng", .fmt = "d-ng|n-ng"}, | 23 | {.name = "ima-ng", .fmt = "d-ng|n-ng"}, |
24 | {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"}, | 24 | {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"}, |
25 | {.name = "ima-buf", .fmt = "d-ng|n-ng|buf"}, | 25 | {.name = "ima-buf", .fmt = "d-ng|n-ng|buf"}, |
26 | {.name = "ima-modsig", .fmt = "d-ng|n-ng|sig|d-modsig|modsig"}, | ||
26 | {.name = "", .fmt = ""}, /* placeholder for a custom format */ | 27 | {.name = "", .fmt = ""}, /* placeholder for a custom format */ |
27 | }; | 28 | }; |
28 | 29 | ||
@@ -42,6 +43,10 @@ static const struct ima_template_field supported_fields[] = { | |||
42 | .field_show = ima_show_template_sig}, | 43 | .field_show = ima_show_template_sig}, |
43 | {.field_id = "buf", .field_init = ima_eventbuf_init, | 44 | {.field_id = "buf", .field_init = ima_eventbuf_init, |
44 | .field_show = ima_show_template_buf}, | 45 | .field_show = ima_show_template_buf}, |
46 | {.field_id = "d-modsig", .field_init = ima_eventdigest_modsig_init, | ||
47 | .field_show = ima_show_template_digest_ng}, | ||
48 | {.field_id = "modsig", .field_init = ima_eventmodsig_init, | ||
49 | .field_show = ima_show_template_sig}, | ||
45 | }; | 50 | }; |
46 | 51 | ||
47 | /* | 52 | /* |
@@ -49,7 +54,7 @@ static const struct ima_template_field supported_fields[] = { | |||
49 | * need to be accounted for since they shouldn't be defined in the same template | 54 | * need to be accounted for since they shouldn't be defined in the same template |
50 | * description as 'd-ng' and 'n-ng' respectively. | 55 | * description as 'd-ng' and 'n-ng' respectively. |
51 | */ | 56 | */ |
52 | #define MAX_TEMPLATE_NAME_LEN sizeof("d-ng|n-ng|sig|buf") | 57 | #define MAX_TEMPLATE_NAME_LEN sizeof("d-ng|n-ng|sig|buf|d-modisg|modsig") |
53 | 58 | ||
54 | static struct ima_template_desc *ima_template; | 59 | static struct ima_template_desc *ima_template; |
55 | 60 | ||
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index 2fb9a10bc6b7..32ae05d88257 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c | |||
@@ -225,7 +225,8 @@ int ima_parse_buf(void *bufstartp, void *bufendp, void **bufcurp, | |||
225 | return 0; | 225 | return 0; |
226 | } | 226 | } |
227 | 227 | ||
228 | static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo, | 228 | static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize, |
229 | u8 hash_algo, | ||
229 | struct ima_field_data *field_data) | 230 | struct ima_field_data *field_data) |
230 | { | 231 | { |
231 | /* | 232 | /* |
@@ -328,6 +329,41 @@ out: | |||
328 | hash_algo, field_data); | 329 | hash_algo, field_data); |
329 | } | 330 | } |
330 | 331 | ||
332 | /* | ||
333 | * This function writes the digest of the file which is expected to match the | ||
334 | * digest contained in the file's appended signature. | ||
335 | */ | ||
336 | int ima_eventdigest_modsig_init(struct ima_event_data *event_data, | ||
337 | struct ima_field_data *field_data) | ||
338 | { | ||
339 | enum hash_algo hash_algo; | ||
340 | const u8 *cur_digest; | ||
341 | u32 cur_digestsize; | ||
342 | |||
343 | if (!event_data->modsig) | ||
344 | return 0; | ||
345 | |||
346 | if (event_data->violation) { | ||
347 | /* Recording a violation. */ | ||
348 | hash_algo = HASH_ALGO_SHA1; | ||
349 | cur_digest = NULL; | ||
350 | cur_digestsize = 0; | ||
351 | } else { | ||
352 | int rc; | ||
353 | |||
354 | rc = ima_get_modsig_digest(event_data->modsig, &hash_algo, | ||
355 | &cur_digest, &cur_digestsize); | ||
356 | if (rc) | ||
357 | return rc; | ||
358 | else if (hash_algo == HASH_ALGO__LAST || cur_digestsize == 0) | ||
359 | /* There was some error collecting the digest. */ | ||
360 | return -EINVAL; | ||
361 | } | ||
362 | |||
363 | return ima_eventdigest_init_common(cur_digest, cur_digestsize, | ||
364 | hash_algo, field_data); | ||
365 | } | ||
366 | |||
331 | static int ima_eventname_init_common(struct ima_event_data *event_data, | 367 | static int ima_eventname_init_common(struct ima_event_data *event_data, |
332 | struct ima_field_data *field_data, | 368 | struct ima_field_data *field_data, |
333 | bool size_limit) | 369 | bool size_limit) |
@@ -406,3 +442,29 @@ int ima_eventbuf_init(struct ima_event_data *event_data, | |||
406 | event_data->buf_len, DATA_FMT_HEX, | 442 | event_data->buf_len, DATA_FMT_HEX, |
407 | field_data); | 443 | field_data); |
408 | } | 444 | } |
445 | |||
446 | /* | ||
447 | * ima_eventmodsig_init - include the appended file signature as part of the | ||
448 | * template data | ||
449 | */ | ||
450 | int ima_eventmodsig_init(struct ima_event_data *event_data, | ||
451 | struct ima_field_data *field_data) | ||
452 | { | ||
453 | const void *data; | ||
454 | u32 data_len; | ||
455 | int rc; | ||
456 | |||
457 | if (!event_data->modsig) | ||
458 | return 0; | ||
459 | |||
460 | /* | ||
461 | * modsig is a runtime structure containing pointers. Get its raw data | ||
462 | * instead. | ||
463 | */ | ||
464 | rc = ima_get_raw_modsig(event_data->modsig, &data, &data_len); | ||
465 | if (rc) | ||
466 | return rc; | ||
467 | |||
468 | return ima_write_template_field_data(data, data_len, DATA_FMT_HEX, | ||
469 | field_data); | ||
470 | } | ||
diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h index 652aa5de81ef..9a88c79a7a61 100644 --- a/security/integrity/ima/ima_template_lib.h +++ b/security/integrity/ima/ima_template_lib.h | |||
@@ -36,10 +36,14 @@ int ima_eventname_init(struct ima_event_data *event_data, | |||
36 | struct ima_field_data *field_data); | 36 | struct ima_field_data *field_data); |
37 | int ima_eventdigest_ng_init(struct ima_event_data *event_data, | 37 | int ima_eventdigest_ng_init(struct ima_event_data *event_data, |
38 | struct ima_field_data *field_data); | 38 | struct ima_field_data *field_data); |
39 | int ima_eventdigest_modsig_init(struct ima_event_data *event_data, | ||
40 | struct ima_field_data *field_data); | ||
39 | int ima_eventname_ng_init(struct ima_event_data *event_data, | 41 | int ima_eventname_ng_init(struct ima_event_data *event_data, |
40 | struct ima_field_data *field_data); | 42 | struct ima_field_data *field_data); |
41 | int ima_eventsig_init(struct ima_event_data *event_data, | 43 | int ima_eventsig_init(struct ima_event_data *event_data, |
42 | struct ima_field_data *field_data); | 44 | struct ima_field_data *field_data); |
43 | int ima_eventbuf_init(struct ima_event_data *event_data, | 45 | int ima_eventbuf_init(struct ima_event_data *event_data, |
44 | struct ima_field_data *field_data); | 46 | struct ima_field_data *field_data); |
47 | int ima_eventmodsig_init(struct ima_event_data *event_data, | ||
48 | struct ima_field_data *field_data); | ||
45 | #endif /* __LINUX_IMA_TEMPLATE_LIB_H */ | 49 | #endif /* __LINUX_IMA_TEMPLATE_LIB_H */ |