[RFC PATCH 10/30] ima: Add ima namespace ID to the ima ML related structures

From: krzysztof.struczynski
Date: Tue Aug 18 2020 - 11:44:27 EST


From: Krzysztof Struczynski <krzysztof.struczynski@xxxxxxxxxx>

Add ima namespace ID to the ima_event_data and ima_template_entry. This
is done so that the ima namespace ID can be tracked per entry and
included in the hash. The following patch will add a new template that
will utilize it.

IMA namespace ID is simply an inode number allocated to the namespace
when it's created and therefore it can be re-used once the namespace is
destroyed.

Signed-off-by: Krzysztof Struczynski <krzysztof.struczynski@xxxxxxxxxx>
---
security/integrity/ima/ima.h | 19 ++++++++++++++++++-
security/integrity/ima/ima_api.c | 9 ++++++++-
security/integrity/ima/ima_fs.c | 17 +++++++++++------
security/integrity/ima/ima_init.c | 2 ++
security/integrity/ima/ima_kexec.c | 4 +++-
security/integrity/ima/ima_main.c | 5 +++--
security/integrity/ima/ima_template.c | 10 +++++++---
7 files changed, 52 insertions(+), 14 deletions(-)

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 33b4a8295c41..7b7252d35d5a 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -75,6 +75,7 @@ struct ima_event_data {
const char *violation;
const void *buf;
int buf_len;
+ unsigned int ns_id;
};

/* IMA template field data definition */
@@ -103,6 +104,7 @@ struct ima_template_desc {

struct ima_template_entry {
int pcr;
+ unsigned int ns_id;
struct tpm_digest *digests;
struct ima_template_desc *template_desc; /* template descriptor */
u32 template_data_len;
@@ -129,8 +131,17 @@ extern const int read_idmap[];

#ifdef CONFIG_HAVE_IMA_KEXEC
void ima_load_kexec_buffer(void);
+extern const u16 kexec_header_version;
+static inline u16 get_kexec_header_version(void)
+{
+ return kexec_header_version;
+}
#else
static inline void ima_load_kexec_buffer(void) {}
+static inline u16 get_kexec_header_version(void)
+{
+ return 1;
+}
#endif /* CONFIG_HAVE_IMA_KEXEC */

/*
@@ -153,7 +164,8 @@ int ima_calc_field_array_hash(struct ima_field_data *field_data,
int ima_calc_boot_aggregate(struct ima_digest_data *hash);
void ima_add_violation(struct file *file, const unsigned char *filename,
struct integrity_iint_cache *iint,
- const char *op, const char *cause);
+ const char *op, const char *cause,
+ struct ima_namespace *ima_ns);
int ima_init_crypto(void);
void ima_putc(struct seq_file *m, void *data, int datalen);
void ima_print_digest(struct seq_file *m, u8 *digest, u32 size);
@@ -415,6 +427,11 @@ extern struct ima_policy_setup_data init_policy_setup_data;
extern struct list_head ima_ns_list;
extern struct rw_semaphore ima_ns_list_lock;

+static inline unsigned int get_ns_id(const struct ima_namespace *ima_ns)
+{
+ return ima_ns->ns.inum;
+}
+
#ifdef CONFIG_IMA_NS
int __init ima_init_namespace(void);

diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 8d7b0d4635fc..1f4411fffa45 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -76,6 +76,8 @@ int ima_alloc_init_template(struct ima_event_data *event_data,
(*entry)->template_data_len += sizeof(len);
(*entry)->template_data_len += len;
}
+
+ (*entry)->ns_id = event_data->ns_id;
return 0;
out:
ima_free_template_entry(*entry);
@@ -132,7 +134,8 @@ int ima_store_template(struct ima_template_entry *entry,
*/
void ima_add_violation(struct file *file, const unsigned char *filename,
struct integrity_iint_cache *iint,
- const char *op, const char *cause)
+ const char *op, const char *cause,
+ struct ima_namespace *ima_ns)
{
struct ima_template_entry *entry;
struct inode *inode = file_inode(file);
@@ -143,6 +146,8 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
int violation = 1;
int result;

+ event_data.ns_id = get_ns_id(ima_ns);
+
/* can overflow, only indicator */
atomic_long_inc(&ima_htable.violations);

@@ -313,7 +318,9 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
.xattr_len = xattr_len,
.modsig = modsig };
int violation = 0;
+ struct ima_namespace *ima_ns = get_current_ns();

+ event_data.ns_id = get_ns_id(ima_ns);
/*
* We still need to store the measurement in the case of MODSIG because
* we only have its contents to put in the list at the time of
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 3839b9eaecab..4758e14c4a7b 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -117,6 +117,7 @@ void ima_putc(struct seq_file *m, void *data, int datalen)

/* print format:
* 32bit-le=pcr#
+ * 32bit-le=namespace id
* char[20]=template digest
* 32bit-le=template name size
* char[n]=template name
@@ -129,7 +130,7 @@ int ima_measurements_show(struct seq_file *m, void *v)
struct ima_queue_entry *qe = v;
struct ima_template_entry *e;
char *template_name;
- u32 pcr, namelen, template_data_len; /* temporary fields */
+ u32 pcr, ns_id, namelen, template_data_len; /* temporary fields */
bool is_ima_template = false;
int i;

@@ -149,18 +150,22 @@ int ima_measurements_show(struct seq_file *m, void *v)
pcr = !ima_canonical_fmt ? e->pcr : cpu_to_le32(e->pcr);
ima_putc(m, &pcr, sizeof(e->pcr));

- /* 2nd: template digest */
+ /* 2nd: ima namespace id */
+ ns_id = !ima_canonical_fmt ? e->ns_id : cpu_to_le32(e->ns_id);
+ ima_putc(m, &ns_id, sizeof(e->ns_id));
+
+ /* 3rd: template digest */
ima_putc(m, e->digests[ima_sha1_idx].digest, TPM_DIGEST_SIZE);

- /* 3rd: template name size */
+ /* 4th: template name size */
namelen = !ima_canonical_fmt ? strlen(template_name) :
cpu_to_le32(strlen(template_name));
ima_putc(m, &namelen, sizeof(namelen));

- /* 4th: template name */
+ /* 5th: template name */
ima_putc(m, template_name, strlen(template_name));

- /* 5th: template length (except for 'ima' template) */
+ /* 6th: template length (except for 'ima' template) */
if (strcmp(template_name, IMA_TEMPLATE_IMA_NAME) == 0)
is_ima_template = true;

@@ -170,7 +175,7 @@ int ima_measurements_show(struct seq_file *m, void *v)
ima_putc(m, &template_data_len, sizeof(e->template_data_len));
}

