diff mbox series

[6/7] ima: Introduce template field evmxattrs

Message ID 20210520085701.465369-7-roberto.sassu@huawei.com (mailing list archive)
State New, archived
Headers show
Series ima: Add template fields to verify EVM portable signatures | expand

Commit Message

Roberto Sassu May 20, 2021, 8:57 a.m. UTC
This patch introduces the new template field evmxattrs, which contains the
number of EVM protected xattrs (u32 in little endian), the xattr names
separated by \0, the xattr lengths (u32 in little endian) and the xattr
values. Xattrs can be used to verify the EVM portable signature, if it was
included with the template fields sig or evmsig.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 Documentation/security/IMA-templates.rst  |   3 +
 security/integrity/ima/ima_template.c     |   2 +
 security/integrity/ima/ima_template_lib.c | 121 ++++++++++++++++++++++
 security/integrity/ima/ima_template_lib.h |   2 +
 4 files changed, 128 insertions(+)

Comments

Mimi Zohar May 24, 2021, 6:31 p.m. UTC | #1
Hi Roberto,

On Thu, 2021-05-20 at 10:57 +0200, Roberto Sassu wrote:
> This patch introduces the new template field evmxattrs, which contains the
> number of EVM protected xattrs (u32 in little endian), the xattr names
> separated by \0, the xattr lengths (u32 in little endian) and the xattr
> values. Xattrs can be used to verify the EVM portable signature, if it was
> included with the template fields sig or evmsig.

Verifying the file data hash and the template data hash, the value
extended into the TPM,  are straight forward.  In the first case all
that is needed is the public key, and in the other case the length of
the template data.  Verifying the template data hash doesn't require
any knowledge of the template data format.   All that is needed is the
length of the template data.

This patch set provides all the necessary information for verifying the
EVM portable signature, but it is so much more difficult.  For example,
the security xattrs are listed in whatever order listxattr returns, not
the order in which the hash is calculated.  Does the attestation server
really need to know which xattrs are included or their length?  If that
information is important for the attestation server, then perhaps
provide it separately from the xattrs data.

I'm thinking the attestation server just needs the ability of verifying
the EVM portable signature.   As each field is prefixed with the field
data length, the attestation server should be able to re-calculate the
expected hash - xattrs, followed by the individual "misc" data fields.

thanks,

Mimi
diff mbox series

Patch

diff --git a/Documentation/security/IMA-templates.rst b/Documentation/security/IMA-templates.rst
index 6e98bce20029..a9684fde3871 100644
--- a/Documentation/security/IMA-templates.rst
+++ b/Documentation/security/IMA-templates.rst
@@ -82,6 +82,9 @@  descriptors by adding their identifier to the format string
  - 'mntgidmap': the GID mappings of the idmapped mount (same format as
    'mntuidmap');
  - 'imode': the inode mode;
+ - 'evmxattrs': the EVM protected xattrs (num xattrs (u32 in canonical format),
+    xattr names separated by \0, xattr lengths (u32 in canonical format) and
+    xattr values);
 
 
 Below, there is the list of defined template descriptors:
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c
index 34674aef1cc5..b9dd900db0ff 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -59,6 +59,8 @@  static const struct ima_template_field supported_fields[] = {
 	 .field_show = ima_show_template_sig},
 	{.field_id = "imode", .field_init = ima_eventinodemode_init,
 	 .field_show = ima_show_template_uint},
