linux-integrity.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH v2 0/4] Virtualize PCR for Container-IMA
@ 2022-10-31  2:55 Denis Semakin
  2022-10-31  2:59 ` [RFC PATCH v2 1/4] ima: Introduce PCR virtualization for IMA namespace Denis Semakin
                   ` (4 more replies)
  0 siblings, 5 replies; 13+ messages in thread
From: Denis Semakin @ 2022-10-31  2:55 UTC (permalink / raw)
  To: linux-integrity
  Cc: artem.kuzin, konstantin.meskhidze, yusongping, hukeping,
	roberto.sassu, krzysztof.struczynski, stefanb, denis.semakin

The main goal of this series is to provide the opportunity
for retrieving integrity information from containters (namespaces)
in case of remote attestation requests and requests from another servers
querying the state of integrity for any given container.

The detailed description and architecture can be found here:
https://www.usenix.org/system/files/raid2019-luo.pdf,
this paper shows the basics for how it works in general
but did not solve the some practical issues related to memoy allocation,
TPM interaction etc.

Summary:

Let Ih is host integrity, and Ic1, Ic2, Icn the integrity
of the first, second and etc container.
Then the whole integrity of system would be:

        Ih = Ic1 + Ic2 + ... + Icn;

        where Ic1, Ic2 ... are integrity of corresponding
        containers (namespaces)

Each container integrity consists of measurement lists
and the value of virtual PCR (container PCR). vPCR = cPCR.

        Architecture scheme

        .---------.     .---------.          .---------.
        | C1 with |     | C2 with |          | Cn with |
        | IMA-ns  |     | IMA-ns  |          | IMA-ns  |
        |---------|     |---------|          |---------|
        |  vPCR1  |<--->|  vPCR2  |... <---> |  vPCRn  |
        |---------|     |---------|          |---------|
        |         |     |         |          |         |
        '---------'     '---------'          '---------'

        C1, C2, Cn - containers (with IMA namespaces)
        vPCRi - virtual PCR (in other words cPCR - container PCRs)

Each IMA namespace which belongs to container should
store its own PCR value (virtual vPCR or in other words
container PCR = cPCR = vPCR, virtual PCR)
and should perform a number of operation.

Measurement:
1. records the history value of a specific PCR (historyPCR)
   which is not used in the current system. In our prototype
   based on TPM 2.0, we choose PCR12.

2. records the digest of all cPCRs
   (cPCR - container PCR or virtual PCR that is stored for namespace).
   During measurement perform:

   tempValue := cPCRi.value xor cPCRi.secret;
   tempPCR := HASH(tempPCR || tempValue);

   Where cPCRi.value - is a value of a given namespaces, cPCRi.secret -
   random generated sequence of bytes for namespace,
   || - concatenation.

3. extends the physical PCR12 with the final tempPCR.
   PCR12 := PCR_Extend(PCR12,tempPCR)

Attestation:
When receiving this request, the IMA (and TPM) should provide
the following data:
1. the related PCR values, in our case this is PCR12

2. sendcPCRs list where sendcPCR for each namespace is calculated as:
   sendcPCRs = cPCRi.value xor cPCRi.secret
3. Measurement lists for namespace.

This work is also based on Stefan Berger's patches from:
https://github.com/stefanberger/linux-ima-namespaces

Denis Semakin (4):
  ima: Introduce PCR virtualization for IMA namespace.
  ima: Use tpm_chip from init IMA namespace.
  ima: Create vpcr file on securityfs.
  ima: Extend the real PCR12 with tempPCR value.

 security/integrity/ima/ima.h             |  13 +-
 security/integrity/ima/ima_fs.c          | 147 +++++++++++++++++++++++
 security/integrity/ima/ima_init_ima_ns.c |  21 ++++
 security/integrity/ima/ima_ns.c          |   3 +
 security/integrity/ima/ima_queue.c       |  55 +++++++++
 5 files changed, 238 insertions(+), 1 deletion(-)

v2: use sequential structure and methods for file on securityfs

-- 
2.38.GIT


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [RFC PATCH v2 1/4] ima: Introduce PCR virtualization for IMA namespace.
  2022-10-31  2:55 [RFC PATCH v2 0/4] Virtualize PCR for Container-IMA Denis Semakin
@ 2022-10-31  2:59 ` Denis Semakin
  2022-10-31  2:59 ` [RFC PATCH v2 2/4] ima: Use tpm_chip from init " Denis Semakin
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 13+ messages in thread
From: Denis Semakin @ 2022-10-31  2:59 UTC (permalink / raw)
  To: linux-integrity
  Cc: artem.kuzin, konstantin.meskhidze, yusongping, hukeping,
	roberto.sassu, krzysztof.struczynski, stefanb, denis.semakin

Define a structure for virtual PCR and corresponding
function.
This function is called when IMA extends the real PCR register
and perform following operations:

1) Extends virtual PCR value in structure vpcr_entry;
2) XOR this vPCR with random secret;
3) Store xored value in specific field.

vpcr_digest :=  HASH256(vpcr_digest || new_digest);
vpcr_temp := vpcr_digest XOR vpcr_secret;

Signed-off-by: Denis Semakin <denis.semakin@huawei.com>
---
 security/integrity/ima/ima.h             | 11 +++++
 security/integrity/ima/ima_init_ima_ns.c | 13 ++++++
 security/integrity/ima/ima_ns.c          |  3 ++
 security/integrity/ima/ima_queue.c       | 55 ++++++++++++++++++++++++
 4 files changed, 82 insertions(+)

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 7f263c9b5d31..cca984301968 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -119,6 +119,16 @@ struct ima_h_table {
 	struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE];
 };
 
+struct vpcr_entry {
+	u8 vpcr_tmp[SHA256_DIGEST_SIZE];
+	u8 vpcr_digest[SHA256_DIGEST_SIZE];
+	u8 secret[SHA256_DIGEST_SIZE];
+	struct list_head list;
+};
+
+extern struct mutex vpcr_list_mutex;
+extern struct list_head vpcr_list;
+
 struct ima_namespace {
 	unsigned long ima_ns_flags;
 /* Bit numbers for above flags; use BIT() to get flag */
@@ -165,6 +175,7 @@ struct ima_namespace {
 	 * and IMA default algo.
 	 */
 	int ima_extra_slots;
+	struct vpcr_entry vpcr;
 } __randomize_layout;
 extern struct ima_namespace init_ima_ns;
 
diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c
index 986f594dd179..d29d113a322c 100644
--- a/security/integrity/ima/ima_init_ima_ns.c
+++ b/security/integrity/ima/ima_init_ima_ns.c
@@ -6,8 +6,12 @@
  *   Stefan Berger <stefanb@linux.vnet.ibm.com>
  */
 
+#include <linux/random.h>
 #include "ima.h"
 
+LIST_HEAD(vpcr_list);
+struct mutex vpcr_list_mutex;
+
 int ima_init_namespace(struct ima_namespace *ns)
 {
 	int ret;
@@ -50,8 +54,17 @@ int ima_init_namespace(struct ima_namespace *ns)
 		ns->ima_tpm_chip = tpm_default_chip();
 		if (ns->ima_tpm_chip)
 			pr_info("No TPM chip found, activating TPM-bypass!\n");
+
+		mutex_init(&vpcr_list_mutex);
+		list_add(&ns->vpcr.list, &vpcr_list);
+	} else {
+		mutex_lock(&vpcr_list_mutex);
+		list_add_tail(&ns->vpcr.list, &vpcr_list);
+		mutex_unlock(&vpcr_list_mutex);
 	}
 
+	get_random_bytes(&ns->vpcr.secret, sizeof(ns->vpcr.secret));
+
 	set_bit(IMA_NS_ACTIVE, &ns->ima_ns_flags);
 
 	return 0;
diff --git a/security/integrity/ima/ima_ns.c b/security/integrity/ima/ima_ns.c
index 9f6ee3423d34..3f65bfbba98d 100644
--- a/security/integrity/ima/ima_ns.c
+++ b/security/integrity/ima/ima_ns.c
@@ -32,6 +32,9 @@ static void destroy_ima_ns(struct ima_namespace *ns)
 	ima_free_policy_rules(ns);
 	ima_free_ns_status_tree(ns);
 	ima_free_measurements(ns);
+	mutex_lock(&vpcr_list_mutex);
+	list_del(&ns->vpcr.list);
+	mutex_unlock(&vpcr_list_mutex);
 }
 
 void ima_free_ima_ns(struct ima_namespace *ns)
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
index b7a3f608ee9d..6f1fcd4ee307 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -17,6 +17,7 @@
 
 #include <linux/rculist.h>
 #include <linux/slab.h>
