xref: /linux/arch/powerpc/platforms/pseries/plpks-secvar.c (revision be1ca3ee8f97067fee87fda73ea5959d5ab75bbf)
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 static u32 get_policy(const char *name)
24 {
25 	if ((strcmp(name, "db") == 0) ||
26 	    (strcmp(name, "dbx") == 0) ||
27 	    (strcmp(name, "grubdb") == 0) ||
28 	    (strcmp(name, "grubdbx") == 0) ||
29 	    (strcmp(name, "sbat") == 0))
30 		return (PLPKS_WORLDREADABLE | PLPKS_SIGNEDUPDATE);
31 	else
32 		return PLPKS_SIGNEDUPDATE;
33 }
34 
35 static const char * const plpks_var_names_static[] = {
36 	"PK",
37 	"moduledb",
38 	"trustedcadb",
39 	NULL,
40 };
41 
42 static const char * const plpks_var_names_dynamic[] = {
43 	"PK",
44 	"KEK",
45 	"db",
46 	"dbx",
47 	"grubdb",
48 	"grubdbx",
49 	"sbat",
50 	"moduledb",
51 	"trustedcadb",
52 	NULL,
53 };
54 
55 static int plpks_get_variable(const char *key, u64 key_len, u8 *data,
56 			      u64 *data_size)
57 {
58 	struct plpks_var var = {0};
59 	int rc = 0;
60 
61 	// We subtract 1 from key_len because we don't need to include the
62 	// null terminator at the end of the string
63 	var.name = kcalloc(key_len - 1, sizeof(wchar_t), GFP_KERNEL);
64 	if (!var.name)
65 		return -ENOMEM;
66 	rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN, (wchar_t *)var.name,
67 			     key_len - 1);
68 	if (rc < 0)
69 		goto err;
70 	var.namelen = rc * 2;
71 
72 	var.os = PLPKS_VAR_LINUX;
73 	if (data) {
74 		var.data = data;
75 		var.datalen = *data_size;
76 	}
77 	rc = plpks_read_os_var(&var);
78 
79 	if (rc)
80 		goto err;
81 
82 	*data_size = var.datalen;
83 
84 err:
85 	kfree(var.name);
86 	if (rc && rc != -ENOENT) {
87 		pr_err("Failed to read variable '%s': %d\n", key, rc);
88 		// Return -EIO since userspace probably doesn't care about the
89 		// specific error
90 		rc = -EIO;
91 	}
92 	return rc;
93 }
94 
95 static int plpks_set_variable(const char *key, u64 key_len, u8 *data,
96 			      u64 data_size)
97 {
98 	struct plpks_var var = {0};
99 	int rc = 0;
100 	u64 flags;
101 
102 	// Secure variables need to be prefixed with 8 bytes of flags.
103 	// We only want to perform the write if we have at least one byte of data.
104 	if (data_size <= sizeof(flags))
105 		return -EINVAL;
106 
107 	// We subtract 1 from key_len because we don't need to include the
108 	// null terminator at the end of the string
109 	var.name = kcalloc(key_len - 1, sizeof(wchar_t), GFP_KERNEL);
110 	if (!var.name)
111 		return -ENOMEM;
112 	rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN, (wchar_t *)var.name,
113 			     key_len - 1);
114 	if (rc < 0)
115 		goto err;
116 	var.namelen = rc * 2;
117 
118 	// Flags are contained in the first 8 bytes of the buffer, and are always big-endian
119 	flags = be64_to_cpup((__be64 *)data);
120 
121 	var.datalen = data_size - sizeof(flags);
122 	var.data = data + sizeof(flags);
123 	var.os = PLPKS_VAR_LINUX;
124 	var.policy = get_policy(key);
125 
126 	// Unlike in the read case, the plpks error code can be useful to
127 	// userspace on write, so we return it rather than just -EIO
128 	rc = plpks_signed_update_var(&var, flags);
129 
130 err:
131 	kfree(var.name);
132 	return rc;
133 }
134 
135 /*
136  * Return the key management mode.
137  *
138  * SB_VERSION is defined as a "1 byte unsigned integer value", taking values
139  * starting from 1. It is owned by the Partition Firmware and its presence
140  * indicates that the key management mode is dynamic. Any failure in
141  * reading SB_VERSION defaults the key management mode to static. The error
142  * codes -ENOENT or -EPERM are expected in static key management mode. An
143  * unexpected error code will have to be investigated. Only signed variables
144  * have null bytes in their names, SB_VERSION does not.
145  *
146  * Return 0 to indicate that the key management mode is static. Otherwise
147  * return the SB_VERSION value to indicate that the key management mode is
148  * dynamic.
149  */
150 static u8 plpks_get_sb_keymgmt_mode(void)
151 {
152 	u8 mode;
153 	ssize_t rc;
154 	struct plpks_var var = {
155 		.component = NULL,
156 		.name = "SB_VERSION",
157 		.namelen = 10,
158 		.datalen = 1,
159 		.data = &mode,
160 	};
161 
162 	rc = plpks_read_fw_var(&var);
163 	if (rc) {
164 		if (rc != -ENOENT && rc != -EPERM)
165 			pr_info("Error %ld reading SB_VERSION from firmware\n", rc);
166 		mode = 0;
167 	}
168 	return mode;
169 }
170 
171 /*
172  * PLPKS dynamic secure boot doesn't give us a format string in the same way
173  * OPAL does. Instead, report the format using the SB_VERSION variable in the
174  * keystore. The string, made up by us, takes the form of either
175  * "ibm,plpks-sb-v<n>" or "ibm,plpks-sb-v0", based on the key management mode,
176  * and return the length of the secvar format property.
177  */
178 static ssize_t plpks_secvar_format(char *buf, size_t bufsize)
179 {
180 	u8 mode;
181 
182 	mode = plpks_get_sb_keymgmt_mode();
183 	return snprintf(buf, bufsize, "ibm,plpks-sb-v%hhu", mode);
184 }
185 
186 static int plpks_max_size(u64 *max_size)
187 {
188 	// The max object size reported by the hypervisor is accurate for the
189 	// object itself, but we use the first 8 bytes of data on write as the
190 	// signed update flags, so the max size a user can write is larger.
191 	*max_size = (u64)plpks_get_maxobjectsize() + sizeof(u64);
192 
193 	return 0;
194 }
195 
196 static const struct secvar_operations plpks_secvar_ops_static = {
197 	.get = plpks_get_variable,
198 	.set = plpks_set_variable,
199 	.format = plpks_secvar_format,
200 	.max_size = plpks_max_size,
201 	.var_names = plpks_var_names_static,
202 };
203 
204 static const struct secvar_operations plpks_secvar_ops_dynamic = {
205 	.get = plpks_get_variable,
206 	.set = plpks_set_variable,
207 	.format = plpks_secvar_format,
208 	.max_size = plpks_max_size,
209 	.var_names = plpks_var_names_dynamic,
210 };
211 
212 static int plpks_secvar_init(void)
213 {
214 	u8 mode;
215 
216 	if (!plpks_is_available())
217 		return -ENODEV;
218 
219 	mode = plpks_get_sb_keymgmt_mode();
220 	if (mode)
221 		return set_secvar_ops(&plpks_secvar_ops_dynamic);
222 	return set_secvar_ops(&plpks_secvar_ops_static);
223 }
224 machine_device_initcall(pseries, plpks_secvar_init);
225