linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
From: Nayna Jain <nayna@linux.ibm.com>
To: linuxppc-dev@lists.ozlabs.org, linux-fsdevel@vger.kernel.org
Cc: Matthew Garrett <mjg59@srcf.ucam.org>,
	linux-efi@vger.kernel.org,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Nayna Jain <nayna@linux.ibm.com>,
	linux-kernel@vger.kernel.org, Dov Murik <dovmurik@linux.ibm.com>,
	Dave Hansen <dave.hansen@intel.com>,
	linux-security-module <linux-security-module@vger.kernel.org>,
	Paul Mackerras <paulus@samba.org>,
	George Wilson <gcwilson@linux.ibm.com>,
	gjoyce@ibm.com
Subject: [RFC PATCH v2 3/3] powerpc/pseries: expose authenticated variables stored in LPAR PKS
Date: Wed, 22 Jun 2022 17:56:48 -0400	[thread overview]
Message-ID: <20220622215648.96723-4-nayna@linux.ibm.com> (raw)
In-Reply-To: <20220622215648.96723-1-nayna@linux.ibm.com>

PowerVM Guest Secure boot feature need to expose firmware managed
secure variables for user management. These variables store keys for
grub/kernel verification and also corresponding denied list.

Expose these variables to the userpace via fwsecurityfs.

Example:

Example:

# cd /sys/firmware/security/secvars

# pwd
/sys/firmware/security/secvars

# cat /tmp/PK.bin > PK

# ls -l
total 0
-rw-r--r-- 1 root root 2497 Jun 22 08:34 PK

# hexdump -C PK
00000000  00 00 00 00 00 08 00 00  a1 59 c0 a5 e4 94 a7 4a  |.........Y.....J|
00000010  87 b5 ab 15 5c 2b f0 72  3f 03 00 00 00 00 00 00  |....\+.r?.......|
00000020  23 03 00 00 ca 18 1d 1c  01 7d eb 11 9a 71 08 94  |#........}...q..|
00000030  ef 31 fb e4 30 82 03 0f  30 82 01 f7 a0 03 02 01  |.1..0...0.......|
00000040  02 02 14 22 ab 18 2f d5  aa dd c5 ba 98 27 60 26  |..."../......'`&|
00000050  f1 63 89 54 4c 52 d9 30  0d 06 09 2a 86 48 86 f7  |.c.TLR.0...*.H..|
...

Signed-off-by: Nayna Jain <nayna@linux.ibm.com>
---
 arch/powerpc/platforms/pseries/Kconfig        |  17 ++
 arch/powerpc/platforms/pseries/plpks/Makefile |   2 +
 .../pseries/plpks/fwsecurityfs_arch.c         |  16 ++
 .../platforms/pseries/plpks/internal.h        |  18 ++
 .../powerpc/platforms/pseries/plpks/secvars.c | 239 ++++++++++++++++++
 include/linux/fwsecurityfs.h                  |   4 +
 6 files changed, 296 insertions(+)
 create mode 100644 arch/powerpc/platforms/pseries/plpks/fwsecurityfs_arch.c
 create mode 100644 arch/powerpc/platforms/pseries/plpks/internal.h
 create mode 100644 arch/powerpc/platforms/pseries/plpks/secvars.c

diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index 6c1ca487103f..9c52095e20c4 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -152,6 +152,23 @@ config PSERIES_PLPKS
 	  config to enable operating system interface to hypervisor to
 	  access this space.
 
+config PSERIES_FWSECURITYFS_ARCH
+	depends on FWSECURITYFS
+	bool "Support fwsecurityfs for pseries"
+	help
+	  Enable fwsecuirtyfs arch specific code. This would initialize
+	  the firmware security filesystem with initial platform specific
+	  structure.
+
+config PSERIES_PLPKS_SECVARS
+	depends on PSERIES_PLPKS
+	select PSERIES_FWSECURITYFS_ARCH
+	tristate "Support for secvars"
+	help
+	  This interface exposes authenticated variables stored in the LPAR
+	  Platform KeyStore using fwsecurityfs interface.
+	  If you are unsure how to use it, say N.
+
 config PAPR_SCM
 	depends on PPC_PSERIES && MEMORY_HOTPLUG && LIBNVDIMM
 	tristate "Support for the PAPR Storage Class Memory interface"
