@@ -119,6 +119,15 @@ 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;
+
struct ima_namespace {
unsigned long ima_ns_flags;
/* Bit numbers for above flags; use BIT() to get flag */
@@ -165,6 +174,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;
@@ -6,8 +6,12 @@
* Stefan Berger <stefanb@linux.vnet.ibm.com>
*/
+#include <linux/random.h>
#include "ima.h"
+struct mutex vpcr_list_mutex;
+struct list_head vpcr_list;
+
int ima_init_namespace(struct ima_namespace *ns)
{
int ret;
@@ -50,8 +54,18 @@ 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");
+
+ INIT_LIST_HEAD(&vpcr_list);
+ 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;
@@ -31,6 +31,9 @@ static void destroy_ima_ns(struct ima_namespace *ns)
kfree(ns->arch_policy_entry);
ima_free_policy_rules(ns);
ima_free_ns_status_tree(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)
@@ -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;
}
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 | 10 +++++ security/integrity/ima/ima_init_ima_ns.c | 14 ++++++ security/integrity/ima/ima_ns.c | 3 ++ security/integrity/ima/ima_queue.c | 55 ++++++++++++++++++++++++ 4 files changed, 82 insertions(+)