+#include <crypto/algapi.h>
 #include "ima.h"
 
 #define AUDIT_CAUSE_LEN_MAX 32
@@ -127,6 +128,55 @@ unsigned long ima_get_binary_runtime_size(struct ima_namespace *ns)
 		return ns->binary_runtime_size + sizeof(struct ima_kexec_hdr);
 }
 
+/**
+ * This function extends the virtual PCR for namespace.
+ * It calculates the HASH for given digest, store it in structure
+ * and XOR it with random secret.
+ * vpcr_digest := HASH(vpcr_digest || new_digest);
+ * vpcr_temp := vpcr_digest XOR vpcr_secret;
+ */
+
+static int ima_vpcr_extend(struct ima_namespace *ns,
+			   struct tpm_digest *digests_arg, int pcr)
+{
+	int ret = 0;
+	u8 buf[IMA_MAX_DIGEST_SIZE * 2];
+	struct {
+		struct ima_digest_data hdr;
+		char digest[IMA_MAX_DIGEST_SIZE];
+	} hash = {};
+
+	size_t dig_len = hash_digest_size[ima_hash_algo];
+	loff_t size = SHA256_DIGEST_SIZE + dig_len;
+
+	/* paranoic zeroing */
+	memset(buf, 0, sizeof(buf));
+	memset(&hash.digest, 0, sizeof(hash.digest));
+
+	/* Use SHA256 hash for vPCR */
+	hash.hdr.algo = HASH_ALGO_SHA256;
+	hash.hdr.length = SHA256_DIGEST_SIZE;
+
+	memcpy(buf, ns->vpcr.vpcr_digest, SHA256_DIGEST_SIZE);
+	memcpy(buf + SHA256_DIGEST_SIZE, &digests_arg->digest[ns->ima_hash_algo_idx],
+	       dig_len);
+
+	ret = ima_calc_buffer_hash(ns, buf, size, &hash.hdr);
+	if (ret < 0)
+		goto out;
+
+	if (mutex_lock_interruptible(&vpcr_list_mutex))
+		return -EINTR;
+
+	memcpy(ns->vpcr.vpcr_digest, &hash.digest, SHA256_DIGEST_SIZE);
+	crypto_xor_cpy(ns->vpcr.vpcr_tmp, ns->vpcr.vpcr_digest,
+		       ns->vpcr.secret, SHA256_DIGEST_SIZE);
+	mutex_unlock(&vpcr_list_mutex);
+out:
+
+	return ret;
+}
+
 static int ima_pcr_extend(struct ima_namespace *ns,
 			  struct tpm_digest *digests_arg, int pcr)
 {
@@ -135,9 +185,14 @@ static int ima_pcr_extend(struct ima_namespace *ns,
 	if (!ns->ima_tpm_chip)
 		return result;
 
+	result = ima_vpcr_extend(ns, digests_arg, pcr);
+	if (result != 0)
+		pr_err("Error extending vPCR, result: %d\n", result);
+
 	result = tpm_pcr_extend(ns->ima_tpm_chip, pcr, digests_arg);
 	if (result != 0)
 		pr_err("Error Communicating to TPM chip, result: %d\n", result);
+
 	return result;
 }
 
-- 
2.38.GIT


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFC PATCH v2 2/4] ima: Use tpm_chip from init IMA namespace.
  2022-10-31  2:55 [RFC PATCH v2 0/4] Virtualize PCR for Container-IMA Denis Semakin
  2022-10-31  2:59 ` [RFC PATCH v2 1/4] ima: Introduce PCR virtualization for IMA namespace Denis Semakin
@ 2022-10-31  2:59 ` Denis Semakin
  2022-10-31  3:00 ` [RFC PATCH v2 3/4] ima: Create vpcr file on securityfs Denis Semakin
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 13+ messages in thread
From: Denis Semakin @ 2022-10-31  2:59 UTC (permalink / raw)
  To: linux-integrity
  Cc: artem.kuzin, konstantin.meskhidze, yusongping, hukeping,
	roberto.sassu, krzysztof.struczynski, stefanb, denis.semakin

For now a child namespace uses the same tpm chip descriptor
from init namespace.

Signed-off-by: Denis Semakin <denis.semakin@huawei.com>
---
 security/integrity/ima/ima_init_ima_ns.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c
index d29d113a322c..8093c61697a4 100644
--- a/security/integrity/ima/ima_init_ima_ns.c
+++ b/security/integrity/ima/ima_init_ima_ns.c
@@ -58,6 +58,14 @@ int ima_init_namespace(struct ima_namespace *ns)
 		mutex_init(&vpcr_list_mutex);
 		list_add(&ns->vpcr.list, &vpcr_list);
 	} else {
+		/**
+		 * Here we just assign tpm_chip from init_ima_ns
+		 * with new IMA namespace.
+		 * In future a new API should be used I think
+		 * Stefan's ima_ns_set_tpm_chip() and etc. to get
+		 * TPM chip descriptor and provider.
+		 */
+		ns->ima_tpm_chip = init_ima_ns.ima_tpm_chip;
 		mutex_lock(&vpcr_list_mutex);
 		list_add_tail(&ns->vpcr.list, &vpcr_list);
 		mutex_unlock(&vpcr_list_mutex);
-- 
2.38.GIT


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFC PATCH v2 3/4] ima: Create vpcr file on securityfs.
  2022-10-31  2:55 [RFC PATCH v2 0/4] Virtualize PCR for Container-IMA Denis Semakin
  2022-10-31  2:59 ` [RFC PATCH v2 1/4] ima: Introduce PCR virtualization for IMA namespace Denis Semakin
  2022-10-31  2:59 ` [RFC PATCH v2 2/4] ima: Use tpm_chip from init " Denis Semakin
@ 2022-10-31  3:00 ` Denis Semakin
  2022-10-31  3:00 ` [RFC PATCH v2 4/4] ima: Extend the real PCR12 with tempPCR value Denis Semakin
  2023-01-27  8:19 ` [RFC PATCH v1 0/3] ima: vPCR debug/security Ilya Hanov
  4 siblings, 0 replies; 13+ messages in thread
From: Denis Semakin @ 2022-10-31  3:00 UTC (permalink / raw)
  To: linux-integrity
  Cc: artem.kuzin, konstantin.meskhidze, yusongping, hukeping,
	roberto.sassu, krzysztof.struczynski, stefanb, denis.semakin

This file contains information of all virtual PCR registers
that is extended by kernel when the real PCR extension operation
is occurred.

It provides the values of cPCRs and PCR12 register.
During reading operation it calculates the final value of
of cPCRs, store it in temp_vpcr_hash structure.

Then this tempPCR value is used to extend the real PCR12 register.

E.g.:
$ sudo cat /sys/kernel/security/ima/vpcr
cPCR:  ab3c1c3ae0581168284738f01470d7be64b9a220bb4b7030b879ffc669a2e4b6
PCR12: 73b7267c1e9b74c573a6e243af1d574bf6141be162a51e6aef4cfc15c7550963

