xref: /linux/drivers/virt/coco/tsm.c (revision 24168c5e6dfbdd5b414f048f47f75d64533296ca)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright(c) 2023 Intel Corporation. All rights reserved. */
3 
4 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
5 
6 #include <linux/tsm.h>
7 #include <linux/err.h>
8 #include <linux/slab.h>
9 #include <linux/rwsem.h>
10 #include <linux/string.h>
11 #include <linux/module.h>
12 #include <linux/cleanup.h>
13 #include <linux/configfs.h>
14 
15 static struct tsm_provider {
16 	const struct tsm_ops *ops;
17 	const struct config_item_type *type;
18 	void *data;
19 } provider;
20 static DECLARE_RWSEM(tsm_rwsem);
21 
22 /**
23  * DOC: Trusted Security Module (TSM) Attestation Report Interface
24  *
25  * The TSM report interface is a common provider of blobs that facilitate
26  * attestation of a TVM (confidential computing guest) by an attestation
27  * service. A TSM report combines a user-defined blob (likely a public-key with
28  * a nonce for a key-exchange protocol) with a signed attestation report. That
29  * combined blob is then used to obtain secrets provided by an agent that can
30  * validate the attestation report. The expectation is that this interface is
31  * invoked infrequently, however configfs allows for multiple agents to
32  * own their own report generation instances to generate reports as
33  * often as needed.
34  *
35  * The attestation report format is TSM provider specific, when / if a standard
36  * materializes that can be published instead of the vendor layout. Until then
37  * the 'provider' attribute indicates the format of 'outblob', and optionally
38  * 'auxblob'.
39  */
40 
41 struct tsm_report_state {
42 	struct tsm_report report;
43 	unsigned long write_generation;
44 	unsigned long read_generation;
45 	struct config_item cfg;
46 };
47 
48 enum tsm_data_select {
49 	TSM_REPORT,
50 	TSM_CERTS,
51 };
52 
53 static struct tsm_report *to_tsm_report(struct config_item *cfg)
54 {
55 	struct tsm_report_state *state =
56 		container_of(cfg, struct tsm_report_state, cfg);
57 
58 	return &state->report;
59 }
60 
61 static struct tsm_report_state *to_state(struct tsm_report *report)
62 {
63 	return container_of(report, struct tsm_report_state, report);
64 }
65 
66 static int try_advance_write_generation(struct tsm_report *report)
67 {
68 	struct tsm_report_state *state = to_state(report);
69 
70 	lockdep_assert_held_write(&tsm_rwsem);
71 
72 	/*
73 	 * Malicious or broken userspace has written enough times for
74 	 * read_generation == write_generation by modular arithmetic without an
75 	 * interim read. Stop accepting updates until the current report
76 	 * configuration is read.
77 	 */
78 	if (state->write_generation == state->read_generation - 1)
79 		return -EBUSY;
80 	state->write_generation++;
81 	return 0;
82 }
83 
84 static ssize_t tsm_report_privlevel_store(struct config_item *cfg,
85 					  const char *buf, size_t len)
86 {
87 	struct tsm_report *report = to_tsm_report(cfg);
88 	unsigned int val;
89 	int rc;
90 
91 	rc = kstrtouint(buf, 0, &val);
92 	if (rc)
93 		return rc;
94 
95 	/*
96 	 * The valid privilege levels that a TSM might accept, if it accepts a
97 	 * privilege level setting at all, are a max of TSM_PRIVLEVEL_MAX (see
98 	 * SEV-SNP GHCB) and a minimum of a TSM selected floor value no less
99 	 * than 0.
100 	 */
101 	if (provider.ops->privlevel_floor > val || val > TSM_PRIVLEVEL_MAX)
102 		return -EINVAL;
103 
104 	guard(rwsem_write)(&tsm_rwsem);
105 	rc = try_advance_write_generation(report);
106 	if (rc)
107 		return rc;
108 	report->desc.privlevel = val;
109 
110 	return len;
111 }
112 CONFIGFS_ATTR_WO(tsm_report_, privlevel);
113 
114 static ssize_t tsm_report_privlevel_floor_show(struct config_item *cfg,
115 					       char *buf)
116 {
117 	guard(rwsem_read)(&tsm_rwsem);
118 	return sysfs_emit(buf, "%u\n", provider.ops->privlevel_floor);
119 }
120 CONFIGFS_ATTR_RO(tsm_report_, privlevel_floor);
121 
122 static ssize_t tsm_report_inblob_write(struct config_item *cfg,
123 				       const void *buf, size_t count)
124 {
125 	struct tsm_report *report = to_tsm_report(cfg);
126 	int rc;
127 
128 	guard(rwsem_write)(&tsm_rwsem);
129 	rc = try_advance_write_generation(report);
130 	if (rc)
131 		return rc;
132 
133 	report->desc.inblob_len = count;
134 	memcpy(report->desc.inblob, buf, count);
135 	return count;
136 }
137 CONFIGFS_BIN_ATTR_WO(tsm_report_, inblob, NULL, TSM_INBLOB_MAX);
138 
139 static ssize_t tsm_report_generation_show(struct config_item *cfg, char *buf)
140 {
141 	struct tsm_report *report = to_tsm_report(cfg);
142 	struct tsm_report_state *state = to_state(report);
143 
144 	guard(rwsem_read)(&tsm_rwsem);
145 	return sysfs_emit(buf, "%lu\n", state->write_generation);
146 }
147 CONFIGFS_ATTR_RO(tsm_report_, generation);
148 
149 static ssize_t tsm_report_provider_show(struct config_item *cfg, char *buf)
150 {
151 	guard(rwsem_read)(&tsm_rwsem);
152 	return sysfs_emit(buf, "%s\n", provider.ops->name);
153 }
154 CONFIGFS_ATTR_RO(tsm_report_, provider);
155 
156 static ssize_t __read_report(struct tsm_report *report, void *buf, size_t count,
157 			     enum tsm_data_select select)
158 {
159 	loff_t offset = 0;
160 	ssize_t len;
161 	u8 *out;
162 
163 	if (select == TSM_REPORT) {
164 		out = report->outblob;
165 		len = report->outblob_len;
166 	} else {
167 		out = report->auxblob;
168 		len = report->auxblob_len;
169 	}
170 
171 	/*
172 	 * Recall that a NULL @buf is configfs requesting the size of
173 	 * the buffer.
174 	 */
175 	if (!buf)
176 		return len;
177 	return memory_read_from_buffer(buf, count, &offset, out, len);
178 }
179 
180 static ssize_t read_cached_report(struct tsm_report *report, void *buf,
181 				  size_t count, enum tsm_data_select select)
182 {
183 	struct tsm_report_state *state = to_state(report);
184 
185 	guard(rwsem_read)(&tsm_rwsem);
186 	if (!report->desc.inblob_len)
187 		return -EINVAL;
188 
189 	/*
190 	 * A given TSM backend always fills in ->outblob regardless of
191 	 * whether the report includes an auxblob or not.
192 	 */
193 	if (!report->outblob ||
194 	    state->read_generation != state->write_generation)
195 		return -EWOULDBLOCK;
196 
197 	return __read_report(report, buf, count, select);
198 }
199 
200 static ssize_t tsm_report_read(struct tsm_report *report, void *buf,
201 			       size_t count, enum tsm_data_select select)
202 {
203 	struct tsm_report_state *state = to_state(report);
204 	const struct tsm_ops *ops;
205 	ssize_t rc;
206 
207 	/* try to read from the existing report if present and valid... */
208 	rc = read_cached_report(report, buf, count, select);
209 	if (rc >= 0 || rc != -EWOULDBLOCK)
210 		return rc;
211 
212 	/* slow path, report may need to be regenerated... */
213 	guard(rwsem_write)(&tsm_rwsem);
214 	ops = provider.ops;
215 	if (!ops)
216 		return -ENOTTY;
217 	if (!report->desc.inblob_len)
218 		return -EINVAL;
219 
220 	/* did another thread already generate this report? */
221 	if (report->outblob &&
222 	    state->read_generation == state->write_generation)
223 		goto out;
224 
225 	kvfree(report->outblob);
226 	kvfree(report->auxblob);
227 	report->outblob = NULL;
228 	report->auxblob = NULL;
229 	rc = ops->report_new(report, provider.data);
230 	if (rc < 0)
231 		return rc;
232 	state->read_generation = state->write_generation;
233 out:
234 	return __read_report(report, buf, count, select);
235 }
236 
237 static ssize_t tsm_report_outblob_read(struct config_item *cfg, void *buf,
238 				       size_t count)
239 {
240 	struct tsm_report *report = to_tsm_report(cfg);
241 
242 	return tsm_report_read(report, buf, count, TSM_REPORT);
243 }
244 CONFIGFS_BIN_ATTR_RO(tsm_report_, outblob, NULL, TSM_OUTBLOB_MAX);
245 
246 static ssize_t tsm_report_auxblob_read(struct config_item *cfg, void *buf,
247 				       size_t count)
248 {
249 	struct tsm_report *report = to_tsm_report(cfg);
250 
251 	return tsm_report_read(report, buf, count, TSM_CERTS);
252 }
253 CONFIGFS_BIN_ATTR_RO(tsm_report_, auxblob, NULL, TSM_OUTBLOB_MAX);
254 
255 #define TSM_DEFAULT_ATTRS() \
256 	&tsm_report_attr_generation, \
257 	&tsm_report_attr_provider
258 
259 static struct configfs_attribute *tsm_report_attrs[] = {
260 	TSM_DEFAULT_ATTRS(),
261 	NULL,
262 };
263 
264 static struct configfs_attribute *tsm_report_extra_attrs[] = {
265 	TSM_DEFAULT_ATTRS(),
266 	&tsm_report_attr_privlevel,
267 	&tsm_report_attr_privlevel_floor,
268 	NULL,
269 };
270 
271 #define TSM_DEFAULT_BIN_ATTRS() \
272 	&tsm_report_attr_inblob, \
273 	&tsm_report_attr_outblob
274 
275 static struct configfs_bin_attribute *tsm_report_bin_attrs[] = {
276 	TSM_DEFAULT_BIN_ATTRS(),
277 	NULL,
278 };
279 
280 static struct configfs_bin_attribute *tsm_report_bin_extra_attrs[] = {
281 	TSM_DEFAULT_BIN_ATTRS(),
282 	&tsm_report_attr_auxblob,
283 	NULL,
284 };
285 
286 static void tsm_report_item_release(struct config_item *cfg)
287 {
288 	struct tsm_report *report = to_tsm_report(cfg);
289 	struct tsm_report_state *state = to_state(report);
290 
291 	kvfree(report->auxblob);
292 	kvfree(report->outblob);
293 	kfree(state);
294 }
295 
296 static struct configfs_item_operations tsm_report_item_ops = {
297 	.release = tsm_report_item_release,
298 };
299 
300 const struct config_item_type tsm_report_default_type = {
301 	.ct_owner = THIS_MODULE,
302 	.ct_bin_attrs = tsm_report_bin_attrs,
303 	.ct_attrs = tsm_report_attrs,
304 	.ct_item_ops = &tsm_report_item_ops,
305 };
306 EXPORT_SYMBOL_GPL(tsm_report_default_type);
307 
308 const struct config_item_type tsm_report_extra_type = {
309 	.ct_owner = THIS_MODULE,
310 	.ct_bin_attrs = tsm_report_bin_extra_attrs,
311 	.ct_attrs = tsm_report_extra_attrs,
312 	.ct_item_ops = &tsm_report_item_ops,
313 };
314 EXPORT_SYMBOL_GPL(tsm_report_extra_type);
315 
316 static struct config_item *tsm_report_make_item(struct config_group *group,
317 						const char *name)
318 {
319 	struct tsm_report_state *state;
320 
321 	guard(rwsem_read)(&tsm_rwsem);
322 	if (!provider.ops)
323 		return ERR_PTR(-ENXIO);
324 
325 	state = kzalloc(sizeof(*state), GFP_KERNEL);
326 	if (!state)
327 		return ERR_PTR(-ENOMEM);
328 
329 	config_item_init_type_name(&state->cfg, name, provider.type);
330 	return &state->cfg;
331 }
332 
333 static struct configfs_group_operations tsm_report_group_ops = {
334 	.make_item = tsm_report_make_item,
335 };
336 
337 static const struct config_item_type tsm_reports_type = {
338 	.ct_owner = THIS_MODULE,
339 	.ct_group_ops = &tsm_report_group_ops,
340 };
341 
342 static const struct config_item_type tsm_root_group_type = {
343 	.ct_owner = THIS_MODULE,
344 };
345 
346 static struct configfs_subsystem tsm_configfs = {
347 	.su_group = {
348 		.cg_item = {
349 			.ci_namebuf = "tsm",
350 			.ci_type = &tsm_root_group_type,
351 		},
352 	},
353 	.su_mutex = __MUTEX_INITIALIZER(tsm_configfs.su_mutex),
354 };
355 
356 int tsm_register(const struct tsm_ops *ops, void *priv,
357 		 const struct config_item_type *type)
358 {
359 	const struct tsm_ops *conflict;
360 
361 	if (!type)
362 		type = &tsm_report_default_type;
363 	if (!(type == &tsm_report_default_type || type == &tsm_report_extra_type))
364 		return -EINVAL;
365 
366 	guard(rwsem_write)(&tsm_rwsem);
367 	conflict = provider.ops;
368 	if (conflict) {
369 		pr_err("\"%s\" ops already registered\n", conflict->name);
370 		return -EBUSY;
371 	}
372 
373 	provider.ops = ops;
374 	provider.data = priv;
375 	provider.type = type;
376 	return 0;
377 }
378 EXPORT_SYMBOL_GPL(tsm_register);
379 
380 int tsm_unregister(const struct tsm_ops *ops)
381 {
382 	guard(rwsem_write)(&tsm_rwsem);
383 	if (ops != provider.ops)
384 		return -EBUSY;
385 	provider.ops = NULL;
386 	provider.data = NULL;
387 	provider.type = NULL;
388 	return 0;
389 }
390 EXPORT_SYMBOL_GPL(tsm_unregister);
391 
392 static struct config_group *tsm_report_group;
393 
394 static int __init tsm_init(void)
395 {
396 	struct config_group *root = &tsm_configfs.su_group;
397 	struct config_group *tsm;
398 	int rc;
399 
400 	config_group_init(root);
401 	rc = configfs_register_subsystem(&tsm_configfs);
402 	if (rc)
403 		return rc;
404 
405 	tsm = configfs_register_default_group(root, "report",
406 					      &tsm_reports_type);
407 	if (IS_ERR(tsm)) {
408 		configfs_unregister_subsystem(&tsm_configfs);
409 		return PTR_ERR(tsm);
410 	}
411 	tsm_report_group = tsm;
412 
413 	return 0;
414 }
415 module_init(tsm_init);
416 
417 static void __exit tsm_exit(void)
418 {
419 	configfs_unregister_default_group(tsm_report_group);
420 	configfs_unregister_subsystem(&tsm_configfs);
421 }
422 module_exit(tsm_exit);
423 
424 MODULE_LICENSE("GPL");
425 MODULE_DESCRIPTION("Provide Trusted Security Module attestation reports via configfs");
426