Define new "d-sig" template field which holds the digest that is expected to match the one contained in the modsig. Suggested-by: Mimi Zohar <zohar@xxxxxxxxxxxxx> Signed-off-by: Thiago Jung Bauermann <bauerman@xxxxxxxxxxxxx> --- Documentation/security/IMA-templates.rst | 5 ++++ security/integrity/ima/ima.h | 9 +++++++ security/integrity/ima/ima_modsig.c | 23 ++++++++++++++++ security/integrity/ima/ima_template.c | 4 ++- security/integrity/ima/ima_template_lib.c | 32 ++++++++++++++++++++++- security/integrity/ima/ima_template_lib.h | 2 ++ 6 files changed, 73 insertions(+), 2 deletions(-) diff --git a/Documentation/security/IMA-templates.rst b/Documentation/security/IMA-templates.rst index 2cd0e273cc9a..f2a0f4225857 100644 --- a/Documentation/security/IMA-templates.rst +++ b/Documentation/security/IMA-templates.rst @@ -68,6 +68,11 @@ descriptors by adding their identifier to the format string - 'd-ng': the digest of the event, calculated with an arbitrary hash algorithm (field format: [<hash algo>:]digest, where the digest prefix is shown only if the hash algorithm is not SHA1 or MD5); + - 'd-sig': the digest of the event for files that have an appended modsig. This + field is calculated without including the modsig and thus will differ from + the total digest of the file, but it is what should match the digest + contained in the modsig (if it doesn't, the signature is invalid). It is + shown in the same format as 'd-ng'; - 'n-ng': the name of the event, without size limitations; - 'sig': the file signature. diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 753d59352718..40a6ddfdd9ea 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -316,6 +316,8 @@ int ima_read_collect_modsig(enum ima_hooks func, const void *buf, loff_t buf_len, struct evm_ima_xattr_data **xattr_value, int *xattr_len); +int ima_get_modsig_hash(struct evm_ima_xattr_data *hdr, enum hash_algo *algo, + const u8 **hash, u8 *len); void ima_free_xattr_data(struct evm_ima_xattr_data *hdr); #else static inline bool ima_hook_supports_modsig(enum ima_hooks func) @@ -331,6 +333,13 @@ static inline int ima_read_collect_modsig(enum ima_hooks func, const void *buf, return -EOPNOTSUPP; } +static inline int ima_get_modsig_hash(struct evm_ima_xattr_data *hdr, + enum hash_algo *algo, const u8 **hash, + u8 *len) +{ + return -EOPNOTSUPP; +} + static inline void ima_free_xattr_data(struct evm_ima_xattr_data *hdr) { kfree(hdr); diff --git a/security/integrity/ima/ima_modsig.c b/security/integrity/ima/ima_modsig.c index f228f333509d..587b79a9afef 100644 --- a/security/integrity/ima/ima_modsig.c +++ b/security/integrity/ima/ima_modsig.c @@ -167,6 +167,29 @@ int ima_read_collect_modsig(enum ima_hooks func, const void *buf, return rc; } +int ima_get_modsig_hash(struct evm_ima_xattr_data *hdr, enum hash_algo *algo, + const u8 **hash, u8 *len) +{ + struct modsig_hdr *modsig = (typeof(modsig)) hdr; + const struct public_key_signature *pks; + int i; + + if (!hdr || hdr->type != IMA_MODSIG) + return -EINVAL; + + pks = pkcs7_get_message_sig(modsig->pkcs7_msg); + if (!pks) + return -EBADMSG; + + for (i = 0; i < HASH_ALGO__LAST; i++) + if (!strcmp(hash_algo_name[i], pks->hash_algo)) + break; + + *algo = i; + + return pkcs7_get_digest(modsig->pkcs7_msg, hash, len); +} + int ima_modsig_verify(struct key *keyring, const void *hdr) { const struct modsig_hdr *modsig = (const struct modsig_hdr *) hdr; diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index b631b8bc7624..045ad508cbb8 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -43,8 +43,10 @@ static const struct ima_template_field supported_fields[] = { .field_show = ima_show_template_string}, {.field_id = "sig", .field_init = ima_eventsig_init, .field_show = ima_show_template_sig}, + {.field_id = "d-sig", .field_init = ima_eventdigest_sig_init, + .field_show = ima_show_template_digest_ng}, }; -#define MAX_TEMPLATE_NAME_LEN 15 +#define MAX_TEMPLATE_NAME_LEN 24 static struct ima_template_desc *ima_template; static struct ima_template_desc *lookup_template_desc(const char *name); diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index 300912914b17..36d175816894 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -222,7 +222,8 @@ int ima_parse_buf(void *bufstartp, void *bufendp, void **bufcurp, return 0; } -static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo, +static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize, + u8 hash_algo, struct ima_field_data *field_data) { /* @@ -325,6 +326,35 @@ int ima_eventdigest_ng_init(struct ima_event_data *event_data, hash_algo, field_data); } +/* + * This function writes the digest of the file which is expected to match the + * digest contained in the file's embedded signature. + */ +int ima_eventdigest_sig_init(struct ima_event_data *event_data, + struct ima_field_data *field_data) +{ + struct evm_ima_xattr_data *xattr_value = event_data->xattr_value; + enum hash_algo hash_algo = HASH_ALGO_SHA1; + const u8 *cur_digest = NULL; + u8 cur_digestsize = 0; + int ret; + + if (!xattr_value || xattr_value->type != IMA_MODSIG) + return 0; + + if (event_data->violation) /* recording a violation. */ + goto out; + + ret = ima_get_modsig_hash(xattr_value, &hash_algo, &cur_digest, + &cur_digestsize); + if (ret) + return ret; + + out: + return ima_eventdigest_init_common(cur_digest, cur_digestsize, + hash_algo, field_data); +} + static int ima_eventname_init_common(struct ima_event_data *event_data, struct ima_field_data *field_data, bool size_limit) diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h index 6a3d8b831deb..3cd353e83f73 100644 --- a/security/integrity/ima/ima_template_lib.h +++ b/security/integrity/ima/ima_template_lib.h @@ -38,6 +38,8 @@ int ima_eventname_init(struct ima_event_data *event_data, struct ima_field_data *field_data); int ima_eventdigest_ng_init(struct ima_event_data *event_data, struct ima_field_data *field_data); +int ima_eventdigest_sig_init(struct ima_event_data *event_data, + struct ima_field_data *field_data); int ima_eventname_ng_init(struct ima_event_data *event_data, struct ima_field_data *field_data); int ima_eventsig_init(struct ima_event_data *event_data,