| /* SPDX-License-Identifier: BSD-2-Clause */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include <inttypes.h> |
| #include <stdbool.h> |
| #include <stdlib.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| #include <unistd.h> |
| |
| #include "tss2_sys.h" |
| #include "tss2_mu.h" |
| |
| #include "tcti-common.h" |
| #include "tcti-cmd-test.h" |
| |
| #define LOGMODULE test |
| #include "util/log.h" |
| |
| /* |
| * A malformed header response. The header reports smaller than the actual |
| * payload. |
| */ |
| static uint8_t getcap_hdr_malformed_size_smaller[] = { |
| 0x80, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x01, 0x00, 0x32, |
| 0x2e, 0x30, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x01, 0x03, 0x00, |
| 0x00, 0x00, 0xa7, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x07, 0xe1, 0x00, |
| 0x00, 0x01, 0x05, 0x49, 0x42, 0x4d, 0x20, 0x00, 0x00, 0x01, 0x06, 0x53, |
| 0x57, 0x20, 0x20, 0x00, 0x00, 0x01, 0x07, 0x20, 0x54, 0x50, 0x4d, 0x00, |
| 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, |
| 0x00, 0x01, 0x0b, 0x20, 0x16, 0x05, 0x11, 0x00, 0x00, 0x01, 0x0c, 0x00, |
| 0x16, 0x28, 0x00, 0x00, 0x00, 0x01, 0x0d, 0x00, 0x00, 0x04, 0x00, 0x00, |
| 0x00, 0x01, 0x0e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x0f, 0x00, |
| 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, |
| 0x00, 0x01, 0x11, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x01, 0x12, 0x00, |
| 0x00, 0x00, 0x18, 0x00, 0x00, 0x01, 0x13, 0x00, 0x00, 0x00, 0x03, 0x00, |
| 0x00, 0x01, 0x14, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0x16, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x17, 0x00, 0x00, 0x08, 0x00, 0x00, |
| 0x00, 0x01, 0x18, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01, 0x19, 0x00, |
| 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x00, 0x00, 0x0c, 0x00, |
| 0x00, 0x01, 0x1b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01, 0x1c, 0x00, |
| 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x1d, 0x00, 0x00, 0x00, 0xff, 0x00, |
| 0x00, 0x01, 0x1e, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x1f, 0x00, |
| 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x30, 0x00, |
| 0x00, 0x01, 0x21, 0x00, 0x00, 0x0c, 0xe4, 0x00, 0x00, 0x01, 0x22, 0x00, |
| 0x00, 0x01, 0x44, 0x00, 0x00, 0x01, 0x23, 0x32, 0x2e, 0x30, 0x00, 0x00, |
| 0x00, 0x01, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x25, 0x00, |
| 0x00, 0x00, 0x92, 0x00, 0x00, 0x01, 0x26, 0x00, 0x00, 0x00, 0xa7, 0x00, |
| 0x00, 0x01, 0x27, 0x00, 0x00, 0x07, 0xe1, 0x00, 0x00, 0x01, 0x28, 0x00, |
| 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x29, 0x00, 0x00, 0x00, 0x71, 0x00, |
| 0x00, 0x01, 0x2a, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x01, 0x2b, 0x00, |
| 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x00, 0x04, 0x00, 0x00, |
| 0x00, 0x01, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2e, 0x00, |
| 0x00, 0x04, 0x00 |
| }; |
| /* |
| * A malformed header response. The header reports bigger than the actual |
| * payload. |
| */ |
| static uint8_t getcap_resp_malformed_size_bigger[] = { |
| 0x80, 0x01, 0x00, 0x00, 0x42, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x01, 0x00, 0x32, |
| 0x2e, 0x30, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x01, 0x03, 0x00, |
| 0x00, 0x00, 0xa7, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x07, 0xe1, 0x00, |
| 0x00, 0x01, 0x05, 0x49, 0x42, 0x4d, 0x20, 0x00, 0x00, 0x01, 0x06, 0x53, |
| 0x57, 0x20, 0x20, 0x00, 0x00, 0x01, 0x07, 0x20, 0x54, 0x50, 0x4d, 0x00, |
| 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, |
| 0x00, 0x01, 0x0b, 0x20, 0x16, 0x05, 0x11, 0x00, 0x00, 0x01, 0x0c, 0x00, |
| 0x16, 0x28, 0x00, 0x00, 0x00, 0x01, 0x0d, 0x00, 0x00, 0x04, 0x00, 0x00, |
| 0x00, 0x01, 0x0e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x0f, 0x00, |
| 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, |
| 0x00, 0x01, 0x11, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x01, 0x12, 0x00, |
| 0x00, 0x00, 0x18, 0x00, 0x00, 0x01, 0x13, 0x00, 0x00, 0x00, 0x03, 0x00, |
| 0x00, 0x01, 0x14, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0x16, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x17, 0x00, 0x00, 0x08, 0x00, 0x00, |
| 0x00, 0x01, 0x18, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01, 0x19, 0x00, |
| 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x00, 0x00, 0x0c, 0x00, |
| 0x00, 0x01, 0x1b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01, 0x1c, 0x00, |
| 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x1d, 0x00, 0x00, 0x00, 0xff, 0x00, |
| 0x00, 0x01, 0x1e, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x1f, 0x00, |
| 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x30, 0x00, |
| 0x00, 0x01, 0x21, 0x00, 0x00, 0x0c, 0xe4, 0x00, 0x00, 0x01, 0x22, 0x00, |
| 0x00, 0x01, 0x44, 0x00, 0x00, 0x01, 0x23, 0x32, 0x2e, 0x30, 0x00, 0x00, |
| 0x00, 0x01, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x25, 0x00, |
| 0x00, 0x00, 0x92, 0x00, 0x00, 0x01, 0x26, 0x00, 0x00, 0x00, 0xa7, 0x00, |
| 0x00, 0x01, 0x27, 0x00, 0x00, 0x07, 0xe1, 0x00, 0x00, 0x01, 0x28, 0x00, |
| 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x29, 0x00, 0x00, 0x00, 0x71, 0x00, |
| 0x00, 0x01, 0x2a, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x01, 0x2b, 0x00, |
| 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x00, 0x04, 0x00, 0x00, |
| 0x00, 0x01, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2e, 0x00, |
| 0x00, 0x04, 0x00 |
| }; |
| /* |
| * A malformed header response. The size is smaller than a header. |
| */ |
| static uint8_t getcap_resp_malformed_short[] = { |
| 0x80, 0x01, 0x00, 0x00, 0x42, 0x83, 0x00, 0x00 |
| }; |
| |
| #define child_exit(code) do { LOG_ERROR ("PID (%d): Child child_exiting", getpid ()); exit (code); } while (0) |
| |
| int main (int argc, char *argv[]) |
| { |
| /* No buffering on read/write from child stdio/stdin */ |
| setvbuf (stdin, NULL, _IONBF, 0); |
| setvbuf (stdout, NULL, _IONBF, 0); |
| |
| /* |
| * Figure out the response the test wants by mapping strings to hard-coded |
| * response buffers. We default to good if no argument is specified. |
| */ |
| uint8_t *response_buffer = getcap_good_resp; |
| size_t response_buffer_size = sizeof (getcap_good_resp); |
| char *response_selector = "good"; |
| if (argc == 2) { |
| response_selector = argv[1]; |
| } else if (argc > 2) { |
| LOG_ERROR ("Expected only 1 argument, got: %d", argc - 1); |
| child_exit (EXIT_SUCCESS); |
| } |
| |
| LOG_DEBUG ("CHILD (%d): Response selector is: %s", getpid (), |
| response_selector); |
| |
| if (!strcmp (response_selector, "good")) { |
| /* nothing to do already set */ |
| } else if (!strcmp (response_selector, "small")) { |
| response_buffer = getcap_hdr_malformed_size_smaller; |
| response_buffer_size = sizeof (getcap_hdr_malformed_size_smaller); |
| } else if (!strcmp (response_selector, "big")) { |
| response_buffer = getcap_resp_malformed_size_bigger; |
| response_buffer_size = sizeof (getcap_resp_malformed_size_bigger); |
| } else if (!strcmp (response_selector, "short")) { |
| response_buffer = getcap_resp_malformed_short; |
| response_buffer_size = sizeof (getcap_resp_malformed_short); |
| } else { |
| LOG_ERROR ("Unknown buffer response string: %s", argv[1]); |
| child_exit (EXIT_FAILURE); |
| } |
| |
| /* |
| * The child now: |
| * - waits for a command over stdin |
| * - checks the command against a known good value |
| * - writes the user requested response to stdout |
| */ |
| bool quit = false; |
| |
| while (!quit) { |
| |
| uint8_t buf[4096]; |
| |
| LOG_DEBUG ("PID (%d): Child waiting on TPM command", getpid ()); |
| |
| size_t read_size = fread (buf, 1, TPM_HEADER_SIZE, stdin); |
| if (read_size != TPM_HEADER_SIZE || ferror (stdin)) { |
| if (ferror (stdin) && errno == EINTR) { |
| quit = true; |
| LOG_ERROR ("PID (%d): Child quiting", getpid ()); |
| continue; |
| } |
| LOG_ERROR ("Could not get TPM Header from stdin: %s", |
| strerror (errno)); |
| child_exit (EXIT_FAILURE); |
| } |
| |
| LOGBLOB_DEBUG (buf, read_size, "PID (%d): Child got TPM command header", |
| getpid ()); |
| |
| tpm_header_t hdr = { 0 }; |
| TSS2_RC rc = header_unmarshal (buf, &hdr); |
| if (rc != TSS2_RC_SUCCESS) { |
| LOG_ERROR ("PID (%d): could not unmarshal header", getpid ()); |
| LOG_ERROR ("Could not unmarshal header"); |
| child_exit (EXIT_FAILURE); |
| } |
| |
| if (hdr.size < TPM_HEADER_SIZE) { |
| LOG_ERROR ( |
| "Header size field cannot be smaller than header, " "got: %" PRIu32, |
| hdr.size); |
| LOG_ERROR ("PID (%d): header size too small: %" PRIu32, getpid (), |
| hdr.size); |
| child_exit (EXIT_FAILURE); |
| } |
| |
| size_t data_size = hdr.size - TPM_HEADER_SIZE; |
| |
| LOG_DEBUG ("PID (%d): Child waiting on remaining tpm: %zu", getpid (), |
| data_size); |
| |
| read_size = fread (&buf[TPM_HEADER_SIZE], 1, data_size, stdin); |
| if (read_size != data_size || ferror (stdin)) { |
| LOG_ERROR ( |
| "PID (%d): Command payload %zu != %zu, full read failed: %s", |
| getpid (), read_size, data_size, strerror (errno)); |
| LOG_ERROR ("Command payload full read failed: %s", strerror (errno)); |
| child_exit (EXIT_FAILURE); |
| } |
| |
| LOGBLOB_DEBUG (buf, data_size, "PID (%d): Child got full TPM command", |
| getpid ()); |
| |
| /* |
| * We know this is the *only* command we will get, so it should be |
| * equal |
| */ |
| if (sizeof (getcap_command) != hdr.size) { |
| LOG_ERROR ( |
| "PID (%d): sizeof (getcap_command) != hdr.size, %zu != %"PRIu32, |
| getpid (), sizeof (getcap_command), hdr.size); |
| LOG_ERROR ("Unexpected command size, got %" PRIu32 ", expected %zu", |
| hdr.size, sizeof (getcap_command)); |
| child_exit (EXIT_FAILURE); |
| } |
| if (memcmp (getcap_command, buf, hdr.size)) { |
| LOG_ERROR ("PID (%d): memcmp failed", getpid ()); |
| LOG_ERROR ("Unexpected command buffer"); |
| child_exit (EXIT_FAILURE); |
| } |
| |
| LOGBLOB_DEBUG (response_buffer, response_buffer_size, |
| "PID (%d): Child writing to stdout", getpid ()); |
| |
| size_t bytes_wrote = fwrite (response_buffer, 1, response_buffer_size, |
| stdout); |
| |
| if (bytes_wrote != response_buffer_size || ferror (stdout)) { |
| if (ferror (stdout)) { |
| if (errno == EINTR) { |
| quit = true; |
| continue; |
| } |
| LOG_ERROR ("Could not write response buffer: %s", |
| strerror (errno)); |
| } else { |
| LOG_ERROR ("bytes_wrote (%zu) != response_buffer_size (%zu)", |
| bytes_wrote, response_buffer_size); |
| } |
| child_exit (EXIT_FAILURE); |
| } |
| |
| LOG_DEBUG ("PID (%d): Child wrote to stdout", getpid ()); |
| } |
| |
| child_exit (EXIT_SUCCESS); |
| } |