ima: define a new template field named 'd-ngv2' and templates
authorMimi Zohar <zohar@linux.ibm.com>
Thu, 23 Dec 2021 17:29:56 +0000 (12:29 -0500)
committerMimi Zohar <zohar@linux.ibm.com>
Thu, 5 May 2022 15:49:13 +0000 (11:49 -0400)
In preparation to differentiate between unsigned regular IMA file
hashes and fs-verity's file digests in the IMA measurement list,
define a new template field named 'd-ngv2'.

Also define two new templates named 'ima-ngv2' and 'ima-sigv2', which
include the new 'd-ngv2' field.

Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
Documentation/admin-guide/kernel-parameters.txt
Documentation/security/IMA-templates.rst
security/integrity/ima/ima_template.c
security/integrity/ima/ima_template_lib.c
security/integrity/ima/ima_template_lib.h

index 3f1cc5e317ed4a5ad001082c9c589b6008f68db9..5e866be89f5d06641ab83c66e1977af5284b4750 100644 (file)
 
        ima_template=   [IMA]
                        Select one of defined IMA measurements template formats.
-                       Formats: { "ima" | "ima-ng" | "ima-sig" }
+                       Formats: { "ima" | "ima-ng" | "ima-ngv2" | "ima-sig" |
+                                  "ima-sigv2" }
                        Default: "ima-ng"
 
        ima_template_fmt=
index cab97f49971d25cb47268825f09cd53dc222e424..eafc4e34f890d3a94798899fb18e768e9e68a85b 100644 (file)
@@ -67,6 +67,8 @@ descriptors by adding their identifier to the format string
  - 'n': the name of the event (i.e. the file name), with size up to 255 bytes;
  - 'd-ng': the digest of the event, calculated with an arbitrary hash
    algorithm (field format: <hash algo>:digest);
+ - 'd-ngv2': same as d-ng, but prefixed with the "ima" digest type
+   (field format: <digest type>:<hash algo>:digest);
  - 'd-modsig': the digest of the event without the appended modsig;
  - 'n-ng': the name of the event, without size limitations;
  - 'sig': the file signature, or the EVM portable signature if the file
@@ -87,7 +89,9 @@ Below, there is the list of defined template descriptors:
 
  - "ima": its format is ``d|n``;
  - "ima-ng" (default): its format is ``d-ng|n-ng``;
+ - "ima-ngv2": its format is ``d-ngv2|n-ng``;
  - "ima-sig": its format is ``d-ng|n-ng|sig``;
+ - "ima-sigv2": its format is ``d-ngv2|n-ng|sig``;
  - "ima-buf": its format is ``d-ng|n-ng|buf``;
  - "ima-modsig": its format is ``d-ng|n-ng|sig|d-modsig|modsig``;
  - "evm-sig": its format is ``d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode``;
