]> Git Repo - linux.git/blob - drivers/virt/coco/tsm.c
Linux 6.14-rc3
[linux.git] / drivers / virt / coco / tsm.c
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
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_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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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");
This page took 0.057113 seconds and 4 git commands to generate.