From: Roberto Sassu <[email protected]>

Make binary_runtime_size as an array, to have separate counters per binary
measurements list type. Currently, define the BINARY type for the existing
binary measurements list.

Introduce ima_update_binary_runtime_size() to facilitate updating a
binary_runtime_size value with a given binary measurement list type.

Also add the binary measurements list type parameter to
ima_get_binary_runtime_size(), to retrieve the desired value. Retrieving
the value is now done under the ima_extend_list_mutex, since there can be
concurrent updates.

No functional change (except for the mutex usage, that fixes the
concurrency issue): the BINARY array element is equivalent to the old
binary_runtime_size.

Link: https://github.com/linux-integrity/linux/issues/1
Signed-off-by: Roberto Sassu <[email protected]>
---
 security/integrity/ima/ima.h       |  2 +-
 security/integrity/ima/ima_kexec.c |  5 ++--
 security/integrity/ima/ima_queue.c | 40 +++++++++++++++++++++---------
 3 files changed, 32 insertions(+), 15 deletions(-)

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 199237e2d2e3..97b7d6024b5d 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -318,7 +318,7 @@ int ima_restore_measurement_entry(struct ima_template_entry 
*entry);
 int ima_restore_measurement_list(loff_t bufsize, void *buf);
 int ima_measurements_show(struct seq_file *m, void *v);
 int __init ima_init_htable(void);
-unsigned long ima_get_binary_runtime_size(void);
+unsigned long ima_get_binary_runtime_size(enum binary_lists binary_list);
 int ima_init_template(void);
 void ima_init_template_list(void);
 int __init ima_init_digests(void);
diff --git a/security/integrity/ima/ima_kexec.c 
b/security/integrity/ima/ima_kexec.c
index 40962dc0ca86..44ebefbdcab0 100644
--- a/security/integrity/ima/ima_kexec.c
+++ b/security/integrity/ima/ima_kexec.c
@@ -42,7 +42,7 @@ void ima_measure_kexec_event(const char *event_name)
        long len;
        int n;
 
-       buf_size = ima_get_binary_runtime_size();
+       buf_size = ima_get_binary_runtime_size(BINARY);
        len = atomic_long_read(&ima_num_entries[BINARY]);
 
        n = scnprintf(ima_kexec_event, IMA_KEXEC_EVENT_LEN,
@@ -159,7 +159,8 @@ void ima_add_kexec_buffer(struct kimage *image)
        else
                extra_memory = CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB * 1024;
 
-       binary_runtime_size = ima_get_binary_runtime_size() + extra_memory;
+       binary_runtime_size = ima_get_binary_runtime_size(BINARY) +
+                             extra_memory;
 
        if (binary_runtime_size >= ULONG_MAX - PAGE_SIZE)
                kexec_segment_size = ULONG_MAX;
diff --git a/security/integrity/ima/ima_queue.c 
b/security/integrity/ima/ima_queue.c
index 952172a4905d..b6d10dceb669 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -27,9 +27,11 @@ static struct tpm_digest *digests;
 
 LIST_HEAD(ima_measurements);   /* list of all measurements */
 #ifdef CONFIG_IMA_KEXEC
-static unsigned long binary_runtime_size;
+static unsigned long binary_runtime_size[BINARY__LAST];
 #else
-static unsigned long binary_runtime_size = ULONG_MAX;
+static unsigned long binary_runtime_size[BINARY__LAST] = {
+       [0 ... BINARY__LAST - 1] = ULONG_MAX
+};
 #endif
 
 /* num of stored measurements in the list */
@@ -131,6 +133,20 @@ static int get_binary_runtime_size(struct 
ima_template_entry *entry)
        return size;
 }
 
+static void ima_update_binary_runtime_size(struct ima_template_entry *entry,
+                                          enum binary_lists binary_list)
+{
+       int size;
+
+       if (binary_runtime_size[binary_list] == ULONG_MAX)
+               return;
+
+       size = get_binary_runtime_size(entry);
+       binary_runtime_size[binary_list] =
+               (binary_runtime_size[binary_list] < ULONG_MAX - size) ?
+               binary_runtime_size[binary_list] + size : ULONG_MAX;
+}
+
 /* ima_add_template_entry helper function:
  * - Add template entry to the measurement list and hash table, for
  *   all entries except those carried across kexec.
@@ -163,13 +179,7 @@ static int ima_add_digest_entry(struct ima_template_entry 
*entry,
                hlist_add_head_rcu(&qe->hnext, &htable[key]);
        }
 
-       if (binary_runtime_size != ULONG_MAX) {
-               int size;
-
-               size = get_binary_runtime_size(entry);
-               binary_runtime_size = (binary_runtime_size < ULONG_MAX - size) ?
-                    binary_runtime_size + size : ULONG_MAX;
-       }
+       ima_update_binary_runtime_size(entry, BINARY);
        return 0;
 }
 
@@ -178,12 +188,18 @@ static int ima_add_digest_entry(struct ima_template_entry 
*entry,
  * entire binary_runtime_measurement list, including the ima_kexec_hdr
  * structure.
  */
-unsigned long ima_get_binary_runtime_size(void)
+unsigned long ima_get_binary_runtime_size(enum binary_lists binary_list)
 {
-       if (binary_runtime_size >= (ULONG_MAX - sizeof(struct ima_kexec_hdr)))
+       unsigned long val;
+
+       mutex_lock(&ima_extend_list_mutex);
+       val = binary_runtime_size[binary_list];
+       mutex_unlock(&ima_extend_list_mutex);
+
+       if (val >= (ULONG_MAX - sizeof(struct ima_kexec_hdr)))
                return ULONG_MAX;
        else
-               return binary_runtime_size + sizeof(struct ima_kexec_hdr);
+               return val + sizeof(struct ima_kexec_hdr);
 }
 
 static int ima_pcr_extend(struct tpm_digest *digests_arg, int pcr)
-- 
2.43.0


Reply via email to