xref: /illumos-gate/usr/src/cmd/bhyve/common/tpm_emul_swtpm.c (revision 6e66f8aaeedfaa2a4e1a2f8999dee4586a229518)
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 #ifdef	__FreeBSD__
16 #include <malloc_np.h>
17 #else
18 #include <sys/vmm.h>
19 #endif
20 #include <stdlib.h>
21 #include <string.h>
22 #include <strings.h>
23 #include <unistd.h>
24 
25 #include "config.h"
26 #include "tpm_device.h"
27 #include "tpm_emul.h"
28 
29 struct tpm_swtpm {
30 	int fd;
31 };
32 
33 struct tpm_resp_hdr {
34 	uint16_t tag;
35 	uint32_t len;
36 	uint32_t errcode;
37 } __packed;
38 
39 static int
tpm_swtpm_init(void ** sc,nvlist_t * nvl)40 tpm_swtpm_init(void **sc, nvlist_t *nvl)
41 {
42 	struct tpm_swtpm *tpm;
43 	const char *path;
44 	struct sockaddr_un tpm_addr;
45 
46 	tpm = calloc(1, sizeof (struct tpm_swtpm));
47 	if (tpm == NULL) {
48 		warnx("%s: failed to allocate tpm_swtpm", __func__);
49 		return (ENOMEM);
50 	}
51 
52 	path = get_config_value_node(nvl, "path");
53 	if (path == NULL) {
54 		warnx("%s: no socket path specified", __func__);
55 		return (ENOENT);
56 	}
57 
58 	tpm->fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
59 	if (tpm->fd < 0) {
60 		warnx("%s: unable to open tpm socket", __func__);
61 		return (ENOENT);
62 	}
63 
64 	bzero(&tpm_addr, sizeof (tpm_addr));
65 	tpm_addr.sun_family = AF_UNIX;
66 	strlcpy(tpm_addr.sun_path, path, sizeof (tpm_addr.sun_path) - 1);
67 
68 	if (connect(tpm->fd, (struct sockaddr *)&tpm_addr, sizeof (tpm_addr)) ==
69 	    -1) {
70 		warnx("%s: unable to connect to tpm socket \"%s\"", __func__,
71 		    path);
72 		return (ENOENT);
73 	}
74 
75 	*sc = tpm;
76 
77 	return (0);
78 }
79 
80 static int
tpm_swtpm_execute_cmd(void * sc,void * cmd,uint32_t cmd_size,void * rsp,uint32_t rsp_size)81 tpm_swtpm_execute_cmd(void *sc, void *cmd, uint32_t cmd_size, void *rsp,
82     uint32_t rsp_size)
83 {
84 	struct tpm_swtpm *tpm;
85 	ssize_t len;
86 
87 	if (rsp_size < (ssize_t)sizeof(struct tpm_resp_hdr)) {
88 		warn("%s: rsp_size of %u is too small", __func__, rsp_size);
89 		return (EINVAL);
90 	}
91 
92 	tpm = sc;
93 
94 #ifdef	__FreeBSD__
95 	len = send(tpm->fd, cmd, cmd_size, MSG_NOSIGNAL|MSG_DONTWAIT);
96 	if (len == -1)
97 		err(1, "%s: cmd send failed, is swtpm running?", __func__);
98 	if (len != cmd_size) {
99 		warn("%s: cmd write failed (bytes written: %zd / %d)", __func__,
100 		    len, cmd_size);
101 		return (EFAULT);
102 	}
103 
104 	len = recv(tpm->fd, rsp, rsp_size, 0);
105 	if (len == -1)
106 		err(1, "%s: rsp recv failed, is swtpm running?", __func__);
107 	if (len < (ssize_t)sizeof(struct tpm_resp_hdr)) {
108 		warn("%s: rsp read failed (bytes read: %zd / %d)", __func__,
109 		    len, rsp_size);
110 		return (EFAULT);
111 	}
112 #else
113 	while (cmd_size > 0) {
114 		len = send(tpm->fd, cmd, cmd_size, MSG_NOSIGNAL|MSG_DONTWAIT);
115 		if (len == -1) {
116 			if (errno == EINTR)
117 				continue;
118 			err(1, "%s: cmd send failed, is swtpm running?",
119 			    __func__);
120 		}
121 		cmd += len;
122 		cmd_size -= len;
123 	}
124 
125 	size_t buflen = rsp_size;
126 	size_t rcvd = 0;
127 	while (buflen > 0 && rcvd < sizeof (struct tpm_resp_hdr)) {
128 		len = recv(tpm->fd, rsp, buflen, 0);
129 		if (len == -1) {
130 			if (errno == EINTR)
131 				continue;
132 			err(1, "%s: rsp recv failed, is swtpm running?",
133 			    __func__);
134 		}
135 		if (len == 0)
136 			break;
137 		rsp += len;
138 		buflen -= len;
139 		rcvd += len;
140 	}
141 #endif
142 
143 	return (0);
144 }
145 
146 static void
tpm_swtpm_deinit(void * sc)147 tpm_swtpm_deinit(void *sc)
148 {
149 	struct tpm_swtpm *tpm;
150 
151 	tpm = sc;
152 	if (tpm == NULL)
153 		return;
154 
155 	if (tpm->fd >= 0)
156 		close(tpm->fd);
157 
158 	free(tpm);
159 }
160 
161 static const struct tpm_emul tpm_emul_swtpm = {
162 	.name = "swtpm",
163 	.init = tpm_swtpm_init,
164 	.deinit = tpm_swtpm_deinit,
165 	.execute_cmd = tpm_swtpm_execute_cmd,
166 };
167 TPM_EMUL_SET(tpm_emul_swtpm);
168