Signed-off-by: Denis Semakin <denis.semakin@huawei.com>
---
 security/integrity/ima/ima_fs.c | 72 +++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index bb4c3d4493e2..d9e91b9f1564 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -25,6 +25,8 @@
 
 #include "ima.h"
 
+extern struct list_head vpcr_list;
+
 bool ima_canonical_fmt;
 static int __init default_canonical_fmt_setup(char *str)
 {
@@ -538,6 +540,65 @@ static const struct file_operations ima_active_ops = {
 	.write = ima_write_active,
 };
 
+static void *vpcr_start(struct seq_file *m, loff_t *pos)
+{
+	int err;
+
+	err = mutex_lock_interruptible(&vpcr_list_mutex);
+	if (err)
+		return ERR_PTR(err);
+
+	return seq_list_start(&vpcr_list, *pos);
+}
+
+static void *vpcr_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	return seq_list_next(v, &vpcr_list, pos);
+}
+
+static void vpcr_stop(struct seq_file *m, void *v)
+{
+	mutex_unlock(&vpcr_list_mutex);
+}
+
+static int vpcr_show(struct seq_file *m, void *v)
+{
+	struct vpcr_entry *vpcr = list_entry(v, struct vpcr_entry, list);
+
+	ima_putc(m, "cPCR: ", strlen("cPCR: "));
+	ima_putc(m, vpcr->vpcr_tmp, SHA256_DIGEST_SIZE);
+
+	return 0;
+}
+
+const struct seq_operations vpcr_seq_ops = {
+	.start = vpcr_start,
+	.next  = vpcr_next,
+	.stop  = vpcr_stop,
+	.show  = vpcr_show,
+};
+
+static int ima_vpcr_open(struct inode *inode, struct file *filp)
+{
+	struct user_namespace *user_ns = ima_user_ns_from_file(filp);
+	struct ima_namespace *ns = ima_ns_from_file(filp);
+
+	if (!ns->ima_tpm_chip)
+		return -ENODEV;
+
+	if (!ns_is_active(ns) || !mac_admin_ns_capable(user_ns))
+		return -EACCES;
+
+	return seq_open(filp, &vpcr_seq_ops);
+}
+
+static const struct file_operations ima_vpcr_fops = {
+	.open = ima_vpcr_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
 int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root)
 {
 	struct ima_namespace *ns = ima_ns_from_user_ns(user_ns);
@@ -549,6 +610,7 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root)
 	struct dentry *runtime_measurements_count = NULL;
 	struct dentry *violations = NULL;
 	struct dentry *active = NULL;
+	struct dentry *vpcr = NULL;
 	int ret;
 
 	/*
@@ -625,6 +687,15 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root)
 		goto out;
 	}
 
+	if (ns == &init_ima_ns) {
+		vpcr = securityfs_create_file("vpcr", S_IRUSR | S_IRGRP,
+					      ima_dir, NULL, &ima_vpcr_fops);
+		if (IS_ERR(vpcr)) {
+			ret = PTR_ERR(vpcr);
+			goto out;
+		}
+	}
+
 	if (!ns->ima_policy_removed) {
 		ns->ima_policy =
 		    securityfs_create_file("policy", POLICY_FILE_FLAGS,
@@ -652,6 +723,7 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root)
 
 	return 0;
 out:
+	securityfs_remove(vpcr);
 	securityfs_remove(active);
 	securityfs_remove(ns->ima_policy);
 	securityfs_remove(violations);
-- 
2.38.GIT


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFC PATCH v2 4/4] ima: Extend the real PCR12 with tempPCR value.
  2022-10-31  2:55 [RFC PATCH v2 0/4] Virtualize PCR for Container-IMA Denis Semakin
                   ` (2 preceding siblings ...)
  2022-10-31  3:00 ` [RFC PATCH v2 3/4] ima: Create vpcr file on securityfs Denis Semakin
@ 2022-10-31  3:00 ` Denis Semakin
  2023-01-27  8:19 ` [RFC PATCH v1 0/3] ima: vPCR debug/security Ilya Hanov
  4 siblings, 0 replies; 13+ messages in thread
From: Denis Semakin @ 2022-10-31  3:00 UTC (permalink / raw)
  To: linux-integrity
  Cc: artem.kuzin, konstantin.meskhidze, yusongping, hukeping,
	roberto.sassu, krzysztof.struczynski, stefanb, denis.semakin

For each namespace do this calculation:
        tempPCR := HASH(tempPCR || tempValue);

And finally extend the real PCR12P:
        PCR12 := PCR_Extend(PCR12,tempPCR);

Then read the PCR12 and return its value to user-space.

Signed-off-by: Denis Semakin <denis.semakin@huawei.com>
---
 security/integrity/ima/ima.h    |  2 +-
 security/integrity/ima/ima_fs.c | 83 +++++++++++++++++++++++++++++++--
 2 files changed, 80 insertions(+), 5 deletions(-)

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index cca984301968..02d7b66098ca 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -27,7 +27,7 @@
 
 enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_BINARY_NO_FIELD_LEN,
 		     IMA_SHOW_BINARY_OLD_STRING_FMT, IMA_SHOW_ASCII };
-enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 };
+enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10, TPM_PCR12 = 12 };
 
 /* digest size for IMA, fits SHA1 or MD5 */
 #define IMA_DIGEST_SIZE		SHA1_DIGEST_SIZE
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index d9e91b9f1564..8e517be7bba2 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -26,6 +26,7 @@
 #include "ima.h"
 
 extern struct list_head vpcr_list;
+static bool vpcr_mutex_acquired;
 
 bool ima_canonical_fmt;
 static int __init default_canonical_fmt_setup(char *str)
@@ -540,13 +541,28 @@ static const struct file_operations ima_active_ops = {
 	.write = ima_write_active,
 };
 
+struct {
+	struct ima_digest_data hdr;
+	char digest[SHA256_DIGEST_SIZE];
+} temp_vpcr_hash = {
+	.hdr = {
+		.algo = HASH_ALGO_SHA256,
+		.length = SHA256_DIGEST_SIZE,
+	},
+};
+
 static void *vpcr_start(struct seq_file *m, loff_t *pos)
 {
 	int err;
 
-	err = mutex_lock_interruptible(&vpcr_list_mutex);
-	if (err)
-		return ERR_PTR(err);
+	if (*pos == 0) {
+		err = mutex_lock_interruptible(&vpcr_list_mutex);
+		if (err) {
+			vpcr_mutex_acquired = false;
+			return ERR_PTR(err);
+		}
+		vpcr_mutex_acquired = true;
+	}
 
 	return seq_list_start(&vpcr_list, *pos);
 }
