blob: 3cfe6a2cd6908c1d0f8a856113ff23837f3711e5 [file] [log] [blame]
/* SPDX-License-Identifier: BSD-2-Clause */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <inttypes.h>
#include <limits.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cmocka.h>
#include <unistd.h>
#include <signal.h>
#if defined (__FreeBSD__)
#include <sys/procctl.h>
#else
#include <sys/prctl.h>
#endif
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include "tss2_tcti.h"
#include "tss2_tcti_cmd.h"
#include "tcti-cmd-test.h"
#include "tss2-tcti/tcti-common.h"
#include "tss2-tcti/tcti-cmd.h"
#define LOGMODULE tests
#include "util/log.h"
#define EXECLP_CMD "test/helper/tpm_cmd_tcti_dummy"
extern TSS2_TCTI_INFO *Tss2_Tcti_Info (void);
static inline
TSS2_TCTI_CONTEXT *state_cast (void **state)
{
return (TSS2_TCTI_CONTEXT *)*state;
}
int tcti_cmd_pipe (int pipefd[2])
{
int rc = mock_type (int);
if (!rc) {
return pipe (pipefd);
}
errno = rc;
return -1;
}
int tcti_cmd_fork (void)
{
int rc = mock_type (int);
if (!rc) {
return fork ();
}
errno = rc;
return -1;
}
FILE *tcti_cmd_fdopen (int fd, const char *mode)
{
int rc = mock_type (int);
if (!rc) {
return fdopen (fd, mode);
}
errno = rc;
return NULL;
}
int tcti_cmd_sigprocmask (int how, const sigset_t *set, sigset_t *oldset)
{
int rc = mock_type (int);
if (!rc) {
return sigprocmask (how, set, oldset);
}
errno = rc;
return -1;
}
int tcti_cmd_ferror (FILE *stream)
{
int rc = mock_type (int);
if (!rc) {
return ferror (stream);
}
errno = rc;
return -1;
}
size_t tcti_cmd_fwrite (const void *ptr, size_t size, size_t nmemb,
FILE *stream)
{
int rc = mock_type (int);
if (!rc) {
return fwrite (ptr, size, nmemb, stream);
}
will_return (tcti_cmd_ferror, rc);
errno = rc;
return 0;
}
TSS2_TCTI_CONTEXT *
test_common_setup (const char *cmd)
{
will_return_always (tcti_cmd_sigprocmask, 0);
will_return_always (tcti_cmd_fdopen, 0);
will_return_always (tcti_cmd_fork, 0);
will_return_always (tcti_cmd_pipe, 0);
size_t tcti_size = 0;
TSS2_RC rval = Tss2_Tcti_Cmd_Init (NULL, &tcti_size, cmd);
assert_int_equal (rval, TSS2_RC_SUCCESS);
TSS2_TCTI_CONTEXT *tcti_context = calloc (1, tcti_size);
assert_non_null (tcti_context);
rval = Tss2_Tcti_Cmd_Init (tcti_context, &tcti_size, cmd);
assert_int_equal (rval, TSS2_RC_SUCCESS);
return tcti_context;
}
static int
test_teardown (void **state)
{
will_return_always (tcti_cmd_sigprocmask, 0);
TSS2_TCTI_CONTEXT *tcti_context = state_cast (state);
if (tcti_context) {
Tss2_Tcti_Finalize (tcti_context);
free (tcti_context);
}
return 0;
}
/*
* Unit Test Code Starts Here
*/
/* When passed all NULL values ensure that we get back the expected RC. */
static void
tcti_cmd_init_all_null_test (void **state)
{
TSS2_RC rval = Tss2_Tcti_Cmd_Init (NULL, NULL, NULL);
assert_int_equal (rval, TSS2_TCTI_RC_BAD_VALUE);
}
/*
* Determine the size of a TCTI context structure. Requires calling the
* initialization function for the cmd TCTI with the first parameter
* (the TCTI context) NULL.
*/
static void
tcti_cmd_init_size_test (void **state)
{
size_t tcti_size = 0;
TSS2_RC rval = Tss2_Tcti_Cmd_Init (NULL, &tcti_size, __func__);
assert_int_equal (rval, TSS2_RC_SUCCESS);
assert_int_equal (tcti_size, sizeof (TSS2_TCTI_CMD_CONTEXT));
}
static void
tcti_cmd_test_pipe_1_fail (void **state)
{
uint8_t buf[4096];
size_t tcti_size = sizeof (buf);
TSS2_TCTI_CONTEXT *tcti_context = (TSS2_TCTI_CONTEXT *)buf;
will_return (tcti_cmd_pipe, EFAULT);
TSS2_RC rval = Tss2_Tcti_Cmd_Init (tcti_context, &tcti_size, __func__);
assert_int_equal (rval, TSS2_TCTI_RC_GENERAL_FAILURE);
}
static void
tcti_cmd_test_pipe_2_fail (void **state)
{
uint8_t buf[4096];
size_t tcti_size = sizeof (buf);
TSS2_TCTI_CONTEXT *tcti_context = (TSS2_TCTI_CONTEXT *)buf;
/* first pipe works, second pipe fails */
will_return (tcti_cmd_pipe, 0);
will_return (tcti_cmd_pipe, EFAULT);
TSS2_RC rval = Tss2_Tcti_Cmd_Init (tcti_context, &tcti_size, __func__);
assert_int_equal (rval, TSS2_TCTI_RC_GENERAL_FAILURE);
}
static void
tcti_cmd_test_fork_fail (void **state)
{
uint8_t buf[4096];
size_t tcti_size = sizeof (buf);
TSS2_TCTI_CONTEXT *tcti_context = (TSS2_TCTI_CONTEXT *)buf;
will_return_always (tcti_cmd_pipe, 0);
will_return_always (tcti_cmd_sigprocmask, 0);
will_return (tcti_cmd_fork, ENOMEM);
TSS2_RC rval = Tss2_Tcti_Cmd_Init (tcti_context, &tcti_size, __func__);
assert_int_equal (rval, TSS2_TCTI_RC_GENERAL_FAILURE);
}
static void
tcti_cmd_test_fdopen_1_fail (void **state)
{
uint8_t buf[4096];
size_t tcti_size = sizeof (buf);
TSS2_TCTI_CONTEXT *tcti_context = (TSS2_TCTI_CONTEXT *)buf;
will_return_always (tcti_cmd_pipe, 0);
will_return_always (tcti_cmd_fork, 0);
will_return_always (tcti_cmd_sigprocmask, 0);
will_return (tcti_cmd_fdopen, EINVAL);
TSS2_RC rval = Tss2_Tcti_Cmd_Init (tcti_context, &tcti_size, __func__);
assert_int_equal (rval, TSS2_TCTI_RC_GENERAL_FAILURE);
}
static void
tcti_cmd_test_fdopen_2_fail (void **state)
{
uint8_t buf[4096];
size_t tcti_size = sizeof (buf);
TSS2_TCTI_CONTEXT *tcti_context = (TSS2_TCTI_CONTEXT *)buf;
will_return_always (tcti_cmd_pipe, 0);
will_return_always (tcti_cmd_fork, 0);
will_return_always (tcti_cmd_sigprocmask, 0);
/* first fdopen works, second fails */
will_return (tcti_cmd_fdopen, 0);
will_return (tcti_cmd_fdopen, EINVAL);
TSS2_RC rval = Tss2_Tcti_Cmd_Init (tcti_context, &tcti_size, __func__);
assert_int_equal (rval, TSS2_TCTI_RC_GENERAL_FAILURE);
}
static void
tcti_cmd_test_sigprocmask_1_fail (void **state)
{
uint8_t buf[4096];
size_t tcti_size = sizeof (buf);
TSS2_TCTI_CONTEXT *tcti_context = (TSS2_TCTI_CONTEXT *)buf;
will_return_always (tcti_cmd_pipe, 0);
will_return (tcti_cmd_sigprocmask, EINVAL);
TSS2_RC rval = Tss2_Tcti_Cmd_Init (tcti_context, &tcti_size, __func__);
assert_int_equal (rval, TSS2_TCTI_RC_GENERAL_FAILURE);
}
static void
tcti_cmd_test_good (void **state)
{
will_return_always (tcti_cmd_fwrite, 0);
will_return_always (tcti_cmd_ferror, 0);
TSS2_TCTI_CONTEXT *tcti_context = *state =
test_common_setup (EXECLP_CMD" good");
assert_non_null (tcti_context);
/* send the command buffer */
TSS2_RC rval = Tss2_Tcti_Transmit (tcti_context,
sizeof (getcap_command), getcap_command);
assert_int_equal (rval, TSS2_RC_SUCCESS);
uint8_t rbuf[sizeof (getcap_good_resp)];
size_t rsize = sizeof (rbuf);
/* get the valid response */
rval = Tss2_Tcti_Receive (tcti_context, &rsize, rbuf,
TSS2_TCTI_TIMEOUT_BLOCK);
assert_int_equal (rval, TSS2_RC_SUCCESS);
/* Should be the expected getcap good response */
assert_int_equal (rsize, sizeof (getcap_good_resp));
assert_memory_equal (rbuf, getcap_good_resp, rsize);
}
static void
tcti_cmd_test_malformed_size_smaller (void **state)
{
will_return_always (tcti_cmd_fwrite, 0);
will_return_always (tcti_cmd_ferror, 0);
TSS2_TCTI_CONTEXT *tcti_context = *state =
test_common_setup (EXECLP_CMD" smaller");
assert_non_null (tcti_context);
/* send the command buffer */
TSS2_RC rval = Tss2_Tcti_Transmit (tcti_context,
sizeof (getcap_command), getcap_command);
assert_int_equal (rval, TSS2_RC_SUCCESS);
uint8_t rbuf[sizeof (getcap_good_resp)];
size_t rsize = sizeof (rbuf);
/* Attempt to receive a malformed response */
rval = Tss2_Tcti_Receive (tcti_context, &rsize, rbuf,
TSS2_TCTI_TIMEOUT_BLOCK);
assert_int_equal (rval, TSS2_TCTI_RC_MALFORMED_RESPONSE);
}
static void
tcti_cmd_test_malformed_size_bigger (void **state)
{
will_return_always (tcti_cmd_fwrite, 0);
will_return_always (tcti_cmd_ferror, 0);
TSS2_TCTI_CONTEXT *tcti_context = *state =
test_common_setup (EXECLP_CMD" bigger");
assert_non_null (tcti_context);
/* send the command buffer */
TSS2_RC rval = Tss2_Tcti_Transmit (tcti_context,
sizeof (getcap_command), getcap_command);
assert_int_equal (rval, TSS2_RC_SUCCESS);
uint8_t rbuf[sizeof (getcap_good_resp)];
size_t rsize = sizeof (rbuf);
/*
* Attempt to receive a malformed response with command header size
* larger than buffer size.
*/
rval = Tss2_Tcti_Receive (tcti_context, &rsize, rbuf,
TSS2_TCTI_TIMEOUT_BLOCK);
assert_int_equal (rval, TSS2_TCTI_RC_MALFORMED_RESPONSE);
}
static void
tcti_cmd_test_transmit_fail (void **state)
{
will_return_always (tcti_cmd_fwrite, EBADF);
TSS2_TCTI_CONTEXT *tcti_context = *state =
test_common_setup (EXECLP_CMD" good");
assert_non_null (tcti_context);
/* send the command buffer */
TSS2_RC rval = Tss2_Tcti_Transmit (tcti_context,
sizeof (getcap_command), getcap_command);
assert_int_equal (rval, TSS2_TCTI_RC_IO_ERROR);
uint8_t rbuf[sizeof (getcap_good_resp)];
size_t rsize = sizeof (rbuf);
/*
* Attempt to receive a response in the wrong state
*/
rval = Tss2_Tcti_Receive (tcti_context, &rsize, rbuf,
TSS2_TCTI_TIMEOUT_BLOCK);
assert_int_equal (rval, TSS2_TCTI_RC_BAD_SEQUENCE);
}
static void
tcti_cmd_test_set_locality (void **state)
{
TSS2_TCTI_CONTEXT *tcti_context = *state =
test_common_setup (EXECLP_CMD" good");
assert_non_null (tcti_context);
/* send the command buffer */
TSS2_RC rval = Tss2_Tcti_SetLocality (tcti_context, 42);
assert_int_equal (rval, TSS2_TCTI_RC_NOT_IMPLEMENTED);
}
static void
tcti_cmd_test_cancel (void **state)
{
TSS2_TCTI_CONTEXT *tcti_context = *state =
test_common_setup (EXECLP_CMD" good");
assert_non_null (tcti_context);
/* send the command buffer */
TSS2_RC rval = Tss2_Tcti_Cancel (tcti_context);
assert_int_equal (rval, TSS2_TCTI_RC_NOT_IMPLEMENTED);
}
static void
tcti_cmd_test_get_poll_handles_ok (void **state)
{
TSS2_TCTI_CONTEXT *tcti_context = *state =
test_common_setup (EXECLP_CMD" good");
assert_non_null (tcti_context);
size_t num_of_handles = 1;
TSS2_TCTI_POLL_HANDLE poll_handle;
/* send the command buffer */
TSS2_RC rval = Tss2_Tcti_GetPollHandles (tcti_context, &poll_handle, &num_of_handles);
assert_int_equal (rval, TSS2_RC_SUCCESS);
assert_int_equal(num_of_handles, 1);
}
static void
tcti_cmd_test_get_info (void **state)
{
TSS2_TCTI_CONTEXT *tcti_context = *state =
test_common_setup (EXECLP_CMD" good");
assert_non_null (tcti_context);
const TSS2_TCTI_INFO *info = Tss2_Tcti_Info ();
assert_non_null (info);
assert_int_equal (info->version, TCTI_VERSION);
assert_int_equal (info->init, Tss2_Tcti_Cmd_Init);
assert_string_equal (info->name, TCTI_CMD_NAME);
assert_string_equal (info->description, TCTI_CMD_DESCRIPTION);
assert_string_equal (info->config_help, TCTI_CMD_HELP);
}
int
main (int argc,
char *argv[])
{
const struct CMUnitTest tests[] = {
/*
* Tests that do not require the setup and teardown routine as they
* don't fork successfully
*/
cmocka_unit_test (tcti_cmd_init_all_null_test),
cmocka_unit_test (tcti_cmd_init_size_test),
cmocka_unit_test (tcti_cmd_test_pipe_1_fail),
cmocka_unit_test (tcti_cmd_test_pipe_2_fail),
cmocka_unit_test (tcti_cmd_test_fork_fail),
cmocka_unit_test (tcti_cmd_test_fdopen_1_fail),
cmocka_unit_test (tcti_cmd_test_fdopen_2_fail),
cmocka_unit_test (tcti_cmd_test_sigprocmask_1_fail),
/*
* Tests that **do** require a teardown routine as they
* **do** fork/exec successfully and thus get a TCTI_CONTEXT
*/
cmocka_unit_test_teardown (
tcti_cmd_test_good,
test_teardown),
cmocka_unit_test_teardown (
tcti_cmd_test_malformed_size_smaller,
test_teardown),
cmocka_unit_test_teardown (
tcti_cmd_test_malformed_size_bigger,
test_teardown),
cmocka_unit_test_teardown (
tcti_cmd_test_transmit_fail,
test_teardown),
cmocka_unit_test_teardown (
tcti_cmd_test_set_locality,
test_teardown),
cmocka_unit_test_teardown (
tcti_cmd_test_cancel,
test_teardown),
cmocka_unit_test_teardown (
tcti_cmd_test_get_poll_handles_ok,
test_teardown),
cmocka_unit_test_teardown (
tcti_cmd_test_get_info,
test_teardown),
};
return cmocka_run_group_tests (tests, NULL, NULL);
}