xref: /linux/drivers/virt/coco/tsm.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
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 	void *data;
18 } provider;
19 static DECLARE_RWSEM(tsm_rwsem);
20 
21 /**
22  * DOC: Trusted Security Module (TSM) Attestation Report Interface
23  *
24  * The TSM report interface is a common provider of blobs that facilitate
25  * attestation of a TVM (confidential computing guest) by an attestation
26  * service. A TSM report combines a user-defined blob (likely a public-key with
27  * a nonce for a key-exchange protocol) with a signed attestation report. That
28  * combined blob is then used to obtain secrets provided by an agent that can
29  * validate the attestation report. The expectation is that this interface is
30  * invoked infrequently, however configfs allows for multiple agents to
31  * own their own report generation instances to generate reports as
32  * often as needed.
33  *
34  * The attestation report format is TSM provider specific, when / if a standard
35  * materializes that can be published instead of the vendor layout. Until then
36  * the 'provider' attribute indicates the format of 'outblob', and optionally
37  * 'auxblob' and 'manifestblob'.
38  */
39 
40 struct tsm_report_state {
41 	struct tsm_report report;
42 	unsigned long write_generation;
43 	unsigned long read_generation;
44 	struct config_item cfg;
45 };
46 
47 enum tsm_data_select {
48 	TSM_REPORT,
49 	TSM_CERTS,
50 	TSM_MANIFEST,
51 };
52 
to_tsm_report(struct config_item * cfg)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 
to_state(struct tsm_report * report)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 
try_advance_write_generation(struct tsm_report * report)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 
tsm_report_privlevel_store(struct config_item * cfg,const char * buf,size_t len)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 
tsm_report_privlevel_floor_show(struct config_item * cfg,char * buf)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 
tsm_report_service_provider_store(struct config_item * cfg,const char * buf,size_t len)122 static ssize_t tsm_report_service_provider_store(struct config_item *cfg,
123 						 const char *buf, size_t len)
124 {
125 	struct tsm_report *report = to_tsm_report(cfg);
126 	size_t sp_len;
127 	char *sp;
128 	int rc;
129 
130 	guard(rwsem_write)(&tsm_rwsem);
131 	rc = try_advance_write_generation(report);
132 	if (rc)
133 		return rc;
134 
135 	sp_len = (buf[len - 1] != '\n') ? len : len - 1;
136 
137 	sp = kstrndup(buf, sp_len, GFP_KERNEL);
138 	if (!sp)
139 		return -ENOMEM;
140 	kfree(report->desc.service_provider);
141 
142 	report->desc.service_provider = sp;
143 
144 	return len;
145 }
146 CONFIGFS_ATTR_WO(tsm_report_, service_provider);
147 
tsm_report_service_guid_store(struct config_item * cfg,const char * buf,size_t len)148 static ssize_t tsm_report_service_guid_store(struct config_item *cfg,
149 					     const char *buf, size_t len)
150 {
151 	struct tsm_report *report = to_tsm_report(cfg);
152 	int rc;
153 
154 	guard(rwsem_write)(&tsm_rwsem);
155 	rc = try_advance_write_generation(report);
156 	if (rc)
157 		return rc;
158 
159 	report->desc.service_guid = guid_null;
160 
161 	rc = guid_parse(buf, &report->desc.service_guid);
162 	if (rc)
163 		return rc;
164 
165 	return len;
166 }
167 CONFIGFS_ATTR_WO(tsm_report_, service_guid);
168 
tsm_report_service_manifest_version_store(struct config_item * cfg,const char * buf,size_t len)169 static ssize_t tsm_report_service_manifest_version_store(struct config_item *cfg,
170 							 const char *buf, size_t len)
171 {
172 	struct tsm_report *report = to_tsm_report(cfg);
173 	unsigned int val;
174 	int rc;
175 
176 	rc = kstrtouint(buf, 0, &val);
177 	if (rc)
178 		return rc;
179 
180 	guard(rwsem_write)(&tsm_rwsem);
181 	rc = try_advance_write_generation(report);
182 	if (rc)
183 		return rc;
184 	report->desc.service_manifest_version = val;
185 
186 	return len;
187 }
188 CONFIGFS_ATTR_WO(tsm_report_, service_manifest_version);
189 
tsm_report_inblob_write(struct config_item * cfg,const void * buf,size_t count)190 static ssize_t tsm_report_inblob_write(struct config_item *cfg,
191 				       const void *buf, size_t count)
192 {
193 	struct tsm_report *report = to_tsm_report(cfg);
194 	int rc;
195 
196 	guard(rwsem_write)(&tsm_rwsem);
197 	rc = try_advance_write_generation(report);
198 	if (rc)
199 		return rc;
200 
201 	report->desc.inblob_len = count;
202 	memcpy(report->desc.inblob, buf, count);
203 	return count;
204 }
205 CONFIGFS_BIN_ATTR_WO(tsm_report_, inblob, NULL, TSM_INBLOB_MAX);
206 
tsm_report_generation_show(struct config_item * cfg,char * buf)207 static ssize_t tsm_report_generation_show(struct config_item *cfg, char *buf)
208 {
209 	struct tsm_report *report = to_tsm_report(cfg);
210 	struct tsm_report_state *state = to_state(report);
211 
212 	guard(rwsem_read)(&tsm_rwsem);
213 	return sysfs_emit(buf, "%lu\n", state->write_generation);
214 }
215 CONFIGFS_ATTR_RO(tsm_report_, generation);
216 
tsm_report_provider_show(struct config_item * cfg,char * buf)217 static ssize_t tsm_report_provider_show(struct config_item *cfg, char *buf)
218 {
219 	guard(rwsem_read)(&tsm_rwsem);
220 	return sysfs_emit(buf, "%s\n", provider.ops->name);
221 }
222 CONFIGFS_ATTR_RO(tsm_report_, provider);
223 
__read_report(struct tsm_report * report,void * buf,size_t count,enum tsm_data_select select)224 static ssize_t __read_report(struct tsm_report *report, void *buf, size_t count,
225 			     enum tsm_data_select select)
226 {
227 	loff_t offset = 0;
228 	ssize_t len;
229 	u8 *out;
230 
231 	if (select == TSM_REPORT) {
232 		out = report->outblob;
233 		len = report->outblob_len;
234 	} else if (select == TSM_MANIFEST) {
235 		out = report->manifestblob;
236 		len = report->manifestblob_len;
237 	} else {
238 		out = report->auxblob;
239 		len = report->auxblob_len;
240 	}
241 
242 	/*
243 	 * Recall that a NULL @buf is configfs requesting the size of
244 	 * the buffer.
245 	 */
246 	if (!buf)
247 		return len;
248 	return memory_read_from_buffer(buf, count, &offset, out, len);
249 }
250 
read_cached_report(struct tsm_report * report,void * buf,size_t count,enum tsm_data_select select)251 static ssize_t read_cached_report(struct tsm_report *report, void *buf,
252 				  size_t count, enum tsm_data_select select)
253 {
254 	struct tsm_report_state *state = to_state(report);
255 
256 	guard(rwsem_read)(&tsm_rwsem);
257 	if (!report->desc.inblob_len)
258 		return -EINVAL;
259 
260 	/*
261 	 * A given TSM backend always fills in ->outblob regardless of
262 	 * whether the report includes an auxblob/manifestblob or not.
263 	 */
264 	if (!report->outblob ||
265 	    state->read_generation != state->write_generation)
266 		return -EWOULDBLOCK;
267 
268 	return __read_report(report, buf, count, select);
269 }
270 
tsm_report_read(struct tsm_report * report,void * buf,size_t count,enum tsm_data_select select)271 static ssize_t tsm_report_read(struct tsm_report *report, void *buf,
272 			       size_t count, enum tsm_data_select select)
273 {
274 	struct tsm_report_state *state = to_state(report);
275 	const struct tsm_ops *ops;
276 	ssize_t rc;
277 
278 	/* try to read from the existing report if present and valid... */
279 	rc = read_cached_report(report, buf, count, select);
280 	if (rc >= 0 || rc != -EWOULDBLOCK)
281 		return rc;
282 
283 	/* slow path, report may need to be regenerated... */
284 	guard(rwsem_write)(&tsm_rwsem);
285 	ops = provider.ops;
286 	if (!ops)
287 		return -ENOTTY;
288 	if (!report->desc.inblob_len)
289 		return -EINVAL;
290 
291 	/* did another thread already generate this report? */
292 	if (report->outblob &&
293 	    state->read_generation == state->write_generation)
294 		goto out;
295 
296 	kvfree(report->outblob);
297 	kvfree(report->auxblob);
298 	kvfree(report->manifestblob);
299 	report->outblob = NULL;
300 	report->auxblob = NULL;
301 	report->manifestblob = NULL;
302 	rc = ops->report_new(report, provider.data);
303 	if (rc < 0)
304 		return rc;
305 	state->read_generation = state->write_generation;
306 out:
307 	return __read_report(report, buf, count, select);
308 }
309 
tsm_report_outblob_read(struct config_item * cfg,void * buf,size_t count)310 static ssize_t tsm_report_outblob_read(struct config_item *cfg, void *buf,
311 				       size_t count)
312 {
313 	struct tsm_report *report = to_tsm_report(cfg);
314 
315 	return tsm_report_read(report, buf, count, TSM_REPORT);
316 }
317 CONFIGFS_BIN_ATTR_RO(tsm_report_, outblob, NULL, TSM_OUTBLOB_MAX);
318 
tsm_report_auxblob_read(struct config_item * cfg,void * buf,size_t count)319 static ssize_t tsm_report_auxblob_read(struct config_item *cfg, void *buf,
320 				       size_t count)
321 {
322 	struct tsm_report *report = to_tsm_report(cfg);
323 
324 	return tsm_report_read(report, buf, count, TSM_CERTS);
325 }
326 CONFIGFS_BIN_ATTR_RO(tsm_report_, auxblob, NULL, TSM_OUTBLOB_MAX);
327 
tsm_report_manifestblob_read(struct config_item * cfg,void * buf,size_t count)328 static ssize_t tsm_report_manifestblob_read(struct config_item *cfg, void *buf,
329 					    size_t count)
330 {
331 	struct tsm_report *report = to_tsm_report(cfg);
332 
333 	return tsm_report_read(report, buf, count, TSM_MANIFEST);
334 }
335 CONFIGFS_BIN_ATTR_RO(tsm_report_, manifestblob, NULL, TSM_OUTBLOB_MAX);
336 
337 static struct configfs_attribute *tsm_report_attrs[] = {
338 	[TSM_REPORT_GENERATION] = &tsm_report_attr_generation,
339 	[TSM_REPORT_PROVIDER] = &tsm_report_attr_provider,
340 	[TSM_REPORT_PRIVLEVEL] = &tsm_report_attr_privlevel,
341 	[TSM_REPORT_PRIVLEVEL_FLOOR] = &tsm_report_attr_privlevel_floor,
342 	[TSM_REPORT_SERVICE_PROVIDER] = &tsm_report_attr_service_provider,
343 	[TSM_REPORT_SERVICE_GUID] = &tsm_report_attr_service_guid,
344 	[TSM_REPORT_SERVICE_MANIFEST_VER] = &tsm_report_attr_service_manifest_version,
345 	NULL,
346 };
347 
348 static struct configfs_bin_attribute *tsm_report_bin_attrs[] = {
349 	[TSM_REPORT_INBLOB] = &tsm_report_attr_inblob,
350 	[TSM_REPORT_OUTBLOB] = &tsm_report_attr_outblob,
351 	[TSM_REPORT_AUXBLOB] = &tsm_report_attr_auxblob,
352 	[TSM_REPORT_MANIFESTBLOB] = &tsm_report_attr_manifestblob,
353 	NULL,
354 };
355 
tsm_report_item_release(struct config_item * cfg)356 static void tsm_report_item_release(struct config_item *cfg)
357 {
358 	struct tsm_report *report = to_tsm_report(cfg);
359 	struct tsm_report_state *state = to_state(report);
360 
361 	kvfree(report->manifestblob);
362 	kvfree(report->auxblob);
363 	kvfree(report->outblob);
364 	kfree(report->desc.service_provider);
365 	kfree(state);
366 }
367 
368 static struct configfs_item_operations tsm_report_item_ops = {
369 	.release = tsm_report_item_release,
370 };
371 
tsm_report_is_visible(struct config_item * item,struct configfs_attribute * attr,int n)372 static bool tsm_report_is_visible(struct config_item *item,
373 				  struct configfs_attribute *attr, int n)
374 {
375 	guard(rwsem_read)(&tsm_rwsem);
376 	if (!provider.ops)
377 		return false;
378 
379 	if (!provider.ops->report_attr_visible)
380 		return true;
381 
382 	return provider.ops->report_attr_visible(n);
383 }
384 
tsm_report_is_bin_visible(struct config_item * item,struct configfs_bin_attribute * attr,int n)385 static bool tsm_report_is_bin_visible(struct config_item *item,
386 				      struct configfs_bin_attribute *attr, int n)
387 {
388 	guard(rwsem_read)(&tsm_rwsem);
389 	if (!provider.ops)
390 		return false;
391 
392 	if (!provider.ops->report_bin_attr_visible)
393 		return true;
394 
395 	return provider.ops->report_bin_attr_visible(n);
396 }
397 
398 static struct configfs_group_operations tsm_report_attr_group_ops = {
399 	.is_visible = tsm_report_is_visible,
400 	.is_bin_visible = tsm_report_is_bin_visible,
401 };
402 
403 static const struct config_item_type tsm_report_type = {
404 	.ct_owner = THIS_MODULE,
405 	.ct_bin_attrs = tsm_report_bin_attrs,
406 	.ct_attrs = tsm_report_attrs,
407 	.ct_item_ops = &tsm_report_item_ops,
408 	.ct_group_ops = &tsm_report_attr_group_ops,
409 };
410 
tsm_report_make_item(struct config_group * group,const char * name)411 static struct config_item *tsm_report_make_item(struct config_group *group,
412 						const char *name)
413 {
414 	struct tsm_report_state *state;
415 
416 	guard(rwsem_read)(&tsm_rwsem);
417 	if (!provider.ops)
418 		return ERR_PTR(-ENXIO);
419 
420 	state = kzalloc(sizeof(*state), GFP_KERNEL);
421 	if (!state)
422 		return ERR_PTR(-ENOMEM);
423 
424 	config_item_init_type_name(&state->cfg, name, &tsm_report_type);
425 	return &state->cfg;
426 }
427 
428 static struct configfs_group_operations tsm_report_group_ops = {
429 	.make_item = tsm_report_make_item,
430 };
431 
432 static const struct config_item_type tsm_reports_type = {
433 	.ct_owner = THIS_MODULE,
434 	.ct_group_ops = &tsm_report_group_ops,
435 };
436 
437 static const struct config_item_type tsm_root_group_type = {
438 	.ct_owner = THIS_MODULE,
439 };
440 
441 static struct configfs_subsystem tsm_configfs = {
442 	.su_group = {
443 		.cg_item = {
444 			.ci_namebuf = "tsm",
445 			.ci_type = &tsm_root_group_type,
446 		},
447 	},
448 	.su_mutex = __MUTEX_INITIALIZER(tsm_configfs.su_mutex),
449 };
450 
tsm_register(const struct tsm_ops * ops,void * priv)451 int tsm_register(const struct tsm_ops *ops, void *priv)
452 {
453 	const struct tsm_ops *conflict;
454 
455 	guard(rwsem_write)(&tsm_rwsem);
456 	conflict = provider.ops;
457 	if (conflict) {
458 		pr_err("\"%s\" ops already registered\n", conflict->name);
459 		return -EBUSY;
460 	}
461 
462 	provider.ops = ops;
463 	provider.data = priv;
464 	return 0;
465 }
466 EXPORT_SYMBOL_GPL(tsm_register);
467 
tsm_unregister(const struct tsm_ops * ops)468 int tsm_unregister(const struct tsm_ops *ops)
469 {
470 	guard(rwsem_write)(&tsm_rwsem);
471 	if (ops != provider.ops)
472 		return -EBUSY;
473 	provider.ops = NULL;
474 	provider.data = NULL;
475 	return 0;
476 }
477 EXPORT_SYMBOL_GPL(tsm_unregister);
478 
479 static struct config_group *tsm_report_group;
480 
tsm_init(void)481 static int __init tsm_init(void)
482 {
483 	struct config_group *root = &tsm_configfs.su_group;
484 	struct config_group *tsm;
485 	int rc;
486 
487 	config_group_init(root);
488 	rc = configfs_register_subsystem(&tsm_configfs);
489 	if (rc)
490 		return rc;
491 
492 	tsm = configfs_register_default_group(root, "report",
493 					      &tsm_reports_type);
494 	if (IS_ERR(tsm)) {
495 		configfs_unregister_subsystem(&tsm_configfs);
496 		return PTR_ERR(tsm);
497 	}
498 	tsm_report_group = tsm;
499 
500 	return 0;
501 }
502 module_init(tsm_init);
503 
tsm_exit(void)504 static void __exit tsm_exit(void)
505 {
506 	configfs_unregister_default_group(tsm_report_group);
507 	configfs_unregister_subsystem(&tsm_configfs);
508 }
509 module_exit(tsm_exit);
510 
511 MODULE_LICENSE("GPL");
512 MODULE_DESCRIPTION("Provide Trusted Security Module attestation reports via configfs");
513