@@ -558,17 +574,76 @@ static void *vpcr_next(struct seq_file *m, void *v, loff_t *pos)
 
 static void vpcr_stop(struct seq_file *m, void *v)
 {
+	int j;
+	int ret;
+	struct tpm_chip *tpm_chip;
+	struct tpm_digest *temp_tpm;
+	struct tpm_digest pcr12_digest;
+	struct ima_namespace *curr_ns = ima_ns_from_file(m->file);
+
+	if (!vpcr_mutex_acquired)
+		return;
+
+	tpm_chip = curr_ns->ima_tpm_chip;
+	pcr12_digest.alg_id = TPM_ALG_SHA256;
+
+	temp_tpm = kcalloc(tpm_chip->nr_allocated_banks,
+			   sizeof(*curr_ns->digests), GFP_NOFS);
+	if (!temp_tpm)
+		goto ex;
+
+	for (j = 0; j < tpm_chip->nr_allocated_banks; j++) {
+		temp_tpm[j].alg_id = tpm_chip->allocated_banks[j].alg_id;
+
+
+		if (temp_tpm[j].alg_id == TPM_ALG_SHA256)
+			memcpy(&temp_tpm[j].digest, &temp_vpcr_hash.digest,
+			       SHA256_DIGEST_SIZE);
+		else
+			memset(&temp_tpm[j].digest, 0,
+			       hash_digest_size[tpm_chip->allocated_banks[j].crypto_id]);
+	}
+
+	ret = tpm_pcr_extend(tpm_chip, TPM_PCR12, temp_tpm);
+	if (ret != 0) {
+		seq_puts(m, "TPM extend error\n");
+		goto free_mem;
+	}
+
+	ret = tpm_pcr_read(tpm_chip, TPM_PCR12, &pcr12_digest);
+	if (ret != 0) {
+		seq_puts(m, "TPM read error\n");
+		goto free_mem;
+	}
+
+	ima_putc(m, "PCR12: ", strlen("PCR12: "));
+	ima_putc(m, pcr12_digest.digest, SHA256_DIGEST_SIZE);
+
+free_mem:
+	kfree(temp_tpm);
+ex:
 	mutex_unlock(&vpcr_list_mutex);
+	vpcr_mutex_acquired = false;
 }
 
 static int vpcr_show(struct seq_file *m, void *v)
 {
+	int ret = 0;
+	u8 buf[IMA_MAX_DIGEST_SIZE * 2] = {0};
 	struct vpcr_entry *vpcr = list_entry(v, struct vpcr_entry, list);
+	struct ima_namespace *curr_ns = container_of(vpcr, struct ima_namespace,
+						     vpcr);
 
 	ima_putc(m, "cPCR: ", strlen("cPCR: "));
 	ima_putc(m, vpcr->vpcr_tmp, SHA256_DIGEST_SIZE);
 
-	return 0;
+	memcpy(buf, &temp_vpcr_hash.digest, SHA256_DIGEST_SIZE);
+	memcpy(buf + SHA256_DIGEST_SIZE, vpcr->vpcr_tmp,
+	       SHA256_DIGEST_SIZE);
+
+	ret = ima_calc_buffer_hash(curr_ns, buf, SHA256_DIGEST_SIZE * 2,
+				   &temp_vpcr_hash.hdr);
+	return ret;
 }
 
 const struct seq_operations vpcr_seq_ops = {
-- 
2.38.GIT


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFC PATCH v1 0/3] ima: vPCR debug/security
  2022-10-31  2:55 [RFC PATCH v2 0/4] Virtualize PCR for Container-IMA Denis Semakin
                   ` (3 preceding siblings ...)
  2022-10-31  3:00 ` [RFC PATCH v2 4/4] ima: Extend the real PCR12 with tempPCR value Denis Semakin
@ 2023-01-27  8:19 ` Ilya Hanov
  2023-01-27  8:19   ` [RFC PATCH v1 1/3] ima: Add a UUID value for each vPCR Ilya Hanov
                     ` (4 more replies)
  4 siblings, 5 replies; 13+ messages in thread
From: Ilya Hanov @ 2023-01-27  8:19 UTC (permalink / raw)
  To: linux-integrity
  Cc: yusongping, hukeping, denis.semakin, artem.kuzin,
	konstantin.meskhidze, ilya.hanov

1. UUID value for each vPCR.

	There's no way to identify vPCR values reading
	/sys/kernel/security/ima/vpcr. It shows only vPCR values (which are in
	turn XORed with vPCR.secret, next cPCR = vPCR; vPCR value means vPCR.value XOR
	vPCR.secret), so imagine a situation when a server has
	hundreds of containers. In order to identify them it needs to keep in mind the
	order vPCR is created in. To solve this problem UUID values were added
	for each vPCR. They appear in the following form -
	"<cPCR-pfx><UUID-value><cPCR-val>...":

	# xxd /sys/kernel/security/ima/binary_vpcr
	00000000: 6350 4352 3a20 c57f 9efc 7149 4df5 a1b3  cPCR: ....qIM...
	00000010: 66fb 03db 4006 8780 7247 57d7 96e2 1b24  f...@...rGW....$
	00000020: 2f9b c891 2c09 05d2 4dfb 2011 a74f d1e9  /...,...M. ..O..
	00000030: 1134 b247 bf80 .... .... .... .... ....  ................
	(output truncated)

	6350 4352 3a20                          - cPCR prefix. 6  bytes long.
	c57f 9efc 7149 4df5 a1b3 66fb 03db 4006 - UUID value.  16 bytes long.
	8780 7247 57d7 96e2 1b24 2f9b c891 .... - cPCR value.  32 bytes long.
	...

2. ascii_vpcr pseudo-file for sysadmins.

	Dump cPCR values in human-readable format. This may add some flexibility for
	debugging. ima/vpcr also was renamed to ima/binary_vpcr. When something went wrong 
	System Administrator is able to see cPCR values without 
	doing PCR_Extend operations (for PCR12), this invokes only PCR_Read. ascii_vpcr
	has the same format as binary_vpcr, but can be read by humans:

	# cat /sys/kernel/security/ima/ascii_vpcr
	cPCR: c57f9efc-7149-4df5-a1b3-66fb03db4006     8780724757d796e21b242f9bc8912c0905d24dfb2011a74fd1e91134b247bf80
	(output truncated)

3. TPM RNG for vPCR.secret if it's presented.

	It adds some security because vPCR.secret will be generated using only
	TPM Hardware (as a Root Of Trust) without any Software
	Implementations. If there's no shipped TPM for a system - then use
	Software get_random_bytes(). To identify whether a system has been
	shipped with TPM RNG or not the code checks for CONFIG_HW_RANDOM_TPM.

Note: UUID values are always generated using get_random_bytes under the
hood. Here using Hardware is optional because UUIDs are not used inside
TPM like cPCRs (PCR_Extend{PCR12}).

Ilya Hanov (3):
  ima: Add a UUID value for each vPCR
  ima: ascii_vpcr pseudo-file for sysadmins
  ima: Use TPM RNG for vPCR.secret if it's presented.

 security/integrity/ima/ima.h             |   2 +
 security/integrity/ima/ima_fs.c          | 130 ++++++++++++++++++++---
 security/integrity/ima/ima_init_ima_ns.c |  12 +++
 3 files changed, 128 insertions(+), 16 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [RFC PATCH v1 1/3] ima: Add a UUID value for each vPCR
  2023-01-27  8:19 ` [RFC PATCH v1 0/3] ima: vPCR debug/security Ilya Hanov
@ 2023-01-27  8:19   ` Ilya Hanov
  2023-01-27  8:19   ` [RFC PATCH v1 2/3] ima: ascii_vpcr pseudo-file for sysadmins Ilya Hanov
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 13+ messages in thread
From: Ilya Hanov @ 2023-01-27  8:19 UTC (permalink / raw)
  To: linux-integrity
  Cc: yusongping, hukeping, denis.semakin, artem.kuzin,
	konstantin.meskhidze, ilya.hanov

Signed-off-by: Ilya Hanov <ilya.hanov@huawei-partners.com>
---
 security/integrity/ima/ima.h             | 2 ++
 security/integrity/ima/ima_fs.c          | 1 +
 security/integrity/ima/ima_init_ima_ns.c | 1 +
 3 files changed, 4 insertions(+)

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 91da4dd11390..a717be9685ed 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -14,6 +14,7 @@
 #define __LINUX_IMA_H
 
 #include <linux/types.h>
+#include <linux/uuid.h>
 #include <linux/crypto.h>
 #include <linux/fs.h>
 #include <linux/security.h>
@@ -176,6 +177,7 @@ struct ima_namespace {
 	 */
 	int ima_extra_slots;
 	struct vpcr_entry vpcr;
+	uuid_t uuid;
 } __randomize_layout;
 extern struct ima_namespace init_ima_ns;
 
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index d2dc7749949b..cf9164d31599 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -635,6 +635,7 @@ static int vpcr_show(struct seq_file *m, void *v)
 						     vpcr);
 
 	ima_putc(m, "cPCR: ", strlen("cPCR: "));
