[RFC PATCH v1 3/4] ima: Create vpcr file on securityfs.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 | hexdump -C
00000000  63 50 43 52 3a 20 00 00  00 00 01 00 00 00 00 00  |cPCR: ..........|
00000010  00 00 00 00 00 00 40 71  8e 03 45 9e ff ff 00 00  |......@q..E.....|
00000020  00 00 00 00 00 00 d1 50  43 52 31 32 3a 43 7b a2  |.......PCR12:C{.|
00000030  89 11 5b b8 b4 30 c3 4d  f7 cd e4 f7 19 1e b2 10  |..[..0.M........|
00000040  38 a4 5e 23 61 aa 15 4e  8d ca 38 7d b2 00        |8.^#a..N..8}..|
0000004e

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

diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 2eb11d0fb3c7..aaa65ee0d9d5 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -25,6 +25,14 @@
 
 #include "ima.h"
 
+extern struct list_head vpcr_list;
+
+#define CPCR_PFX	"cPCR: "
+#define CPCR_PFX_LEN	6
+
+#define PCR12_PFX	"PCR12:"
+#define PCR12_PFX_LEN	6
+
 bool ima_canonical_fmt;
 static int __init default_canonical_fmt_setup(char *str)
 {
@@ -533,6 +541,109 @@ static const struct file_operations ima_active_ops = {
 	.write = ima_write_active,
 };
 
+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 0;
+}
+
+static ssize_t ima_vpcr_read(struct file *filp, char __user *buf, size_t count,
+			     loff_t *ppos)
+{
+	struct vpcr_entry *vpcr;
+	struct {
+		struct ima_digest_data hdr;
+		char digest[SHA256_DIGEST_SIZE];
+	} temp_vpcr_hash = {};
+
+	struct {
+		u8 dig[CPCR_PFX_LEN + SHA256_DIGEST_SIZE + 1];
+	} *vpcr_buff = NULL;
+
+	int ret, i = 0;
+	size_t vpcr_buff_size = 0;
+	loff_t size = SHA256_DIGEST_SIZE * 2;
+	struct ima_namespace *init_ns = &init_ima_ns;
+	struct ima_namespace *curr_ns = ima_ns_from_file(filp);
+
+	if (*ppos != 0)
+		return 0;
+
+	temp_vpcr_hash.hdr.algo = HASH_ALGO_SHA256;
+	temp_vpcr_hash.hdr.length = SHA256_DIGEST_SIZE;
+
+	if (mutex_lock_interruptible(&vpcr_list_mutex))
+		return -EINTR;
+
+	list_for_each_entry(vpcr, &init_ns->vpcr.list, list) {
+		size_t buff_len;
+		u8 buf[IMA_MAX_DIGEST_SIZE * 2] = {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, size,
+					   &temp_vpcr_hash.hdr);
+		if (ret) {
+			ret = -EINTR;
+			goto free_mem;
+		}
+
+		buff_len = (CPCR_PFX_LEN + SHA256_DIGEST_SIZE + 1) * (i + 1);
+		vpcr_buff_size += buff_len;
+
+		/**
+		 * Using krealloc() here probably looks buggy,
+		 * maybe it's better to use kvmalloc() or vmalloc() instead.
+		 */
+		vpcr_buff = krealloc(vpcr_buff, buff_len, GFP_NOFS);
+		if (!vpcr_buff) {
+			ret = -ENOMEM;
+			goto free_mem;
+		}
+
+		memcpy(&vpcr_buff[i].dig, CPCR_PFX, CPCR_PFX_LEN);
+		memcpy(&vpcr_buff[i].dig[CPCR_PFX_LEN], vpcr->vpcr_tmp,
+		       SHA256_DIGEST_SIZE);
+		i++;
+	}
+
+	vpcr_buff_size += PCR12_PFX_LEN + SHA256_DIGEST_SIZE + 1;
+	vpcr_buff = krealloc(vpcr_buff, vpcr_buff_size, GFP_NOFS);
+	if (!vpcr_buff) {
+		ret = -ENOMEM;
+		goto free_mem;
+	}
+
+	memcpy(&vpcr_buff[i].dig, PCR12_PFX, PCR12_PFX_LEN);
+	mutex_unlock(&vpcr_list_mutex);
+	ret = simple_read_from_buffer(buf, count, ppos, vpcr_buff,
+				      vpcr_buff_size);
+	kfree(vpcr_buff);
+
+	return ret;
+
+free_mem:
+	mutex_unlock(&vpcr_list_mutex);
+	if (vpcr_buff)
+		kfree(vpcr_buff);
+
+	return ret;
+}
+
+static const struct file_operations ima_vpcr_ops = {
+	.open = ima_vpcr_open,
+	.read = ima_vpcr_read,
+};
+
 int ima_fs_ns_init(struct user_namespace *user_ns, struct dentry *root)
 {
 	struct ima_namespace *ns = ima_ns_from_user_ns(user_ns);
@@ -544,6 +655,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;
 
 	/*
@@ -620,6 +732,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_ops);
+		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,
@@ -647,6 +768,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.25.1




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux Kernel]     [Linux Kernel Hardening]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux