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 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 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 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