1 /*- 2 * Copyright (c) 2018 Stormshield. 3 * Copyright (c) 2018 Semihalf. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/random.h> 32 33 #include "tpm20.h" 34 35 #define TPM_HARVEST_SIZE 16 36 /* 37 * Perform a harvest every 10 seconds. 38 * Since discrete TPMs are painfully slow 39 * we don't want to execute this too often 40 * as the chip is likely to be used by others too. 41 */ 42 #define TPM_HARVEST_INTERVAL 10000000 43 44 MALLOC_DECLARE(M_TPM20); 45 MALLOC_DEFINE(M_TPM20, "tpm_buffer", "buffer for tpm 2.0 driver"); 46 47 static void tpm20_discard_buffer(void *arg); 48 #ifdef TPM_HARVEST 49 static void tpm20_harvest(void *arg); 50 #endif 51 static int tpm20_save_state(device_t dev, bool suspend); 52 53 static d_open_t tpm20_open; 54 static d_close_t tpm20_close; 55 static d_read_t tpm20_read; 56 static d_write_t tpm20_write; 57 static d_ioctl_t tpm20_ioctl; 58 59 static struct cdevsw tpm20_cdevsw = { 60 .d_version = D_VERSION, 61 .d_open = tpm20_open, 62 .d_close = tpm20_close, 63 .d_read = tpm20_read, 64 .d_write = tpm20_write, 65 .d_ioctl = tpm20_ioctl, 66 .d_name = "tpm20", 67 }; 68 69 int 70 tpm20_read(struct cdev *dev, struct uio *uio, int flags) 71 { 72 struct tpm_sc *sc; 73 size_t bytes_to_transfer; 74 int result = 0; 75 76 sc = (struct tpm_sc *)dev->si_drv1; 77 78 callout_stop(&sc->discard_buffer_callout); 79 sx_xlock(&sc->dev_lock); 80 81 bytes_to_transfer = MIN(sc->pending_data_length, uio->uio_resid); 82 if (bytes_to_transfer > 0) { 83 result = uiomove((caddr_t) sc->buf, bytes_to_transfer, uio); 84 memset(sc->buf, 0, TPM_BUFSIZE); 85 sc->pending_data_length = 0; 86 cv_signal(&sc->buf_cv); 87 } else { 88 result = ETIMEDOUT; 89 } 90 91 sx_xunlock(&sc->dev_lock); 92 93 return (result); 94 } 95 96 int 97 tpm20_write(struct cdev *dev, struct uio *uio, int flags) 98 { 99 struct tpm_sc *sc; 100 size_t byte_count; 101 int result = 0; 102 103 sc = (struct tpm_sc *)dev->si_drv1; 104 105 byte_count = uio->uio_resid; 106 if (byte_count < TPM_HEADER_SIZE) { 107 device_printf(sc->dev, 108 "Requested transfer is too small\n"); 109 return (EINVAL); 110 } 111 112 if (byte_count > TPM_BUFSIZE) { 113 device_printf(sc->dev, 114 "Requested transfer is too large\n"); 115 return (E2BIG); 116 } 117 118 sx_xlock(&sc->dev_lock); 119 120 while (sc->pending_data_length != 0) 121 cv_wait(&sc->buf_cv, &sc->dev_lock); 122 123 result = uiomove(sc->buf, byte_count, uio); 124 if (result != 0) { 125 sx_xunlock(&sc->dev_lock); 126 return (result); 127 } 128 129 result = sc->transmit(sc, byte_count); 130 131 if (result == 0) 132 callout_reset(&sc->discard_buffer_callout, 133 TPM_READ_TIMEOUT / tick, tpm20_discard_buffer, sc); 134 135 sx_xunlock(&sc->dev_lock); 136 return (result); 137 } 138 139 static void tpm20_discard_buffer(void *arg) 140 { 141 struct tpm_sc *sc; 142 143 sc = (struct tpm_sc *)arg; 144 if (callout_pending(&sc->discard_buffer_callout)) 145 return; 146 147 sx_xlock(&sc->dev_lock); 148 149 memset(sc->buf, 0, TPM_BUFSIZE); 150 sc->pending_data_length = 0; 151 152 cv_signal(&sc->buf_cv); 153 sx_xunlock(&sc->dev_lock); 154 155 device_printf(sc->dev, 156 "User failed to read buffer in time\n"); 157 } 158 159 int 160 tpm20_open(struct cdev *dev, int flag, int mode, struct thread *td) 161 { 162 163 return (0); 164 } 165 166 int 167 tpm20_close(struct cdev *dev, int flag, int mode, struct thread *td) 168 { 169 170 return (0); 171 } 172 173 174 int 175 tpm20_ioctl(struct cdev *dev, u_long cmd, caddr_t data, 176 int flags, struct thread *td) 177 { 178 179 return (ENOTTY); 180 } 181 182 int 183 tpm20_init(struct tpm_sc *sc) 184 { 185 struct make_dev_args args; 186 int result; 187 188 sc->buf = malloc(TPM_BUFSIZE, M_TPM20, M_WAITOK); 189 sx_init(&sc->dev_lock, "TPM driver lock"); 190 cv_init(&sc->buf_cv, "TPM buffer cv"); 191 callout_init(&sc->discard_buffer_callout, 1); 192 #ifdef TPM_HARVEST 193 sc->harvest_ticks = TPM_HARVEST_INTERVAL / tick; 194 callout_init(&sc->harvest_callout, 1); 195 callout_reset(&sc->harvest_callout, 0, tpm20_harvest, sc); 196 #endif 197 sc->pending_data_length = 0; 198 199 make_dev_args_init(&args); 200 args.mda_devsw = &tpm20_cdevsw; 201 args.mda_uid = UID_ROOT; 202 args.mda_gid = GID_WHEEL; 203 args.mda_mode = TPM_CDEV_PERM_FLAG; 204 args.mda_si_drv1 = sc; 205 result = make_dev_s(&args, &sc->sc_cdev, TPM_CDEV_NAME); 206 if (result != 0) 207 tpm20_release(sc); 208 209 return (result); 210 211 } 212 213 void 214 tpm20_release(struct tpm_sc *sc) 215 { 216 217 #ifdef TPM_HARVEST 218 callout_drain(&sc->harvest_callout); 219 #endif 220 221 if (sc->buf != NULL) 222 free(sc->buf, M_TPM20); 223 224 sx_destroy(&sc->dev_lock); 225 cv_destroy(&sc->buf_cv); 226 if (sc->sc_cdev != NULL) 227 destroy_dev(sc->sc_cdev); 228 } 229 230 231 int 232 tpm20_suspend(device_t dev) 233 { 234 return (tpm20_save_state(dev, true)); 235 } 236 237 int 238 tpm20_shutdown(device_t dev) 239 { 240 return (tpm20_save_state(dev, false)); 241 } 242 243 #ifdef TPM_HARVEST 244 245 /* 246 * Get TPM_HARVEST_SIZE random bytes and add them 247 * into system entropy pool. 248 */ 249 static void 250 tpm20_harvest(void *arg) 251 { 252 struct tpm_sc *sc; 253 unsigned char entropy[TPM_HARVEST_SIZE]; 254 uint16_t entropy_size; 255 int result; 256 uint8_t cmd[] = { 257 0x80, 0x01, /* TPM_ST_NO_SESSIONS tag*/ 258 0x00, 0x00, 0x00, 0x0c, /* cmd length */ 259 0x00, 0x00, 0x01, 0x7b, /* cmd TPM_CC_GetRandom */ 260 0x00, TPM_HARVEST_SIZE /* number of bytes requested */ 261 }; 262 263 264 sc = arg; 265 sx_xlock(&sc->dev_lock); 266 while (sc->pending_data_length != 0) 267 cv_wait(&sc->buf_cv, &sc->dev_lock); 268 269 memcpy(sc->buf, cmd, sizeof(cmd)); 270 result = sc->transmit(sc, sizeof(cmd)); 271 if (result != 0) { 272 sx_xunlock(&sc->dev_lock); 273 return; 274 } 275 276 /* Ignore response size */ 277 sc->pending_data_length = 0; 278 279 /* The number of random bytes we got is placed right after the header */ 280 entropy_size = (uint16_t) sc->buf[TPM_HEADER_SIZE + 1]; 281 if (entropy_size > 0) { 282 entropy_size = MIN(entropy_size, TPM_HARVEST_SIZE); 283 memcpy(entropy, 284 sc->buf + TPM_HEADER_SIZE + sizeof(uint16_t), 285 entropy_size); 286 } 287 288 sx_xunlock(&sc->dev_lock); 289 if (entropy_size > 0) 290 random_harvest_queue(entropy, entropy_size, RANDOM_PURE_TPM); 291 292 callout_reset(&sc->harvest_callout, sc->harvest_ticks, tpm20_harvest, sc); 293 } 294 #endif /* TPM_HARVEST */ 295 296 static int 297 tpm20_save_state(device_t dev, bool suspend) 298 { 299 struct tpm_sc *sc; 300 uint8_t save_cmd[] = { 301 0x80, 0x01, /* TPM_ST_NO_SESSIONS tag*/ 302 0x00, 0x00, 0x00, 0x0C, /* cmd length */ 303 0x00, 0x00, 0x01, 0x45, 0x00, 0x00 /* cmd TPM_CC_Shutdown */ 304 }; 305 306 sc = device_get_softc(dev); 307 308 /* 309 * Inform the TPM whether we are going to suspend or reboot/shutdown. 310 */ 311 if (suspend) 312 save_cmd[11] = 1; /* TPM_SU_STATE */ 313 314 if (sc == NULL || sc->buf == NULL) 315 return (0); 316 317 sx_xlock(&sc->dev_lock); 318 319 memcpy(sc->buf, save_cmd, sizeof(save_cmd)); 320 sc->transmit(sc, sizeof(save_cmd)); 321 322 sx_xunlock(&sc->dev_lock); 323 324 return (0); 325 } 326 327 int32_t 328 tpm20_get_timeout(uint32_t command) 329 { 330 int32_t timeout; 331 332 switch (command) { 333 case TPM_CC_CreatePrimary: 334 case TPM_CC_Create: 335 case TPM_CC_CreateLoaded: 336 timeout = TPM_TIMEOUT_LONG; 337 break; 338 case TPM_CC_SequenceComplete: 339 case TPM_CC_Startup: 340 case TPM_CC_SequenceUpdate: 341 case TPM_CC_GetCapability: 342 case TPM_CC_PCR_Extend: 343 case TPM_CC_EventSequenceComplete: 344 case TPM_CC_HashSequenceStart: 345 timeout = TPM_TIMEOUT_C; 346 break; 347 default: 348 timeout = TPM_TIMEOUT_B; 349 break; 350 } 351 return timeout; 352 } 353