+	ima_putc(m, curr_ns->uuid.b, UUID_SIZE);
 	ima_putc(m, vpcr->vpcr_tmp, SHA256_DIGEST_SIZE);
 
 	memcpy(buf, &temp_vpcr_hash.digest, SHA256_DIGEST_SIZE);
diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c
index f22062b70977..33e6a18dc560 100644
--- a/security/integrity/ima/ima_init_ima_ns.c
+++ b/security/integrity/ima/ima_init_ima_ns.c
@@ -71,6 +71,7 @@ int ima_init_namespace(struct ima_namespace *ns)
 		mutex_unlock(&vpcr_list_mutex);
 	}
 
+	generate_random_uuid(ns->uuid.b);
 	get_random_bytes(&ns->vpcr.secret, sizeof(ns->vpcr.secret));
 
 	set_bit(IMA_NS_ACTIVE, &ns->ima_ns_flags);
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFC PATCH v1 2/3] ima: ascii_vpcr pseudo-file for sysadmins
  2023-01-27  8:19 ` [RFC PATCH v1 0/3] ima: vPCR debug/security Ilya Hanov
  2023-01-27  8:19   ` [RFC PATCH v1 1/3] ima: Add a UUID value for each vPCR Ilya Hanov
@ 2023-01-27  8:19   ` Ilya Hanov
  2023-01-27  8:19   ` [RFC PATCH v1 3/3] ima: Use TPM RNG for vPCR.secret if it's presented Ilya Hanov
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 13+ messages in thread
From: Ilya Hanov @ 2023-01-27  8:19 UTC (permalink / raw)
  To: linux-integrity
  Cc: yusongping, hukeping, denis.semakin, artem.kuzin,
	konstantin.meskhidze, ilya.hanov

Dump cPCR values in human-readable format. This may add some flexibility for
debugging. ima/vpcr also was renamed to ima/binary_vpcr. When something went wrong
System Administrator is able to see cPCR values without
doing PCR_Extend operations (for PCR12), this invokes only PCR_Read. ascii_vpcr
has the same format as binary_vpcr, but can be read by humans:

$ sudo cat /sys/kernel/security/ima/ascii_vpcr
cPCR: c57f9efc-7149-4df5-a1b3-66fb03db4006 8780724757d796e21b242f9bc8912c0905d24dfb2011a74fd1e91134b247bf80
(output truncated)

Signed-off-by: Ilya Hanov <ilya.hanov@huawei-partners.com>
---
 security/integrity/ima/ima_fs.c | 129 ++++++++++++++++++++++++++++----
 1 file changed, 113 insertions(+), 16 deletions(-)

diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index cf9164d31599..2ebbdfa708df 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -572,7 +572,7 @@ static void *vpcr_next(struct seq_file *m, void *v, loff_t *pos)
 	return seq_list_next(v, &vpcr_list, pos);
 }
 
-static void vpcr_stop(struct seq_file *m, void *v)
+static void binary_vpcr_stop(struct seq_file *m, void *v)
 {
 	int j;
 	int ret;
@@ -585,8 +585,10 @@ static void vpcr_stop(struct seq_file *m, void *v)
 		return;
 
 	tpm_chip = curr_ns->ima_tpm_chip;
-	pcr12_digest.alg_id = TPM_ALG_SHA256;
+	if (!tpm_chip)
+		goto ex;
 
+	pcr12_digest.alg_id = TPM_ALG_SHA256;
 	temp_tpm = kcalloc(tpm_chip->nr_allocated_banks,
 			   sizeof(*curr_ns->digests), GFP_NOFS);
 	if (!temp_tpm)
@@ -626,7 +628,7 @@ static void vpcr_stop(struct seq_file *m, void *v)
 	mutex_unlock(&vpcr_list_mutex);
 }
 
-static int vpcr_show(struct seq_file *m, void *v)
+static int binary_vpcr_show(struct seq_file *m, void *v)
 {
 	int ret = 0;
 	u8 buf[IMA_MAX_DIGEST_SIZE * 2] = {0};
@@ -647,14 +649,96 @@ static int vpcr_show(struct seq_file *m, void *v)
 	return ret;
 }
 
