diff mbox series

[3/7] ima: Introduce template fields mntuidmap and mntgidmap

Message ID 20210520085701.465369-4-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:56 a.m. UTC
This patch introduces the new template fields mntuidmap and mntgidmap,
which include respectively the UID and GID mappings of the idmapped mount,
if the user namespace is not the initial one.

These template fields, which should be included whenever the iuid and the
igid fields are included, allow remote verifiers to find the original UID
and GID of the inode during signature verification. The iuid and igid
fields include the mapped UID and GID when the inode is in an idmapped
mount.

This solution has been preferred to providing always the original UID and
GID, regardless of whether the inode is in an idmapped mount or not, as
the mapped UID and GID are those seen by processes and matched with the IMA
policy.

Cc: Christian Brauner <christian.brauner@ubuntu.com>
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 Documentation/security/IMA-templates.rst  |  4 ++
 security/integrity/ima/ima_template.c     |  6 ++
 security/integrity/ima/ima_template_lib.c | 83 +++++++++++++++++++++++
 security/integrity/ima/ima_template_lib.h |  4 ++
 4 files changed, 97 insertions(+)

Comments

Christian Brauner May 20, 2021, 9:36 a.m. UTC | #1
On Thu, May 20, 2021 at 10:56:57AM +0200, Roberto Sassu wrote:
> This patch introduces the new template fields mntuidmap and mntgidmap,
> which include respectively the UID and GID mappings of the idmapped mount,
> if the user namespace is not the initial one.
> 
> These template fields, which should be included whenever the iuid and the
> igid fields are included, allow remote verifiers to find the original UID
> and GID of the inode during signature verification. The iuid and igid
> fields include the mapped UID and GID when the inode is in an idmapped
> mount.
> 
> This solution has been preferred to providing always the original UID and
> GID, regardless of whether the inode is in an idmapped mount or not, as
> the mapped UID and GID are those seen by processes and matched with the IMA
> policy.

Hm, looking at the code this doesn't seem like a good idea to me. I
think we should avoid that and just rely on the original uid and gid.
Christian Brauner May 20, 2021, 9:41 a.m. UTC | #2
On Thu, May 20, 2021 at 11:37:07AM +0200, Christian Brauner wrote:
> On Thu, May 20, 2021 at 10:56:57AM +0200, Roberto Sassu wrote:
> > This patch introduces the new template fields mntuidmap and mntgidmap,
> > which include respectively the UID and GID mappings of the idmapped mount,
> > if the user namespace is not the initial one.
> > 
> > These template fields, which should be included whenever the iuid and the
> > igid fields are included, allow remote verifiers to find the original UID
> > and GID of the inode during signature verification. The iuid and igid
> > fields include the mapped UID and GID when the inode is in an idmapped
> > mount.
> > 
> > This solution has been preferred to providing always the original UID and
> > GID, regardless of whether the inode is in an idmapped mount or not, as
> > the mapped UID and GID are those seen by processes and matched with the IMA
> > policy.
> 
> Hm, looking at the code this doesn't seem like a good idea to me. I
> think we should avoid that and just rely on the original uid and gid.

It'd be ok to include the mapped uid/gid but don't copy the mapping
itself.
Roberto Sassu May 20, 2021, 11:54 a.m. UTC | #3
> From: Christian Brauner [mailto:christian.brauner@ubuntu.com]
> Sent: Thursday, May 20, 2021 11:41 AM
> On Thu, May 20, 2021 at 11:37:07AM +0200, Christian Brauner wrote:
> > On Thu, May 20, 2021 at 10:56:57AM +0200, Roberto Sassu wrote:
> > > This patch introduces the new template fields mntuidmap and mntgidmap,
> > > which include respectively the UID and GID mappings of the idmapped
> mount,
> > > if the user namespace is not the initial one.
> > >
> > > These template fields, which should be included whenever the iuid and the
> > > igid fields are included, allow remote verifiers to find the original UID
> > > and GID of the inode during signature verification. The iuid and igid
> > > fields include the mapped UID and GID when the inode is in an idmapped
> > > mount.
> > >
> > > This solution has been preferred to providing always the original UID and
> > > GID, regardless of whether the inode is in an idmapped mount or not, as
> > > the mapped UID and GID are those seen by processes and matched with
> the IMA
> > > policy.
> >
> > Hm, looking at the code this doesn't seem like a good idea to me. I
> > think we should avoid that and just rely on the original uid and gid.
> 
> It'd be ok to include the mapped uid/gid but don't copy the mapping
> itself.

Uhm, we would need a way to obtain the original UID and GID to
verify the portable signature.

Roberto

HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063
Managing Director: Li Peng, Li Jian, Shi Yanli
diff mbox series

Patch

diff --git a/Documentation/security/IMA-templates.rst b/Documentation/security/IMA-templates.rst
index bf8ce4cf5878..48a2df22a1a1 100644
--- a/Documentation/security/IMA-templates.rst
+++ b/Documentation/security/IMA-templates.rst
@@ -77,6 +77,10 @@  descriptors by adding their identifier to the format string
  - 'evmsig': the EVM portable signature;
  - 'iuid': the inode UID;
  - 'igid': the inode GID;