diff --git a/arch/powerpc/platforms/pseries/plpks/Makefile b/arch/powerpc/platforms/pseries/plpks/Makefile
index e651ace920db..ff3d4b4cd3d7 100644
--- a/arch/powerpc/platforms/pseries/plpks/Makefile
+++ b/arch/powerpc/platforms/pseries/plpks/Makefile
@@ -5,3 +5,5 @@
 #
 
 obj-$(CONFIG_PSERIES_PLPKS)  += plpks.o
+obj-$(CONFIG_PSERIES_FWSECURITYFS_ARCH) += fwsecurityfs_arch.o
+obj-$(CONFIG_PSERIES_PLPKS_SECVARS) += secvars.o
diff --git a/arch/powerpc/platforms/pseries/plpks/fwsecurityfs_arch.c b/arch/powerpc/platforms/pseries/plpks/fwsecurityfs_arch.c
new file mode 100644
index 000000000000..6ccdfe4000a6
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/plpks/fwsecurityfs_arch.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * POWER LPAR Platform KeyStore (PLPKS)
+ * Copyright (C) 2022 IBM Corporation
+ * Author: Nayna Jain <nayna@linux.ibm.com>
+ *
+ */
+
+#include <linux/fwsecurityfs.h>
+
+#include "internal.h"
+
+int arch_fwsecurity_init(void)
+{
+	return plpks_secvars_init();
+}
diff --git a/arch/powerpc/platforms/pseries/plpks/internal.h b/arch/powerpc/platforms/pseries/plpks/internal.h
new file mode 100644
index 000000000000..6061ffd37677
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/plpks/internal.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022 IBM Corporation
+ * Author: Nayna Jain <nayna@linux.ibm.com>
+ *
+ */
+#ifndef PKS_FWSEC_INTERNAL
+#define PKS_FWSEC_INTERNAL
+
+#ifdef CONFIG_PSERIES_PLPKS_SECVARS
+int plpks_secvars_init(void);
+#else
+int plpks_secvars_init(void)
+{
+	return 0;
+}
+#endif
+#endif
diff --git a/arch/powerpc/platforms/pseries/plpks/secvars.c b/arch/powerpc/platforms/pseries/plpks/secvars.c
new file mode 100644
index 000000000000..8852cb8f2f3c
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/plpks/secvars.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * POWER LPAR Platform KeyStore (PLPKS)
+ * Copyright (C) 2022 IBM Corporation
+ * Author: Nayna Jain <nayna@linux.ibm.com>
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/fs_context.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+#include <linux/init.h>
+#include <linux/namei.h>
+#include <linux/ctype.h>
+#include <linux/fwsecurityfs.h>
+#include <asm/plpks.h>
+
+#include "internal.h"
+
+static struct dentry *secvar_dir;
+
+static const char * const names[] = {
+	"PK",
+	"KEK",
+	"db",
+	"dbx",
+	"grubdb",
+	"sbat",
+	"moduledb",
+	"trustedcadb",
+	NULL
+};
+
+static int validate_name(char *name)
+{
+	int i = 0;
+
+	while (names[i] != NULL) {
+		if ((strlen(names[i]) == strlen(name))
+		&& (strncmp(name, names[i], strlen(names[i])) == 0))
+			return 0;
+		i++;
+	}
+	pr_err("Invalid name, allowed ones are (dbx,grubdb,sbat,moduledb,trustedcadb)\n");
+
+	return -EINVAL;
+}
+
+static u32 get_policy(char *name)
+{
+	if ((strncmp(name, "PK", 2) == 0)
+	|| (strncmp(name, "KEK", 3) == 0)
+	|| (strncmp(name, "db", 2) == 0)
+	|| (strncmp(name, "dbx", 3) == 0)
+	|| (strncmp(name, "grubdb", 6) == 0)
+	|| (strncmp(name, "sbat", 4) == 0))
+		return (WORLDREADABLE & SIGNEDUPDATE);
+	else
+		return SIGNEDUPDATE;
+}
+
+static ssize_t plpks_secvar_file_write(struct file *file,
+				     const char __user *userbuf,
+				     size_t count, loff_t *ppos)
+{
+	struct plpks_var var;
+	void *data;
+	struct inode *inode = file->f_mapping->host;
+	u16 datasize = count;
+	ssize_t bytes;
+
+	data = memdup_user(userbuf, datasize);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	var.component = NULL;
+	var.name = file->f_path.dentry->d_iname;
+	var.namelen = strlen(var.name);
+	var.policy = get_policy(var.name);
+	var.datalen = datasize;
+	var.data = data;
+	bytes = plpks_signed_update_var(var);
+
+	if (bytes) {
+		pr_err("Update of the variable failed with error %ld\n", bytes);
+		goto out;
+	}
+
+	inode_lock(inode);
+	i_size_write(inode, datasize);
+	inode->i_mtime = current_time(inode);
+	inode_unlock(inode);
+
+	bytes = count;
+out:
+	kfree(data);
+
+	return bytes;
+
+}
+
+static ssize_t plpks_secvar_file_read(struct file *file, char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	struct plpks_var var;
+	char *out;
+	u32 outlen;
+	int rc;
+	size_t size;
+
+	var.name = file->f_path.dentry->d_iname;
+	var.namelen = strlen(var.name);
+	var.component = NULL;
+	rc = plpks_read_os_var(&var);
+	if (rc) {
+		pr_err("Error reading object %d\n", rc);
+		return rc;
+	}
+
+	outlen = sizeof(var.policy) + var.datalen;
+	out = kzalloc(outlen, GFP_KERNEL);
+	memcpy(out, &var.policy, sizeof(var.policy));
+
+	memcpy(out + sizeof(var.policy), var.data, var.datalen);
+
+	size = simple_read_from_buffer(userbuf, count, ppos,
+				       out, outlen);
+	kfree(out);
+	return size;
+}
+
+
+static const struct file_operations plpks_secvar_file_operations = {
+	.open   = simple_open,
+	.read   = plpks_secvar_file_read,
+	.write  = plpks_secvar_file_write,
+	.llseek = no_llseek,
+};
+
+static int plpks_secvar_create(struct user_namespace *mnt_userns, struct inode *dir,
+			     struct dentry *dentry, umode_t mode, bool excl)
+{
+	int namelen, i = 0;
+	char *varname;
+	int rc = 0;
+
+	namelen = dentry->d_name.len;
+
+	varname = kzalloc(namelen + 1, GFP_KERNEL);
+	if (!varname)
+		return -ENOMEM;
+
+	for (i = 0; i < namelen; i++)
+		varname[i] = dentry->d_name.name[i];
+	varname[i] = '\0';
+
+	rc = validate_name(varname);
+	if (rc)
+		goto out;
+
+	rc = validate_name(varname);
+	if (rc)
+		goto out;
+
+	rc = fwsecurityfs_create_file(varname, S_IFREG|0644, 0, secvar_dir,
+				      dentry, &plpks_secvar_file_operations);
+	if (rc)
+		pr_err("Error creating file\n");
+
+out:
+	kfree(varname);
+
+	return rc;
+}
+
+static const struct inode_operations plpks_secvar_dir_inode_operations = {
+	.lookup = simple_lookup,
+	.create = plpks_secvar_create,
+};
+
+static int plpks_fill_secvars(struct super_block *sb)
+{
+	struct plpks_var *var = NULL;
+	int err;
+	int i = 0;
+
+	while (names[i] != NULL) {
+		var = kzalloc(sizeof(struct plpks_var), GFP_KERNEL);
+		var->name = (char *)names[i];
+		var->namelen = strlen(names[i]);
+		pr_debug("name is %s\n", var->name);
+		var->component = NULL;
+		i++;
+		err = plpks_read_os_var(var);
+		if (err) {
+			kfree(var);
+			continue;
+		}
+
+		err = fwsecurityfs_create_file(var->name, S_IFREG|0644,
+					       var->datalen, secvar_dir,
+					       NULL,
+					       &plpks_secvar_file_operations);
+
+		kfree(var);
+		if (err) {
+			pr_err("Error creating file\n");
+			break;
+		}
+	}
+	return  err;
+};
+
+int plpks_secvars_init(void)
+{
+	int error;
+
+	struct super_block *sb;
+
+	secvar_dir = fwsecurityfs_create_dir("secvars", S_IFDIR | 0755, NULL,
+					     &plpks_secvar_dir_inode_operations);
+	if (IS_ERR(secvar_dir)) {
+		int ret = PTR_ERR(secvar_dir);
+
+		if (ret != -ENODEV)
+			pr_err("Unable to create integrity sysfs dir: %d\n",
+					ret);
+		secvar_dir = NULL;
+		return ret;
+	}
+
+	sb = fwsecurityfs_get_superblock();
+	error = plpks_fill_secvars(sb);
+	if (error)
+		pr_err("Filling secvars failed\n");
+
+	return 0;
+};
diff --git a/include/linux/fwsecurityfs.h b/include/linux/fwsecurityfs.h
index c079ce939f42..d5fd51aa6322 100644
--- a/include/linux/fwsecurityfs.h
+++ b/include/linux/fwsecurityfs.h
@@ -21,9 +21,13 @@ struct dentry *fwsecurityfs_create_dir(const char *name, umode_t mode,
 				       const struct inode_operations *iops);
 int fwsecurityfs_remove_dir(struct dentry *dentry);
 