-const struct seq_operations vpcr_seq_ops = {
+const struct seq_operations binary_vpcr_seq_ops = {
+	.start = vpcr_start,
+	.next  = vpcr_next,
+	.stop  = binary_vpcr_stop,
+	.show  = binary_vpcr_show,
+};
+
+static int ima_binary_vpcr_open(struct inode *inode, struct file *filp)
+{
+	struct user_namespace *user_ns = ima_user_ns_from_file(filp);
+	struct ima_namespace *ns = ima_ns_from_file(filp);
+
+	if (!ns->ima_tpm_chip)
+		return -ENODEV;
+
+	if (!ns_is_active(ns) || !mac_admin_ns_capable(user_ns))
+		return -EACCES;
+
+	return seq_open(filp, &binary_vpcr_seq_ops);
+}
+
+static const struct file_operations ima_binary_vpcr_fops = {
+	.open = ima_binary_vpcr_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+static void ascii_vpcr_stop(struct seq_file *m, void *v)
+{
+	int ret;
+	struct tpm_chip *tpm_chip;
+	struct tpm_digest pcr12_digest;
+	struct ima_namespace *curr_ns = ima_ns_from_file(m->file);
+
+	if (!vpcr_mutex_acquired)
+		return;
+
+	tpm_chip = curr_ns->ima_tpm_chip;
+	if (!tpm_chip)
+		goto ex;
+
+	pcr12_digest.alg_id = TPM_ALG_SHA256;
+	ret = tpm_pcr_read(tpm_chip, TPM_PCR12, &pcr12_digest);
+	if (ret != 0) {
+		seq_puts(m, "TPM read error\n");
+		goto ex;
+	}
+
+	/* 1st: PCR12 Prefix */
+	seq_printf(m, "\nPCR12: ");
+
+	/* 2nd: PCR12 Hash */
+	seq_printf(m, "%*phN", SHA256_DIGEST_SIZE, pcr12_digest.digest);
+	seq_printf(m, "\n");
+ex:
+	WRITE_ONCE(vpcr_mutex_acquired, false);
+	mutex_unlock(&vpcr_list_mutex);
+}
+
+static int ascii_vpcr_show(struct seq_file *m, void *v)
+{
+	struct vpcr_entry *vpcr = list_entry(v, struct vpcr_entry, list);
+	struct ima_namespace *curr_ns = container_of(vpcr, struct ima_namespace,
+						     vpcr);
+
+	if (!vpcr)
+		return -ENOENT;
+
+	/* 1st: cPCR Prefix */
+	seq_printf(m, "cPCR: ");
+
+	/* 2nd: cPCR UUID Value */
+	seq_printf(m, "%pUb ", &curr_ns->uuid);
+
+	/* 3rd: cPCR.Value XOR cPCR.Secret */
+	seq_printf(m, "%*phN", SHA256_DIGEST_SIZE, vpcr->vpcr_tmp);
+	seq_printf(m, "\n");
+
+	return 0;
+}
+
+const struct seq_operations ascii_vpcr_seq_ops = {
 	.start = vpcr_start,
 	.next  = vpcr_next,
-	.stop  = vpcr_stop,
-	.show  = vpcr_show,
+	.stop  = ascii_vpcr_stop,
+	.show  = ascii_vpcr_show,
 };
 
-static int ima_vpcr_open(struct inode *inode, struct file *filp)
+static int ima_ascii_vpcr_open(struct inode *inode, struct file *filp)
 {
 	struct user_namespace *user_ns = ima_user_ns_from_file(filp);
 	struct ima_namespace *ns = ima_ns_from_file(filp);
@@ -665,11 +749,11 @@ static int ima_vpcr_open(struct inode *inode, struct file *filp)
 	if (!ns_is_active(ns) || !mac_admin_ns_capable(user_ns))
 		return -EACCES;
 
-	return seq_open(filp, &vpcr_seq_ops);
+	return seq_open(filp, &ascii_vpcr_seq_ops);
 }
 
-static const struct file_operations ima_vpcr_fops = {
-	.open = ima_vpcr_open,
+static const struct file_operations ima_ascii_vpcr_fops = {
+	.open = ima_ascii_vpcr_open,
 	.read = seq_read,
 	.llseek = seq_lseek,
 	.release = seq_release,
@@ -686,7 +770,8 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root)
 	struct dentry *runtime_measurements_count = NULL;
 	struct dentry *violations = NULL;
 	struct dentry *active = NULL;
-	struct dentry *vpcr = NULL;
+	struct dentry *binary_vpcr = NULL;
+	struct dentry *ascii_vpcr = NULL;
 	int ret;
 
 	/*
@@ -764,10 +849,21 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root)
 	}
 
 	if (ns == &init_ima_ns) {
-		vpcr = securityfs_create_file("vpcr", S_IRUSR | S_IRGRP,
-					      ima_dir, NULL, &ima_vpcr_fops);
-		if (IS_ERR(vpcr)) {
-			ret = PTR_ERR(vpcr);
+		binary_vpcr =
+		    securityfs_create_file("binary_vpcr",
+					    S_IRUSR | S_IRGRP, ima_dir, NULL,
+					    &ima_binary_vpcr_fops);
+		if (IS_ERR(binary_vpcr)) {
+			ret = PTR_ERR(binary_vpcr);
+			goto out;
+		}
+
+		ascii_vpcr =
+		    securityfs_create_file("ascii_vpcr",
+					    S_IRUSR | S_IRGRP, ima_dir, NULL,
+					    &ima_ascii_vpcr_fops);
+		if (IS_ERR(ascii_vpcr)) {
+			ret = PTR_ERR(ascii_vpcr);
 			goto out;
 		}
 	}
@@ -799,7 +895,8 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root)
 
 	return 0;
 out:
-	securityfs_remove(vpcr);
+	securityfs_remove(ascii_vpcr);
+	securityfs_remove(binary_vpcr);
 	securityfs_remove(active);
 	securityfs_remove(ns->ima_policy);
 	securityfs_remove(violations);
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFC PATCH v1 3/3] ima: Use TPM RNG for vPCR.secret if it's presented.
  2023-01-27  8:19 ` [RFC PATCH v1 0/3] ima: vPCR debug/security Ilya Hanov
  2023-01-27  8:19   ` [RFC PATCH v1 1/3] ima: Add a UUID value for each vPCR Ilya Hanov
  2023-01-27  8:19   ` [RFC PATCH v1 2/3] ima: ascii_vpcr pseudo-file for sysadmins Ilya Hanov
@ 2023-01-27  8:19   ` Ilya Hanov
  2023-03-29  8:58   ` [RFC PATCH v1 0/1] ima: obtain child measurement list from init namespace Denis Semakin
  2023-03-29  9:03   ` [RFC PATCH v1 1/1] " Denis Semakin
  4 siblings, 0 replies; 13+ messages in thread
From: Ilya Hanov @ 2023-01-27  8:19 UTC (permalink / raw)
  To: linux-integrity
  Cc: yusongping, hukeping, denis.semakin, artem.kuzin,
	konstantin.meskhidze, ilya.hanov

Signed-off-by: Ilya Hanov <ilya.hanov@huawei-partners.com>
---
 security/integrity/ima/ima_init_ima_ns.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c
index 33e6a18dc560..5ce3e42b6caa 100644
--- a/security/integrity/ima/ima_init_ima_ns.c
+++ b/security/integrity/ima/ima_init_ima_ns.c
@@ -6,7 +6,11 @@
  *   Stefan Berger <stefanb@linux.vnet.ibm.com>
  */
 
+#ifdef CONFIG_HW_RANDOM_TPM
+#include <linux/tpm.h>
+#else /* !CONFIG_HW_RANDOM_TPM */
 #include <linux/random.h>
+#endif /* CONFIG_HW_RANDOM_TPM */
 #include "ima.h"
 
 LIST_HEAD(vpcr_list);
@@ -72,7 +76,14 @@ int ima_init_namespace(struct ima_namespace *ns)
 	}
 
 	generate_random_uuid(ns->uuid.b);
+#ifdef CONFIG_HW_RANDOM_TPM
+	ret = tpm_get_random(ns->ima_tpm_chip, ns->vpcr.secret,
+			     sizeof(ns->vpcr.secret));
+	if (ret < 0)
+		goto err_destroy_cache;
+#else /* !CONFIG_HW_RANDOM_TPM */
 	get_random_bytes(&ns->vpcr.secret, sizeof(ns->vpcr.secret));
+#endif /* CONFIG_HW_RANDOM_TPM */
 
 	set_bit(IMA_NS_ACTIVE, &ns->ima_ns_flags);
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFC PATCH v1 0/1] ima: obtain child measurement list from init namespace
  2023-01-27  8:19 ` [RFC PATCH v1 0/3] ima: vPCR debug/security Ilya Hanov
                     ` (2 preceding siblings ...)
  2023-01-27  8:19   ` [RFC PATCH v1 3/3] ima: Use TPM RNG for vPCR.secret if it's presented Ilya Hanov
@ 2023-03-29  8:58   ` Denis Semakin
  2023-05-02 13:36     ` Stefan Berger
  2023-03-29  9:03   ` [RFC PATCH v1 1/1] " Denis Semakin
  4 siblings, 1 reply; 13+ messages in thread
From: Denis Semakin @ 2023-03-29  8:58 UTC (permalink / raw)
  To: linux-integrity
  Cc: artem.kuzin, konstantin.meskhidze, ilya.hanov, yusongping,
	hukeping, denis.semakin

This patch allows to read measurement lists of child namespaces
form init IMA namespace in order to obtain the values of hashes
to perform operations and procedures of remote attestation.

Denis Semakin (1):
  ima: obtain child measurement list from init namespace

 security/integrity/ima/ima.h             |   1 +
 security/integrity/ima/ima_fs.c          | 164 ++++++++++++++++++++++-
 security/integrity/ima/ima_init_ima_ns.c |   2 +
 security/integrity/ima/ima_ns.c          |  31 +++++
 4 files changed, 193 insertions(+), 5 deletions(-)

-- 
2.38.GIT


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [RFC PATCH v1 1/1] ima: obtain child measurement list from init namespace
  2023-01-27  8:19 ` [RFC PATCH v1 0/3] ima: vPCR debug/security Ilya Hanov
                     ` (3 preceding siblings ...)
  2023-03-29  8:58   ` [RFC PATCH v1 0/1] ima: obtain child measurement list from init namespace Denis Semakin
@ 2023-03-29  9:03   ` Denis Semakin
  4 siblings, 0 replies; 13+ messages in thread
From: Denis Semakin @ 2023-03-29  9:03 UTC (permalink / raw)
  To: linux-integrity
  Cc: artem.kuzin, konstantin.meskhidze, ilya.hanov, yusongping,
	hukeping, denis.semakin

Signed-off-by: Denis Semakin <denis.semakin@huawei.com>
---
 security/integrity/ima/ima.h             |   1 +
 security/integrity/ima/ima_fs.c          | 164 ++++++++++++++++++++++-
 security/integrity/ima/ima_init_ima_ns.c |   2 +
 security/integrity/ima/ima_ns.c          |  31 +++++
 4 files changed, 193 insertions(+), 5 deletions(-)

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index a717be9685ed..b46d6944f6ca 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -178,6 +178,7 @@ struct ima_namespace {
 	int ima_extra_slots;
 	struct vpcr_entry vpcr;
 	uuid_t uuid;
+	struct dentry *parent_dentry;
 } __randomize_layout;
 extern struct ima_namespace init_ima_ns;
 
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 570e5d00a454..78d9f967e1f4 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -24,6 +24,7 @@
 #include <linux/ima.h>
 
 #include "ima.h"
+#define INUM_BUF_SIZE	16
 
 extern struct list_head vpcr_list;
 static bool vpcr_mutex_acquired;
@@ -84,9 +85,8 @@ static const struct file_operations ima_measurements_count_ops = {
 };
 
 /* returns pointer to hlist_node */
-static void *ima_measurements_start(struct seq_file *m, loff_t *pos)
+static void *__ima_measurements_start(struct ima_namespace *ns, loff_t *pos)
 {
-	struct ima_namespace *ns = ima_ns_from_file(m->file);
 	loff_t l = *pos;
 	struct ima_queue_entry *qe;
 
@@ -102,9 +102,16 @@ static void *ima_measurements_start(struct seq_file *m, loff_t *pos)
 	return NULL;
 }
 
-static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
+static void *ima_measurements_start(struct seq_file *m, loff_t *pos)
 {
 	struct ima_namespace *ns = ima_ns_from_file(m->file);
+
+	return __ima_measurements_start(ns, pos);
+}
+
+static void *__ima_measurements_next(struct ima_namespace *ns, void *v,
+				     loff_t *pos)
+{
 	struct ima_queue_entry *qe = v;
 
 	/* lock protects when reading beyond last element
@@ -118,6 +125,13 @@ static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
 	return (&qe->later == &ns->ima_measurements) ? NULL : qe;
 }
 
+static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	struct ima_namespace *ns = ima_ns_from_file(m->file);
+
+	return __ima_measurements_next(ns, v, pos);
+}
+
 static void ima_measurements_stop(struct seq_file *m, void *v)
 {
 }
@@ -237,10 +251,10 @@ void ima_print_digest(struct seq_file *m, u8 *digest, u32 size)
 }
 
 /* print in ascii */
-static int ima_ascii_measurements_show(struct seq_file *m, void *v)
+static int __ima_ascii_measurements_show(struct ima_namespace *ns,
+					 struct seq_file *m, void *v)
 {
 	/* the list never shrinks, so we don't need a lock here */
-	struct ima_namespace *ns = ima_ns_from_file(m->file);
 	struct ima_queue_entry *qe = v;
 	struct ima_template_entry *e;
 	char *template_name;
@@ -276,6 +290,13 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v)
 	return 0;
 }
 
+static int ima_ascii_measurements_show(struct seq_file *m, void *v)
+{
+	struct ima_namespace *ns = ima_ns_from_file(m->file);
+
+	return __ima_ascii_measurements_show(ns, m, v);
+}
+
 static const struct seq_operations ima_ascii_measurements_seqops = {
 	.start = ima_measurements_start,
 	.next = ima_measurements_next,
@@ -706,6 +727,94 @@ static const struct file_operations ima_ascii_vpcr_fops = {
 	.release = seq_release,
 };
 
+static void *child_ns_measure_start(struct seq_file *m, loff_t *pos)
+{
+	struct ima_namespace *ns = (struct ima_namespace *)m->private;
+
+	return __ima_measurements_start(ns, pos);
+}
+
+static void *child_ns_measure_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	struct ima_namespace *ns = (struct ima_namespace *)m->private;
+
+	return __ima_measurements_next(ns, v, pos);
+}
+
+static void child_ns_measure_stop(struct seq_file *m, void *v)
+{
+}
+
+static int ascii_child_ns_measure_show(struct seq_file *m, void *v)
+{
+	struct ima_namespace *ns = (struct ima_namespace *)m->private;
+
+	return __ima_ascii_measurements_show(ns, m, v);
+}
+
+static int child_ns_measure_show(struct seq_file *m, void *v)
+{
+	struct ima_namespace *ns = (struct ima_namespace *)m->private;
+
+	return ima_ns_measurements_show(ns, m, v);
+}
+
+
+const struct seq_operations ascii_child_ns_measure_seqops = {
+	.start = child_ns_measure_start,
+	.next  = child_ns_measure_next,
+	.stop  = child_ns_measure_stop,
+	.show  = ascii_child_ns_measure_show,
+};
+
+const struct seq_operations child_ns_measure_seqops = {
+	.start = child_ns_measure_start,
+	.next  = child_ns_measure_next,
+	.stop  = child_ns_measure_stop,
+	.show  = child_ns_measure_show,
+};
+
+static int child_ns_measure_open(struct inode *inode, struct file *filp,
+				 struct seq_operations *seq_ops)
+{
+	int ret;
+	struct seq_file *m;
+
+	ret = seq_open(filp, seq_ops);
+	if (ret)
+		return ret;
+
+	m = filp->private_data;
+	m->private = inode->i_private;
+
+	return 0;
+}
+
+static int ascii_child_ns_measure_open(struct inode *inode, struct file *filp)
+{
+	return child_ns_measure_open(inode, filp,
+				     &ascii_child_ns_measure_seqops);
+}
+static int bin_child_ns_measure_open(struct inode *inode, struct file *filp)
+{
+	return child_ns_measure_open(inode, filp, &child_ns_measure_seqops);
+}
+
+
+static const struct file_operations ascii_ima_child_ns_measure_fops = {
+	.open = ascii_child_ns_measure_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+static const struct file_operations ima_child_ns_measure_fops = {
+	.open = bin_child_ns_measure_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
 int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root)
 {
 	struct ima_namespace *ns = ima_ns_from_user_ns(user_ns);
@@ -718,6 +827,9 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root)
 	struct dentry *violations = NULL;
 	struct dentry *binary_vpcr = NULL;
 	struct dentry *ascii_vpcr = NULL;
+	struct dentry *child_dir;
+	struct dentry *child_ascii_dentry;
+	struct dentry *child_bin_dentry;
 	int ret;
 
 	/*
@@ -821,6 +933,12 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root)
 			ret = PTR_ERR(ascii_vpcr);
 			goto out;
 		}
+
+		ns->parent_dentry = securityfs_create_dir("children", ima_dir);
+		if (IS_ERR(ima_dir)) {
+			ret = PTR_ERR(ima_dir);
+			goto out;
+		}
 	}
 
 	if (!ns->ima_policy_removed) {
@@ -834,11 +952,47 @@ int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root)
 		}
 	}
 
+	if (ns != &init_ima_ns) {
+		char buf[INUM_BUF_SIZE];
+		snprintf(buf, INUM_BUF_SIZE, "%u", user_ns->ns.inum);
+		child_dir =
+			securityfs_create_dir(buf, init_ima_ns.parent_dentry);
+
+		if (IS_ERR(child_dir)) {
+			ret = PTR_ERR(child_dir);
+			if (ret != -EEXIST) /* Ignore only EEXIST */
+				goto out;
+		} else {
+			child_ascii_dentry =
+				securityfs_create_file("ascii_measurement",
+						S_IRUSR | S_IWUSR | S_IRGRP,
+						child_dir, ns,
+						&ascii_ima_child_ns_measure_fops);
+			if (IS_ERR(child_ascii_dentry)) {
+				ret = PTR_ERR(child_ascii_dentry);
+				goto out;
+			}
+
+			child_bin_dentry =
+				securityfs_create_file("binary_measurement",
+						    S_IRUSR | S_IWUSR | S_IRGRP,
+						    child_dir, ns,
+						    &ima_child_ns_measure_fops);
+			if (IS_ERR(child_bin_dentry)) {
+				ret = PTR_ERR(child_bin_dentry);
+				goto out;
+			}
+		}
+	}
+
 	if (!ima_ns_from_user_ns(user_ns))
 		user_ns_set_ima_ns(user_ns, ns);
 
 	return 0;
 out:
