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