xref: /freebsd/usr.sbin/bhyve/tpm_emul_swtpm.c (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2024 Hans Rosenfeld
5  * Author: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
6  */
7 
8 #include <sys/types.h>
9 #include <sys/socket.h>
10 #include <sys/un.h>
11 
12 #include <err.h>
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <malloc_np.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <strings.h>
19 #include <unistd.h>
20 
21 #include "config.h"
22 #include "tpm_device.h"
23 #include "tpm_emul.h"
24 
25 struct tpm_swtpm {
26 	int fd;
27 };
28 
29 struct tpm_resp_hdr {
30 	uint16_t tag;
31 	uint32_t len;
32 	uint32_t errcode;
33 } __packed;
34 
35 static int
36 tpm_swtpm_init(void **sc, nvlist_t *nvl)
37 {
38 	struct tpm_swtpm *tpm;
39 	const char *path;
40 	struct sockaddr_un tpm_addr;
41 
42 	tpm = calloc(1, sizeof (struct tpm_swtpm));
43 	if (tpm == NULL) {
44 		warnx("%s: failed to allocate tpm_swtpm", __func__);
45 		return (ENOMEM);
46 	}
47 
48 	path = get_config_value_node(nvl, "path");
49 	if (path == NULL) {
50 		warnx("%s: no socket path specified", __func__);
51 		return (ENOENT);
52 	}
53 
54 	tpm->fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
55 	if (tpm->fd < 0) {
56 		warnx("%s: unable to open tpm socket", __func__);
57 		return (ENOENT);
58 	}
59 
60 	bzero(&tpm_addr, sizeof (tpm_addr));
61 	tpm_addr.sun_family = AF_UNIX;
62 	strlcpy(tpm_addr.sun_path, path, sizeof (tpm_addr.sun_path) - 1);
63 
64 	if (connect(tpm->fd, (struct sockaddr *)&tpm_addr, sizeof (tpm_addr)) ==
65 	    -1) {
66 		warnx("%s: unable to connect to tpm socket \"%s\"", __func__,
67 		    path);
68 		return (ENOENT);
69 	}
70 
71 	*sc = tpm;
72 
73 	return (0);
74 }
75 
76 static int
77 tpm_swtpm_execute_cmd(void *sc, void *cmd, uint32_t cmd_size, void *rsp,
78     uint32_t rsp_size)
79 {
80 	struct tpm_swtpm *tpm;
81 	ssize_t len;
82 
83 	if (rsp_size < (ssize_t)sizeof(struct tpm_resp_hdr)) {
84 		warn("%s: rsp_size of %u is too small", __func__, rsp_size);
85 		return (EINVAL);
86 	}
87 
88 	tpm = sc;
89 
90 	len = send(tpm->fd, cmd, cmd_size, MSG_NOSIGNAL|MSG_DONTWAIT);
91 	if (len == -1)
92 		err(1, "%s: cmd send failed, is swtpm running?", __func__);
93 	if (len != cmd_size) {
94 		warn("%s: cmd write failed (bytes written: %zd / %d)", __func__,
95 		    len, cmd_size);
96 		return (EFAULT);
97 	}
98 
99 	len = recv(tpm->fd, rsp, rsp_size, 0);
100 	if (len == -1)
101 		err(1, "%s: rsp recv failed, is swtpm running?", __func__);
102 	if (len < (ssize_t)sizeof(struct tpm_resp_hdr)) {
103 		warn("%s: rsp read failed (bytes read: %zd / %d)", __func__,
104 		    len, rsp_size);
105 		return (EFAULT);
106 	}
107 
108 	return (0);
109 }
110 
111 static void
112 tpm_swtpm_deinit(void *sc)
113 {
114 	struct tpm_swtpm *tpm;
115 
116 	tpm = sc;
117 	if (tpm == NULL)
118 		return;
119 
120 	if (tpm->fd >= 0)
121 		close(tpm->fd);
122 
123 	free(tpm);
124 }
125 
126 static const struct tpm_emul tpm_emul_swtpm = {
127 	.name = "swtpm",
128 	.init = tpm_swtpm_init,
129 	.deinit = tpm_swtpm_deinit,
130 	.execute_cmd = tpm_swtpm_execute_cmd,
131 };
132 TPM_EMUL_SET(tpm_emul_swtpm);
133