+	{.field_id = "evmxattrs", .field_init = ima_eventinodeevmxattrs_init,
+	 .field_show = ima_show_template_sig},
 };
 
 /*
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index b82fb8f35e5d..71e642d90e63 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -11,6 +11,7 @@ 
 
 #include "ima_template_lib.h"
 #include <linux/xattr.h>
+#include <linux/evm.h>
 
 static bool ima_template_hash_algo_allowed(u8 algo)
 {
@@ -714,3 +715,123 @@  int ima_eventinodemode_init(struct ima_event_data *event_data,
 	return ima_write_template_field_data((char *)&mode, sizeof(mode),
 					     DATA_FMT_UINT, field_data);
 }
+
+/*
+ *  ima_eventinodeevmxattrs_init - include the number of EVM protected xattrs,
+ *  the xattr names, lengths and values as part of the template data
+ */
+int ima_eventinodeevmxattrs_init(struct ima_event_data *event_data,
+				 struct ima_field_data *field_data)
+
+{
+	struct inode *inode;
+	u8 *buffer = NULL;
+	char *xattr_names, *xattr_names_ptr, *xattr_name;
+	size_t names_size, total_size;
+	u32 num_xattrs = 0, xattr_value_len;
+	loff_t names_offset, lengths_offset, values_offset;
+	int rc, evm_present = 0;
+
+	if (!event_data->file)
+		return 0;
+
+	inode = file_inode(event_data->file);
+	if (!inode->i_op->listxattr || !(inode->i_opflags & IOP_XATTR))
+		return 0;
+
+	names_size = inode->i_op->listxattr(file_dentry(event_data->file),
+					    NULL, 0);
+	if (names_size <= 0)
+		return 0;
+
+	xattr_names = kmalloc(names_size, GFP_KERNEL);
+	if (!xattr_names)
+		return 0;
+
+	names_size = inode->i_op->listxattr(file_dentry(event_data->file),
+					    xattr_names, names_size);
+	if (names_size <= 0)
+		goto out;
+
+	xattr_names_ptr = xattr_names;
+	total_size = sizeof(num_xattrs);
+	lengths_offset = total_size;
+
+	while (xattr_names_ptr < xattr_names + names_size) {
+		xattr_name = xattr_names_ptr;
+		xattr_names_ptr += strlen(xattr_names_ptr) + 1;
+
+		if (!strcmp(xattr_name, XATTR_NAME_EVM)) {
+			evm_present = 1;
+			continue;
+		}
+
+		if (!evm_protected_xattr_if_enabled(xattr_name))
+			continue;
+
+		total_size += xattr_names_ptr - xattr_name;
+		lengths_offset += xattr_names_ptr - xattr_name;
+		total_size += sizeof(xattr_value_len);
+		rc = __vfs_getxattr(file_dentry(event_data->file),
+				    file_inode(event_data->file), xattr_name,
+				    NULL, 0);
+		xattr_value_len = (rc >= 0) ? rc : 0;
+		total_size += xattr_value_len;
+		num_xattrs++;
+	}
+
+	/*
+	 * Don't provide data if security.evm is not found or there are no
+	 * protected xattrs.
+	 */
+	if (!evm_present || !num_xattrs)
+		return 0;
+
+	buffer = kmalloc(total_size, GFP_KERNEL);
+	if (!buffer)
+		goto out;
+
+	*(u32 *)buffer = num_xattrs;
+	if (ima_canonical_fmt)
+		*(u32 *)buffer = cpu_to_le32(*(u32 *)buffer);
+
+	names_offset = sizeof(num_xattrs);
+	values_offset = lengths_offset + num_xattrs * sizeof(xattr_value_len);
+
+	xattr_names_ptr = xattr_names;
+
+	while (xattr_names_ptr < xattr_names + names_size) {
+		xattr_name = xattr_names_ptr;
+		xattr_names_ptr += strlen(xattr_names_ptr) + 1;
+
+		if (!strcmp(xattr_name, XATTR_NAME_EVM))
+			continue;
+
+		if (!evm_protected_xattr_if_enabled(xattr_name))
+			continue;
+
+		memcpy(buffer + names_offset, xattr_name,
+		       xattr_names_ptr - xattr_name);
+		names_offset += xattr_names_ptr - xattr_name;
+
+		rc = __vfs_getxattr(file_dentry(event_data->file),
+				    file_inode(event_data->file), xattr_name,
+				    buffer + values_offset,
+				    total_size - values_offset);
+		xattr_value_len = (rc >= 0) ? rc : 0;
+		*(u32 *)(buffer + lengths_offset) = xattr_value_len;
+		if (ima_canonical_fmt)
+			*(u32 *)(buffer + lengths_offset) =
+				cpu_to_le32(*(u32 *)(buffer + lengths_offset));
+
+		lengths_offset += sizeof(xattr_value_len);
+		values_offset += xattr_value_len;
+	}
+
+	rc = ima_write_template_field_data((char *)buffer, total_size,
+					   DATA_FMT_HEX, field_data);
+out:
+	kfree(xattr_names);
+	kfree(buffer);
+	return rc;
+}
diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h
index dc3c16912f6d..ee8f53847305 100644
--- a/security/integrity/ima/ima_template_lib.h
+++ b/security/integrity/ima/ima_template_lib.h
@@ -60,4 +60,6 @@  int ima_eventmnt_userns_gid_map_init(struct ima_event_data *event_data,
 				     struct ima_field_data *field_data);
 int ima_eventinodemode_init(struct ima_event_data *event_data,
 			    struct ima_field_data *field_data);
+int ima_eventinodeevmxattrs_init(struct ima_event_data *event_data,
+				 struct ima_field_data *field_data);
 #endif /* __LINUX_IMA_TEMPLATE_LIB_H */