1ccadf154SRussell Currey // SPDX-License-Identifier: GPL-2.0-only
2ccadf154SRussell Currey 
3ccadf154SRussell Currey // Secure variable implementation using the PowerVM LPAR Platform KeyStore (PLPKS)
4ccadf154SRussell Currey //
5ccadf154SRussell Currey // Copyright 2022, 2023 IBM Corporation
6ccadf154SRussell Currey // Authors: Russell Currey
7ccadf154SRussell Currey //          Andrew Donnellan
8ccadf154SRussell Currey //          Nayna Jain
9ccadf154SRussell Currey 
10ccadf154SRussell Currey #define pr_fmt(fmt) "secvar: "fmt
11ccadf154SRussell Currey 
12ccadf154SRussell Currey #include <linux/printk.h>
13ccadf154SRussell Currey #include <linux/init.h>
14ccadf154SRussell Currey #include <linux/types.h>
15ccadf154SRussell Currey #include <linux/slab.h>
16ccadf154SRussell Currey #include <linux/string.h>
17ccadf154SRussell Currey #include <linux/kobject.h>
18ccadf154SRussell Currey #include <linux/nls.h>
19ccadf154SRussell Currey #include <asm/machdep.h>
20ccadf154SRussell Currey #include <asm/secvar.h>
21ccadf154SRussell Currey #include <asm/plpks.h>
22ccadf154SRussell Currey 
23ccadf154SRussell Currey // Config attributes for sysfs
24ccadf154SRussell Currey #define PLPKS_CONFIG_ATTR(name, fmt, func)			\
25ccadf154SRussell Currey 	static ssize_t name##_show(struct kobject *kobj,	\
26ccadf154SRussell Currey 				   struct kobj_attribute *attr,	\
27ccadf154SRussell Currey 				   char *buf)			\
28ccadf154SRussell Currey 	{							\
29ccadf154SRussell Currey 		return sysfs_emit(buf, fmt, func());		\
30ccadf154SRussell Currey 	}							\
31ccadf154SRussell Currey 	static struct kobj_attribute attr_##name = __ATTR_RO(name)
32ccadf154SRussell Currey 
33ccadf154SRussell Currey PLPKS_CONFIG_ATTR(version, "%u\n", plpks_get_version);
34ccadf154SRussell Currey PLPKS_CONFIG_ATTR(max_object_size, "%u\n", plpks_get_maxobjectsize);
35ccadf154SRussell Currey PLPKS_CONFIG_ATTR(total_size, "%u\n", plpks_get_totalsize);
36ccadf154SRussell Currey PLPKS_CONFIG_ATTR(used_space, "%u\n", plpks_get_usedspace);
37ccadf154SRussell Currey PLPKS_CONFIG_ATTR(supported_policies, "%08x\n", plpks_get_supportedpolicies);
38ccadf154SRussell Currey PLPKS_CONFIG_ATTR(signed_update_algorithms, "%016llx\n", plpks_get_signedupdatealgorithms);
39ccadf154SRussell Currey 
40ccadf154SRussell Currey static const struct attribute *config_attrs[] = {
41ccadf154SRussell Currey 	&attr_version.attr,
42ccadf154SRussell Currey 	&attr_max_object_size.attr,
43ccadf154SRussell Currey 	&attr_total_size.attr,
44ccadf154SRussell Currey 	&attr_used_space.attr,
45ccadf154SRussell Currey 	&attr_supported_policies.attr,
46ccadf154SRussell Currey 	&attr_signed_update_algorithms.attr,
47ccadf154SRussell Currey 	NULL,
48ccadf154SRussell Currey };
49ccadf154SRussell Currey 
get_policy(const char * name)50ccadf154SRussell Currey static u32 get_policy(const char *name)
51ccadf154SRussell Currey {
52ccadf154SRussell Currey 	if ((strcmp(name, "db") == 0) ||
53ccadf154SRussell Currey 	    (strcmp(name, "dbx") == 0) ||
54ccadf154SRussell Currey 	    (strcmp(name, "grubdb") == 0) ||
55ccadf154SRussell Currey 	    (strcmp(name, "grubdbx") == 0) ||
56ccadf154SRussell Currey 	    (strcmp(name, "sbat") == 0))
57ccadf154SRussell Currey 		return (PLPKS_WORLDREADABLE | PLPKS_SIGNEDUPDATE);
58ccadf154SRussell Currey 	else
59ccadf154SRussell Currey 		return PLPKS_SIGNEDUPDATE;
60ccadf154SRussell Currey }
61ccadf154SRussell Currey 
62ccadf154SRussell Currey static const char * const plpks_var_names[] = {
63ccadf154SRussell Currey 	"PK",
64ccadf154SRussell Currey 	"KEK",
65ccadf154SRussell Currey 	"db",
66ccadf154SRussell Currey 	"dbx",
67ccadf154SRussell Currey 	"grubdb",
68ccadf154SRussell Currey 	"grubdbx",
69ccadf154SRussell Currey 	"sbat",
70ccadf154SRussell Currey 	"moduledb",
71ccadf154SRussell Currey 	"trustedcadb",
72ccadf154SRussell Currey 	NULL,
73ccadf154SRussell Currey };
74ccadf154SRussell Currey 
plpks_get_variable(const char * key,u64 key_len,u8 * data,u64 * data_size)75ccadf154SRussell Currey static int plpks_get_variable(const char *key, u64 key_len, u8 *data,
76ccadf154SRussell Currey 			      u64 *data_size)
77ccadf154SRussell Currey {
78ccadf154SRussell Currey 	struct plpks_var var = {0};
79ccadf154SRussell Currey 	int rc = 0;
80ccadf154SRussell Currey 
81ccadf154SRussell Currey 	// We subtract 1 from key_len because we don't need to include the
82ccadf154SRussell Currey 	// null terminator at the end of the string
83ccadf154SRussell Currey 	var.name = kcalloc(key_len - 1, sizeof(wchar_t), GFP_KERNEL);
84ccadf154SRussell Currey 	if (!var.name)
85ccadf154SRussell Currey 		return -ENOMEM;
86ccadf154SRussell Currey 	rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN, (wchar_t *)var.name,
87ccadf154SRussell Currey 			     key_len - 1);
88ccadf154SRussell Currey 	if (rc < 0)
89ccadf154SRussell Currey 		goto err;
90ccadf154SRussell Currey 	var.namelen = rc * 2;
91ccadf154SRussell Currey 
92ccadf154SRussell Currey 	var.os = PLPKS_VAR_LINUX;
93ccadf154SRussell Currey 	if (data) {
94ccadf154SRussell Currey 		var.data = data;
95ccadf154SRussell Currey 		var.datalen = *data_size;
96ccadf154SRussell Currey 	}
97ccadf154SRussell Currey 	rc = plpks_read_os_var(&var);
98ccadf154SRussell Currey 
99ccadf154SRussell Currey 	if (rc)
100ccadf154SRussell Currey 		goto err;
101ccadf154SRussell Currey 
102ccadf154SRussell Currey 	*data_size = var.datalen;
103ccadf154SRussell Currey 
104ccadf154SRussell Currey err:
105ccadf154SRussell Currey 	kfree(var.name);
106ccadf154SRussell Currey 	if (rc && rc != -ENOENT) {
107ccadf154SRussell Currey 		pr_err("Failed to read variable '%s': %d\n", key, rc);
108ccadf154SRussell Currey 		// Return -EIO since userspace probably doesn't care about the
109ccadf154SRussell Currey 		// specific error
110ccadf154SRussell Currey 		rc = -EIO;
111ccadf154SRussell Currey 	}
112ccadf154SRussell Currey 	return rc;
113ccadf154SRussell Currey }
114ccadf154SRussell Currey 
plpks_set_variable(const char * key,u64 key_len,u8 * data,u64 data_size)115ccadf154SRussell Currey static int plpks_set_variable(const char *key, u64 key_len, u8 *data,
116ccadf154SRussell Currey 			      u64 data_size)
117ccadf154SRussell Currey {
118ccadf154SRussell Currey 	struct plpks_var var = {0};
119ccadf154SRussell Currey 	int rc = 0;
120ccadf154SRussell Currey 	u64 flags;
121ccadf154SRussell Currey 
122ccadf154SRussell Currey 	// Secure variables need to be prefixed with 8 bytes of flags.
123ccadf154SRussell Currey 	// We only want to perform the write if we have at least one byte of data.
124ccadf154SRussell Currey 	if (data_size <= sizeof(flags))
125ccadf154SRussell Currey 		return -EINVAL;
126ccadf154SRussell Currey 
127ccadf154SRussell Currey 	// We subtract 1 from key_len because we don't need to include the
128ccadf154SRussell Currey 	// null terminator at the end of the string
129ccadf154SRussell Currey 	var.name = kcalloc(key_len - 1, sizeof(wchar_t), GFP_KERNEL);
130ccadf154SRussell Currey 	if (!var.name)
131ccadf154SRussell Currey 		return -ENOMEM;
132ccadf154SRussell Currey 	rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN, (wchar_t *)var.name,
133ccadf154SRussell Currey 			     key_len - 1);
134ccadf154SRussell Currey 	if (rc < 0)
135ccadf154SRussell Currey 		goto err;
136ccadf154SRussell Currey 	var.namelen = rc * 2;
137ccadf154SRussell Currey 
138*7096deb7SAndrew Donnellan 	// Flags are contained in the first 8 bytes of the buffer, and are always big-endian
139*7096deb7SAndrew Donnellan 	flags = be64_to_cpup((__be64 *)data);
140ccadf154SRussell Currey 
141ccadf154SRussell Currey 	var.datalen = data_size - sizeof(flags);
142ccadf154SRussell Currey 	var.data = data + sizeof(flags);
143ccadf154SRussell Currey 	var.os = PLPKS_VAR_LINUX;
144ccadf154SRussell Currey 	var.policy = get_policy(key);
145ccadf154SRussell Currey 
146ccadf154SRussell Currey 	// Unlike in the read case, the plpks error code can be useful to
147ccadf154SRussell Currey 	// userspace on write, so we return it rather than just -EIO
148ccadf154SRussell Currey 	rc = plpks_signed_update_var(&var, flags);
149ccadf154SRussell Currey 
150ccadf154SRussell Currey err:
151ccadf154SRussell Currey 	kfree(var.name);
152ccadf154SRussell Currey 	return rc;
153ccadf154SRussell Currey }
154ccadf154SRussell Currey 
155ccadf154SRussell Currey // PLPKS dynamic secure boot doesn't give us a format string in the same way OPAL does.
156ccadf154SRussell Currey // Instead, report the format using the SB_VERSION variable in the keystore.
157ccadf154SRussell Currey // The string is made up by us, and takes the form "ibm,plpks-sb-v<n>" (or "ibm,plpks-sb-unknown"
158ccadf154SRussell Currey // if the SB_VERSION variable doesn't exist). Hypervisor defines the SB_VERSION variable as a
159ccadf154SRussell Currey // "1 byte unsigned integer value".
plpks_secvar_format(char * buf,size_t bufsize)160ccadf154SRussell Currey static ssize_t plpks_secvar_format(char *buf, size_t bufsize)
161ccadf154SRussell Currey {
162ccadf154SRussell Currey 	struct plpks_var var = {0};
163ccadf154SRussell Currey 	ssize_t ret;
164ccadf154SRussell Currey 	u8 version;
165ccadf154SRussell Currey 
166ccadf154SRussell Currey 	var.component = NULL;
167ccadf154SRussell Currey 	// Only the signed variables have null bytes in their names, this one doesn't
168ccadf154SRussell Currey 	var.name = "SB_VERSION";
169ccadf154SRussell Currey 	var.namelen = strlen(var.name);
170ccadf154SRussell Currey 	var.datalen = 1;
171ccadf154SRussell Currey 	var.data = &version;
172ccadf154SRussell Currey 
173ccadf154SRussell Currey 	// Unlike the other vars, SB_VERSION is owned by firmware instead of the OS
174ccadf154SRussell Currey 	ret = plpks_read_fw_var(&var);
175ccadf154SRussell Currey 	if (ret) {
176ccadf154SRussell Currey 		if (ret == -ENOENT) {
177ccadf154SRussell Currey 			ret = snprintf(buf, bufsize, "ibm,plpks-sb-unknown");
178ccadf154SRussell Currey 		} else {
179ccadf154SRussell Currey 			pr_err("Error %ld reading SB_VERSION from firmware\n", ret);
180ccadf154SRussell Currey 			ret = -EIO;
181ccadf154SRussell Currey 		}
182ccadf154SRussell Currey 		goto err;
183ccadf154SRussell Currey 	}
184ccadf154SRussell Currey 
185ccadf154SRussell Currey 	ret = snprintf(buf, bufsize, "ibm,plpks-sb-v%hhu", version);
186ccadf154SRussell Currey err:
187ccadf154SRussell Currey 	return ret;
188ccadf154SRussell Currey }
189ccadf154SRussell Currey 
plpks_max_size(u64 * max_size)190ccadf154SRussell Currey static int plpks_max_size(u64 *max_size)
191ccadf154SRussell Currey {
192ccadf154SRussell Currey 	// The max object size reported by the hypervisor is accurate for the
193ccadf154SRussell Currey 	// object itself, but we use the first 8 bytes of data on write as the
194ccadf154SRussell Currey 	// signed update flags, so the max size a user can write is larger.
195ccadf154SRussell Currey 	*max_size = (u64)plpks_get_maxobjectsize() + sizeof(u64);
196ccadf154SRussell Currey 
197ccadf154SRussell Currey 	return 0;
198ccadf154SRussell Currey }
199ccadf154SRussell Currey 
200ccadf154SRussell Currey 
201ccadf154SRussell Currey static const struct secvar_operations plpks_secvar_ops = {
202ccadf154SRussell Currey 	.get = plpks_get_variable,
203ccadf154SRussell Currey 	.set = plpks_set_variable,
204ccadf154SRussell Currey 	.format = plpks_secvar_format,
205ccadf154SRussell Currey 	.max_size = plpks_max_size,
206ccadf154SRussell Currey 	.config_attrs = config_attrs,
207ccadf154SRussell Currey 	.var_names = plpks_var_names,
208ccadf154SRussell Currey };
209ccadf154SRussell Currey 
plpks_secvar_init(void)210ccadf154SRussell Currey static int plpks_secvar_init(void)
211ccadf154SRussell Currey {
212ccadf154SRussell Currey 	if (!plpks_is_available())
213ccadf154SRussell Currey 		return -ENODEV;
214ccadf154SRussell Currey 
215ccadf154SRussell Currey 	return set_secvar_ops(&plpks_secvar_ops);
216ccadf154SRussell Currey }
217ccadf154SRussell Currey machine_device_initcall(pseries, plpks_secvar_init);
218