+#ifdef CONFIG_PSERIES_FWSECURITYFS_ARCH
+int arch_fwsecurity_init(void);
+#else
 static int arch_fwsecurity_init(void)
 {
 	return 0;
 }
+#endif
 
 #endif /* _FWSECURITYFS_H_ */
-- 
2.27.0


  parent reply	other threads:[~2022-06-22 22:00 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-22 21:56 [RFC PATCH v2 0/3] powerpc/pseries: add support for local secure storage called Platform KeyStore(PKS) Nayna Jain
2022-06-22 21:56 ` [RFC PATCH v2 1/3] powerpc/pseries: define driver for Platform KeyStore Nayna Jain
2022-06-22 21:56 ` [RFC PATCH v2 2/3] fs: define a firmware security filesystem named fwsecurityfs Nayna Jain
2022-06-22 22:29   ` Casey Schaufler
2022-06-23  1:50     ` Nayna
2022-06-23  8:54   ` Greg Kroah-Hartman
2022-06-23 13:23     ` James Bottomley
2022-06-26 15:48       ` Mimi Zohar
2022-06-27  7:37         ` Greg Kroah-Hartman
2022-06-28 13:25           ` Christian Brauner
2022-06-22 21:56 ` Nayna Jain [this message]
2022-06-23  2:36   ` [RFC PATCH v2 3/3] powerpc/pseries: expose authenticated variables stored in LPAR PKS Randy Dunlap
2022-06-27 21:10 ` [RFC PATCH v2 0/3] powerpc/pseries: add support for local secure storage called Platform KeyStore(PKS) Dave Hansen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220622215648.96723-4-nayna@linux.ibm.com \
    --to=nayna@linux.ibm.com \
    --cc=dave.hansen@intel.com \
    --cc=dovmurik@linux.ibm.com \
    --cc=gcwilson@linux.ibm.com \
    --cc=gjoyce@ibm.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-efi@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=mjg59@srcf.ucam.org \
    --cc=paulus@samba.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).