- /* 6th: template specific data */
+ /* 7th: template specific data */
for (i = 0; i < e->template_desc->num_fields; i++) {
enum ima_show_type show = IMA_SHOW_BINARY;
const struct ima_template_field *field =
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index d042b08cc4d7..d63ecb02b032 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -68,6 +68,8 @@ static int __init ima_add_boot_aggregate(void)
char digest[TPM_MAX_DIGEST_SIZE];
} hash;

+ event_data.ns_id = get_ns_id(&init_ima_ns);
+
memset(iint, 0, sizeof(*iint));
memset(&hash, 0, sizeof(hash));
iint->ima_hash = &hash.hdr;
diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
index 121de3e04af2..1fefa59cf9b1 100644
--- a/security/integrity/ima/ima_kexec.c
+++ b/security/integrity/ima/ima_kexec.c
@@ -13,6 +13,8 @@
#include "ima.h"

#ifdef CONFIG_IMA_KEXEC
+const u16 kexec_header_version = 2;
+
static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
unsigned long segment_size)
{
@@ -33,7 +35,7 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
file.count = sizeof(khdr); /* reserved space */

memset(&khdr, 0, sizeof(khdr));
- khdr.version = 1;
+ khdr.version = kexec_header_version;
list_for_each_entry_rcu(qe, &ima_measurements, later) {
if (file.count < file.size) {
khdr.count++;
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 80b1737a3369..fa63780ae76e 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -134,10 +134,10 @@ static void ima_rdwr_violation_check(struct file *file,

if (send_tomtou)
ima_add_violation(file, *pathname, iint,
- "invalid_pcr", "ToMToU");
+ "invalid_pcr", "ToMToU", ima_ns);
if (send_writers)
ima_add_violation(file, *pathname, iint,
- "invalid_pcr", "open_writers");
+ "invalid_pcr", "open_writers", ima_ns);
}

static void ima_check_active_ns(struct ima_namespace *current_ima_ns,
@@ -923,6 +923,7 @@ void process_buffer_measurement(struct inode *inode, const void *buf, int size,
goto out;
}

+ event_data.ns_id = get_ns_id(ima_ns);
ret = ima_alloc_init_template(&event_data, &entry, template);
if (ret < 0) {
audit_cause = "alloc_entry";
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c
index 5a2def40a733..945e70fafd2e 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -13,7 +13,7 @@
#include "ima.h"
#include "ima_template_lib.h"

-enum header_fields { HDR_PCR, HDR_DIGEST, HDR_TEMPLATE_NAME,
+enum header_fields { HDR_PCR, HDR_NS_ID, HDR_DIGEST, HDR_TEMPLATE_NAME,
HDR_TEMPLATE_DATA, HDR__LAST };

static struct ima_template_desc builtin_templates[] = {
@@ -362,6 +362,7 @@ int ima_restore_measurement_list(loff_t size, void *buf)
struct ima_kexec_hdr *khdr = buf;
struct ima_field_data hdr[HDR__LAST] = {
[HDR_PCR] = {.len = sizeof(u32)},
+ [HDR_NS_ID] = {.len = sizeof(u32)},
[HDR_DIGEST] = {.len = TPM_DIGEST_SIZE},
};

@@ -382,7 +383,7 @@ int ima_restore_measurement_list(loff_t size, void *buf)
khdr->buffer_size = le64_to_cpu(khdr->buffer_size);
}

- if (khdr->version != 1) {
+ if (khdr->version != get_kexec_header_version()) {
pr_err("attempting to restore a incompatible measurement list");
return -EINVAL;
}
@@ -394,11 +395,12 @@ int ima_restore_measurement_list(loff_t size, void *buf)

bitmap_zero(hdr_mask, HDR__LAST);
bitmap_set(hdr_mask, HDR_PCR, 1);
+ bitmap_set(hdr_mask, HDR_NS_ID, 1);
bitmap_set(hdr_mask, HDR_DIGEST, 1);

/*
* ima kexec buffer prefix: version, buffer size, count
- * v1 format: pcr, digest, template-name-len, template-name,
+ * v2 format: pcr, ns_id, digest, template-name-len, template-name,
* template-data-size, template-data
*/
bufendp = buf + khdr->buffer_size;
@@ -470,6 +472,8 @@ int ima_restore_measurement_list(loff_t size, void *buf)

entry->pcr = !ima_canonical_fmt ? *(hdr[HDR_PCR].data) :
le32_to_cpu(*(hdr[HDR_PCR].data));
+ entry->ns_id = !ima_canonical_fmt ? *(hdr[HDR_NS_ID].data) :
+ le32_to_cpu(*(hdr[HDR_NS_ID].data));
ret = ima_restore_measurement_entry(entry);
if (ret < 0)
break;
--
2.20.1