blob: df87b5226adb04a9e71a627967727af26097a7c2 [file] [log] [blame]
/* 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);
}