+ - 'mntuidmap': the UID mappings of the idmapped mount (nr extents,
+    [ uid_gid_extent1 ] ... [ uid_gid_extentN ], all u32 in canonical format);
+ - 'mntgidmap': the GID mappings of the idmapped mount (same format as
+   'mntuidmap');
 
 
 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 a5ecd9e2581b..19de115b985b 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -51,6 +51,12 @@  static const struct ima_template_field supported_fields[] = {
 	 .field_show = ima_show_template_uint},
 	{.field_id = "igid", .field_init = ima_eventinodegid_init,
 	 .field_show = ima_show_template_uint},
+	{.field_id = "mntuidmap",
+	 .field_init = ima_eventmnt_userns_uid_map_init,
+	 .field_show = ima_show_template_sig},
+	{.field_id = "mntgidmap",
+	 .field_init = ima_eventmnt_userns_gid_map_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 a191b861548b..bc4919d90c3a 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -609,3 +609,86 @@  int ima_eventinodegid_init(struct ima_event_data *event_data,
 {
 	return ima_eventinodedac_init_common(event_data, field_data, false);
 }
+
+int ima_eventmnt_userns_common_init(struct ima_event_data *event_data,
+				    struct ima_field_data *field_data,
+				    bool get_uid_map)
+{
+	struct user_namespace *mnt_userns;
+	u8 *buf, *buf_ptr;
+	struct uid_gid_map *map;
+	int rc, i;
+
+	if (!event_data->file)
+		return 0;
+
+	mnt_userns = file_mnt_user_ns(event_data->file);
+	if (mnt_userns == &init_user_ns)
+		return 0;
+
+	map = &mnt_userns->uid_map;
+	if (!get_uid_map)
+		map = &mnt_userns->gid_map;
+
+	buf_ptr = buf = kmalloc(sizeof(map->nr_extents) +
+				map->nr_extents * sizeof(*map->extent),
+				GFP_KERNEL);
+	if (!buf)
+		return 0;
+
+	memcpy(buf_ptr, &map->nr_extents, sizeof(map->nr_extents));
+
+	if (ima_canonical_fmt)
+		*(u32 *)buf_ptr = cpu_to_le32(*(u32 *)buf_ptr);
+
+	buf_ptr += sizeof(u32);
+
+	for (i = 0; i < map->nr_extents; i++) {
+		struct uid_gid_extent *extent;
+
+		/* Taken from m_start() in kernel/user_namespace.c. */
+		if (map->nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS)
+			extent = &map->extent[i];
+		else
+			extent = &map->forward[i];
+
+		memcpy(buf_ptr, &extent->first, sizeof(extent->first));
+		if (ima_canonical_fmt)
+			*(u32 *)buf_ptr = cpu_to_le32(*(u32 *)buf_ptr);
+		buf_ptr += sizeof(extent->first);
+		memcpy(buf_ptr, &extent->lower_first,
+		       sizeof(extent->lower_first));
+		if (ima_canonical_fmt)
+			*(u32 *)buf_ptr = cpu_to_le32(*(u32 *)buf_ptr);
+		buf_ptr += sizeof(extent->lower_first);
+		memcpy(buf_ptr, &extent->count, sizeof(extent->count));
+		if (ima_canonical_fmt)
+			*(u32 *)buf_ptr = cpu_to_le32(*(u32 *)buf_ptr);
+		buf_ptr += sizeof(extent->count);
+	}
+
+	rc = ima_write_template_field_data((char *)buf, buf_ptr - buf,
+					   DATA_FMT_HEX, field_data);
+	kfree(buf);
+	return rc;
+}
+
+/*
+ *  ima_eventmnt_userns_uid_map_init - include the UID mappings of the idmapped
+ *  mount as part of the template data
+ */
+int ima_eventmnt_userns_uid_map_init(struct ima_event_data *event_data,
+				     struct ima_field_data *field_data)
+{
+	return ima_eventmnt_userns_common_init(event_data, field_data, true);
+}
+
+/*
+ *  ima_eventmnt_userns_gid_map_init - include the GID mappings of the idmapped
+ *  mount as part of the template data
+ */
+int ima_eventmnt_userns_gid_map_init(struct ima_event_data *event_data,
+				     struct ima_field_data *field_data)
+{
+	return ima_eventmnt_userns_common_init(event_data, field_data, false);
+}
diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h
index b0aaf109f386..51ee66fc7230 100644
--- a/security/integrity/ima/ima_template_lib.h
+++ b/security/integrity/ima/ima_template_lib.h
@@ -54,4 +54,8 @@  int ima_eventinodeuid_init(struct ima_event_data *event_data,
 			   struct ima_field_data *field_data);
 int ima_eventinodegid_init(struct ima_event_data *event_data,
 			   struct ima_field_data *field_data);
+int ima_eventmnt_userns_uid_map_init(struct ima_event_data *event_data,
+				     struct ima_field_data *field_data);
+int ima_eventmnt_userns_gid_map_init(struct ima_event_data *event_data,
+				     struct ima_field_data *field_data);
 #endif /* __LINUX_IMA_TEMPLATE_LIB_H */