+	securityfs_remove(child_bin_dentry);
+	securityfs_remove(child_ascii_dentry);
+	securityfs_remove(child_dir);
 	securityfs_remove(ascii_vpcr);
 	securityfs_remove(binary_vpcr);
 	securityfs_remove(ns->ima_policy);
diff --git a/security/integrity/ima/ima_init_ima_ns.c b/security/integrity/ima/ima_init_ima_ns.c
index 53d5539f67d6..c989bbb22a97 100644
--- a/security/integrity/ima/ima_init_ima_ns.c
+++ b/security/integrity/ima/ima_init_ima_ns.c
@@ -86,6 +86,8 @@ int ima_init_namespace(struct ima_namespace *ns)
 		/* Also the child ns inherits the algo array from init ns */
 		ns->ima_algo_array = init_ima_ns.ima_algo_array;
 
+		ns->parent_dentry = init_ima_ns.parent_dentry;
+
 		mutex_lock(&vpcr_list_mutex);
 		list_add_tail(&ns->vpcr.list, &vpcr_list);
 		mutex_unlock(&vpcr_list_mutex);
diff --git a/security/integrity/ima/ima_ns.c b/security/integrity/ima/ima_ns.c
index 3f65bfbba98d..de49abfdf9e9 100644
--- a/security/integrity/ima/ima_ns.c
+++ b/security/integrity/ima/ima_ns.c
@@ -7,6 +7,7 @@
  */
 
 #include <linux/ima.h>