index db1ad6d7a57fbf7d5866ccf4d6cafb397c6f4f3f..c25079faa208859214c2a9d2aa24d18de870f108 100644 (file)
@@ -20,6 +20,8 @@ static struct ima_template_desc builtin_templates[] = {
        {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT},
        {.name = "ima-ng", .fmt = "d-ng|n-ng"},
        {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"},
+       {.name = "ima-ngv2", .fmt = "d-ngv2|n-ng"},
+       {.name = "ima-sigv2", .fmt = "d-ngv2|n-ng|sig"},
        {.name = "ima-buf", .fmt = "d-ng|n-ng|buf"},
        {.name = "ima-modsig", .fmt = "d-ng|n-ng|sig|d-modsig|modsig"},
        {.name = "evm-sig",
@@ -38,6 +40,8 @@ static const struct ima_template_field supported_fields[] = {
         .field_show = ima_show_template_string},
        {.field_id = "d-ng", .field_init = ima_eventdigest_ng_init,
         .field_show = ima_show_template_digest_ng},
+       {.field_id = "d-ngv2", .field_init = ima_eventdigest_ngv2_init,
+        .field_show = ima_show_template_digest_ngv2},
        {.field_id = "n-ng", .field_init = ima_eventname_ng_init,
         .field_show = ima_show_template_string},
        {.field_id = "sig", .field_init = ima_eventsig_init,
index 4b6706f864d439a57e3ba646450f95719030e9a7..409023e620d6437b8fccc76afdd438897793d7de 100644 (file)
@@ -24,11 +24,22 @@ static bool ima_template_hash_algo_allowed(u8 algo)
 enum data_formats {
        DATA_FMT_DIGEST = 0,
        DATA_FMT_DIGEST_WITH_ALGO,
+       DATA_FMT_DIGEST_WITH_TYPE_AND_ALGO,
        DATA_FMT_STRING,
        DATA_FMT_HEX,
        DATA_FMT_UINT
 };
 
+enum digest_type {
+       DIGEST_TYPE_IMA,
+       DIGEST_TYPE__LAST
+};
+
+#define DIGEST_TYPE_NAME_LEN_MAX 4     /* including NUL */
+static const char * const digest_type_name[DIGEST_TYPE__LAST] = {
+       [DIGEST_TYPE_IMA] = "ima"
+};
+
 static int ima_write_template_field_data(const void *data, const u32 datalen,
                                         enum data_formats datafmt,
                                         struct ima_field_data *field_data)
@@ -72,8 +83,9 @@ static void ima_show_template_data_ascii(struct seq_file *m,
        u32 buflen = field_data->len;
 
        switch (datafmt) {
+       case DATA_FMT_DIGEST_WITH_TYPE_AND_ALGO:
        case DATA_FMT_DIGEST_WITH_ALGO:
-               buf_ptr = strnchr(field_data->data, buflen, ':');
+               buf_ptr = strrchr(field_data->data, ':');
                if (buf_ptr != field_data->data)
                        seq_printf(m, "%s", field_data->data);
 
@@ -178,6 +190,14 @@ void ima_show_template_digest_ng(struct seq_file *m, enum ima_show_type show,
                                     field_data);
 }
 
+void ima_show_template_digest_ngv2(struct seq_file *m, enum ima_show_type show,
+                                  struct ima_field_data *field_data)
+{
+       ima_show_template_field_data(m, show,
+                                    DATA_FMT_DIGEST_WITH_TYPE_AND_ALGO,
+                                    field_data);
+}
+
 void ima_show_template_string(struct seq_file *m, enum ima_show_type show,
                              struct ima_field_data *field_data)
 {
@@ -265,28 +285,35 @@ int ima_parse_buf(void *bufstartp, void *bufendp, void **bufcurp,
 }
 
 static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize,
-                                      u8 hash_algo,
+                                      u8 digest_type, u8 hash_algo,
                                       struct ima_field_data *field_data)
 {
        /*
         * digest formats:
         *  - DATA_FMT_DIGEST: digest
         *  - DATA_FMT_DIGEST_WITH_ALGO: <hash algo> + ':' + '\0' + digest,
+        *  - DATA_FMT_DIGEST_WITH_TYPE_AND_ALGO:
+        *      <digest type> + ':' + <hash algo> + ':' + '\0' + digest,
         *
         *    where 'DATA_FMT_DIGEST' is the original digest format ('d')
         *      with a hash size limitation of 20 bytes,
+        *    where <digest type> is "ima",
         *    where <hash algo> is the hash_algo_name[] string.
         */
-       u8 buffer[CRYPTO_MAX_ALG_NAME + 2 + IMA_MAX_DIGEST_SIZE] = { 0 };
+       u8 buffer[DIGEST_TYPE_NAME_LEN_MAX + CRYPTO_MAX_ALG_NAME + 2 +
+               IMA_MAX_DIGEST_SIZE] = { 0 };
        enum data_formats fmt = DATA_FMT_DIGEST;
        u32 offset = 0;
 
-       if (hash_algo < HASH_ALGO__LAST) {
+       if (digest_type < DIGEST_TYPE__LAST && hash_algo < HASH_ALGO__LAST) {
+               fmt = DATA_FMT_DIGEST_WITH_TYPE_AND_ALGO;
+               offset += 1 + sprintf(buffer, "%s:%s:",
+                                     digest_type_name[digest_type],
+                                     hash_algo_name[hash_algo]);
+       } else if (hash_algo < HASH_ALGO__LAST) {
                fmt = DATA_FMT_DIGEST_WITH_ALGO;
-               offset += snprintf(buffer, CRYPTO_MAX_ALG_NAME + 1, "%s",
-                                  hash_algo_name[hash_algo]);
-               buffer[offset] = ':';
-               offset += 2;
+               offset += 1 + sprintf(buffer, "%s:",
+                                     hash_algo_name[hash_algo]);
        }
 
        if (digest)
@@ -361,7 +388,8 @@ int ima_eventdigest_init(struct ima_event_data *event_data,
        cur_digestsize = hash.hdr.length;
 out:
        return ima_eventdigest_init_common(cur_digest, cur_digestsize,
-                                          HASH_ALGO__LAST, field_data);
+                                          DIGEST_TYPE__LAST, HASH_ALGO__LAST,
+                                          field_data);
 }
 
 /*
@@ -382,7 +410,32 @@ int ima_eventdigest_ng_init(struct ima_event_data *event_data,
        hash_algo = event_data->iint->ima_hash->algo;
 out:
        return ima_eventdigest_init_common(cur_digest, cur_digestsize,
-                                          hash_algo, field_data);
+                                          DIGEST_TYPE__LAST, hash_algo,
+                                          field_data);
+}
+
+/*
+ * This function writes the digest of an event (without size limit),
+ * prefixed with both the digest type and hash algorithm.
+ */
+int ima_eventdigest_ngv2_init(struct ima_event_data *event_data,
+                             struct ima_field_data *field_data)
+{
+       u8 *cur_digest = NULL, hash_algo = ima_hash_algo;
+       u32 cur_digestsize = 0;
+       u8 digest_type = DIGEST_TYPE_IMA;
+
+       if (event_data->violation)      /* recording a violation. */
+               goto out;
+
+       cur_digest = event_data->iint->ima_hash->digest;
+       cur_digestsize = event_data->iint->ima_hash->length;
+
+       hash_algo = event_data->iint->ima_hash->algo;
+out:
+       return ima_eventdigest_init_common(cur_digest, cur_digestsize,
+                                          digest_type, hash_algo,
+                                          field_data);
 }
 
 /*
@@ -417,7 +470,8 @@ int ima_eventdigest_modsig_init(struct ima_event_data *event_data,
        }
 
        return ima_eventdigest_init_common(cur_digest, cur_digestsize,
-                                          hash_algo, field_data);
+                                          DIGEST_TYPE__LAST, hash_algo,
+                                          field_data);
 }
 
 static int ima_eventname_init_common(struct ima_event_data *event_data,
index c71f1de95753d92a37c87fc9eef744f164f683bb..9f7c335f304f4ff714c741424bc0a446c267024c 100644 (file)
@@ -21,6 +21,8 @@ void ima_show_template_digest(struct seq_file *m, enum ima_show_type show,
                              struct ima_field_data *field_data);
 void ima_show_template_digest_ng(struct seq_file *m, enum ima_show_type show,
                                 struct ima_field_data *field_data);
+void ima_show_template_digest_ngv2(struct seq_file *m, enum ima_show_type show,
+                                  struct ima_field_data *field_data);
 void ima_show_template_string(struct seq_file *m, enum ima_show_type show,
                              struct ima_field_data *field_data);
 void ima_show_template_sig(struct seq_file *m, enum ima_show_type show,
@@ -38,6 +40,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_ngv2_init(struct ima_event_data *event_data,
+                             struct ima_field_data *field_data);
 int ima_eventdigest_modsig_init(struct ima_event_data *event_data,
                                struct ima_field_data *field_data);
 int ima_eventname_ng_init(struct ima_event_data *event_data,