+#include <linux/namei.h>
 
 #include "ima.h"
 
@@ -48,11 +49,41 @@ void ima_free_ima_ns(struct ima_namespace *ns)
 	kmem_cache_free(imans_cachep, ns);
 }
 
+#define DENTRY_BUF_SIZE 16
+
+static void remove_ima_child_dentry(struct user_namespace *user_ns)
+{
+	char inum_dir[DENTRY_BUF_SIZE];
+	char ascii_fname[DENTRY_BUF_SIZE * 2];
+	char bin_fname[DENTRY_BUF_SIZE * 2];
+	struct dentry *dentry_dir, *ascii_file, *bin_file;
+
+	snprintf(inum_dir, DENTRY_BUF_SIZE, "%u", user_ns->ns.inum);
+	snprintf(ascii_fname, DENTRY_BUF_SIZE * 2, "%u/ascii", user_ns->ns.inum);
+	snprintf(bin_fname, DENTRY_BUF_SIZE * 2, "%u/bin", user_ns->ns.inum);
+
+	inode_lock(d_inode(init_ima_ns.parent_dentry));
+
+	dentry_dir = lookup_one_len(inum_dir, init_ima_ns.parent_dentry,
+				    strlen(inum_dir));
+	ascii_file = lookup_one_len(ascii_fname, init_ima_ns.parent_dentry,
+				     strlen(ascii_fname));
+	bin_file = lookup_one_len(bin_fname, init_ima_ns.parent_dentry,
+				     strlen(bin_fname));
+
+	inode_unlock(d_inode(init_ima_ns.parent_dentry));
+
+	securityfs_remove(ascii_file);
+	securityfs_remove(bin_file);
+	securityfs_remove(dentry_dir);
+}
+
 void free_ima_ns(struct user_namespace *user_ns)
 {
 	struct ima_namespace *ns = ima_ns_from_user_ns(user_ns);
 
 	ima_free_ima_ns(ns);
+	remove_ima_child_dentry(user_ns);
 
 	user_ns->ima_ns = NULL;
 }
-- 
2.38.GIT


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH v1 0/1] ima: obtain child measurement list from init namespace
  2023-03-29  8:58   ` [RFC PATCH v1 0/1] ima: obtain child measurement list from init namespace Denis Semakin
@ 2023-05-02 13:36     ` Stefan Berger
  2023-05-02 14:00       ` Denis Semakin
  0 siblings, 1 reply; 13+ messages in thread
From: Stefan Berger @ 2023-05-02 13:36 UTC (permalink / raw)
  To: Denis Semakin, linux-integrity
  Cc: artem.kuzin, konstantin.meskhidze, ilya.hanov, yusongping,
	hukeping, denis.semakin



On 3/29/23 04:58, Denis Semakin wrote:
> This patch allows to read measurement lists of child namespaces
> form init IMA namespace in order to obtain the values of hashes
> to perform operations and procedures of remote attestation.

I supposed this type of support would go onto the next stage (current posted
'stage' is auditing support, next would be measurement support)?

   Stefan

> 
> Denis Semakin (1):
>    ima: obtain child measurement list from init namespace
> 
>   security/integrity/ima/ima.h             |   1 +
>   security/integrity/ima/ima_fs.c          | 164 ++++++++++++++++++++++-
>   security/integrity/ima/ima_init_ima_ns.c |   2 +
>   security/integrity/ima/ima_ns.c          |  31 +++++
>   4 files changed, 193 insertions(+), 5 deletions(-)
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH v1 0/1] ima: obtain child measurement list from init namespace
  2023-05-02 13:36     ` Stefan Berger
@ 2023-05-02 14:00       ` Denis Semakin
  0 siblings, 0 replies; 13+ messages in thread
From: Denis Semakin @ 2023-05-02 14:00 UTC (permalink / raw)
  To: Stefan Berger, Denis Semakin, linux-integrity
  Cc: artem.kuzin, konstantin.meskhidze, ilya.hanov, yusongping, hukeping


On 02.05.2023 16:36, Stefan Berger wrote:
>
>
> On 3/29/23 04:58, Denis Semakin wrote:
>> This patch allows to read measurement lists of child namespaces
>> form init IMA namespace in order to obtain the values of hashes
>> to perform operations and procedures of remote attestation.
>
> I supposed this type of support would go onto the next stage (current 
> posted
> 'stage' is auditing support, next would be measurement support)?
Yes. I agree.
>
>   Stefan
>
>>
>> Denis Semakin (1):
>>    ima: obtain child measurement list from init namespace
>>
>>   security/integrity/ima/ima.h             |   1 +
>>   security/integrity/ima/ima_fs.c          | 164 ++++++++++++++++++++++-
>>   security/integrity/ima/ima_init_ima_ns.c |   2 +
>>   security/integrity/ima/ima_ns.c          |  31 +++++
>>   4 files changed, 193 insertions(+), 5 deletions(-)
>>

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2023-05-02 13:58 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-31  2:55 [RFC PATCH v2 0/4] Virtualize PCR for Container-IMA Denis Semakin
2022-10-31  2:59 ` [RFC PATCH v2 1/4] ima: Introduce PCR virtualization for IMA namespace Denis Semakin
2022-10-31  2:59 ` [RFC PATCH v2 2/4] ima: Use tpm_chip from init " Denis Semakin
2022-10-31  3:00 ` [RFC PATCH v2 3/4] ima: Create vpcr file on securityfs Denis Semakin
2022-10-31  3:00 ` [RFC PATCH v2 4/4] ima: Extend the real PCR12 with tempPCR value Denis Semakin
2023-01-27  8:19 ` [RFC PATCH v1 0/3] ima: vPCR debug/security Ilya Hanov
2023-01-27  8:19   ` [RFC PATCH v1 1/3] ima: Add a UUID value for each vPCR Ilya Hanov
2023-01-27  8:19   ` [RFC PATCH v1 2/3] ima: ascii_vpcr pseudo-file for sysadmins Ilya Hanov
2023-01-27  8:19   ` [RFC PATCH v1 3/3] ima: Use TPM RNG for vPCR.secret if it's presented Ilya Hanov
2023-03-29  8:58   ` [RFC PATCH v1 0/1] ima: obtain child measurement list from init namespace Denis Semakin
2023-05-02 13:36     ` Stefan Berger
2023-05-02 14:00       ` Denis Semakin
2023-03-29  9:03   ` [RFC PATCH v1 1/1] " Denis Semakin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).