swtpm: Add support for --tpmstate dir=<dir> command line parameter

Add support for the --tpmstate dir=<dir> command line parameter.
It will be used instead of the TPM_PATH, unless it is not set.

Adapt two test cases for the new parameter.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
This commit is contained in:
Stefan Berger 2015-10-27 21:53:25 -04:00
parent efb0779cd6
commit bc525ccdab
15 changed files with 274 additions and 59 deletions

View File

@ -133,7 +133,7 @@
.\" ========================================================================
.\"
.IX Title "swtpm 8"
.TH swtpm 8 "2015-10-26" "swtpm" ""
.TH swtpm 8 "2015-10-27" "swtpm" ""
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
@ -153,9 +153,9 @@ Unless corresponding command line parameters are used, the
be set to the \s-1TCP/IP\s0 port the process is supposed to listen on for \s-1TPM\s0
request messages.
.PP
The environment variable \fI\s-1TPM_PATH\s0\fR must be set and
Similarly, the environment variable \fI\s-1TPM_PATH\s0\fR can be set and
contain the name of a directory where the \s-1TPM\s0 can store its persistent
data into.
state into.
.PP
The \fBswtpm\fR process can be terminated by sending a
\&\fI\s-1SIGTERM\s0\fR signal to it.
@ -164,8 +164,8 @@ The following options are supported if the \fIsocket\fR interface is chosen:
.IP "\fB\-p|\-\-port <port\fR>" 4
.IX Item "-p|--port <port>"
Use the given port rather than using the environment variable \s-1TPM_PORT.\s0
.IP "\fB\-i|\-\-dir <dir\fR>" 4
.IX Item "-i|--dir <dir>"
.IP "\fB\-\-tpmstate dir=<dir>\fR" 4
.IX Item "--tpmstate dir=<dir>"
Use the given path rather than using the environment variable \s-1TPM_PATH.\s0
.IP "\fB\-f|\-\-fd <fd\fR>" 4
.IX Item "-f|--fd <fd>"

View File

@ -16,9 +16,9 @@ B<swtpm> program requires that the environment variable I<TPM_PORT>
be set to the TCP/IP port the process is supposed to listen on for TPM
request messages.
The environment variable I<TPM_PATH> must be set and
Similarly, the environment variable I<TPM_PATH> can be set and
contain the name of a directory where the TPM can store its persistent
data into.
state into.
The B<swtpm> process can be terminated by sending a
I<SIGTERM> signal to it.
@ -31,7 +31,7 @@ The following options are supported if the I<socket> interface is chosen:
Use the given port rather than using the environment variable TPM_PORT.
=item B<-i|--dir <dir>>
=item B<--tpmstate dir=E<lt>dirE<gt>>
Use the given path rather than using the environment variable TPM_PATH.

View File

@ -133,7 +133,7 @@
.\" ========================================================================
.\"
.IX Title "swtpm_cuse 8"
.TH swtpm_cuse 8 "2015-10-26" "swtpm" ""
.TH swtpm_cuse 8 "2015-10-27" "swtpm" ""
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
@ -146,13 +146,9 @@ swtpm
.SH "DESCRIPTION"
.IX Header "DESCRIPTION"
\&\fBswtpm_cuse\fR implements a \s-1TPM\s0 software emulator built on libtpms.
It provides access to \s-1TPM\s0 functionality over a Linux \s-1CUSE
It provides access to \s-1TPM\s0 functionality over a Linux \s-1CUSE
\&\s0(character device in user space) interface.
.PP
The environment variable \fI\s-1TPM_PATH\s0\fR must be set and
contain the name of a directory where the \s-1TPM\s0 can store its persistent
data into.
.PP
The \fBswtpm_ioctl\fR command should be used for a graceful shutdown
of the \s-1CUSE TPM.\s0
.PP
@ -160,6 +156,11 @@ The following options are supported:
.IP "\fB\-h | \-\-help\fR" 4
.IX Item "-h | --help"
Display help screen.
.IP "\fB\-\-tpmstate dir=<dir>\fR" 4
.IX Item "--tpmstate dir=<dir>"
This parameter allows to set the directory where the \s-1TPM\s0 will
store its persistent state to. If this parameter is not set,
the environment variable \fI\s-1TPM_PATH\s0\fR can be set instead.
.IP "\fB\-n <device name> | \-\-name=<device name> (mandatory)\fR" 4
.IX Item "-n <device name> | --name=<device name> (mandatory)"
The name of the character device to create. To create /dev/vtpm\-200, the

View File

@ -9,13 +9,9 @@ B<swtpm_cuse [OPTIONS]>
=head1 DESCRIPTION
B<swtpm_cuse> implements a TPM software emulator built on libtpms.
It provides access to TPM functionality over a Linux CUSE
It provides access to TPM functionality over a Linux CUSE
(character device in user space) interface.
The environment variable I<TPM_PATH> must be set and
contain the name of a directory where the TPM can store its persistent
data into.
The B<swtpm_ioctl> command should be used for a graceful shutdown
of the CUSE TPM.
@ -27,6 +23,12 @@ The following options are supported:
Display help screen.
=item B<--tpmstate dir=E<lt>dirE<gt>>
This parameter allows to set the directory where the TPM will
store its persistent state to. If this parameter is not set,
the environment variable I<TPM_PATH> can be set instead.
=item B<-n E<lt>device nameE<gt> | --name=E<lt>device nameE<gt> (mandatory)>
The name of the character device to create. To create /dev/vtpm-200, the

View File

@ -14,7 +14,8 @@ noinst_HEADERS = \
swtpm_aes.h \
swtpm_debug.h \
swtpm_io.h \
swtpm_nvfile.h
swtpm_nvfile.h \
tpmstate.h
lib_LTLIBRARIES = libswtpm_libtpms.la
@ -27,7 +28,8 @@ libswtpm_libtpms_la_SOURCES = \
swtpm_aes.c \
swtpm_debug.c \
swtpm_io.c \
swtpm_nvfile.c
swtpm_nvfile.c \
tpmstate.c
libswtpm_libtpms_la_CFLAGS = \
$(HARDENING_CFLAGS)

View File

@ -53,6 +53,7 @@
#include "logging.h"
#include "swtpm_nvfile.h"
#include "pidfile.h"
#include "tpmstate.h"
/* --log %s */
static const OptionDesc logging_opt_desc[] = {
@ -96,6 +97,15 @@ static const OptionDesc pid_opt_desc[] = {
END_OPTION_DESC
};
/* --state %s */
static const OptionDesc tpmstate_opt_desc[] = {
{
.name = "dir",
.type = OPT_TYPE_STRING,
},
END_OPTION_DESC
};
/*
* handle_log_options:
* Parse and act upon the parsed log options. Initialize the logging.
@ -324,8 +334,8 @@ error:
/*
* handle_pidfile_options:
* Parse and act upon the parse pidfile options. Set global value
* related to the options found.
* Parse and act upon the parse pidfile options.
*
* @options: the pidfile options to parse
*
* Returns 0 on success, -1 on failure.
@ -341,9 +351,83 @@ handle_pid_options(char *options)
if (parse_pid_options(options, &pidfile) < 0)
return -1;
pidfile_set(pidfile);
if (pidfile_set(pidfile) < 0)
return -1;
free(pidfile);
return 0;
}
/*
* parse_tpmstate_options:
* Parse and act upon the parsed 'tpmstate' options.
*
* @options: the 'pid' options to parse
* @tpmstatedir: Point to pointer for tpmstatedir
*
* Returns 0 on success, -1 on failure.
*/
static int
parse_tpmstate_options(char *options, char **tpmstatedir)
{
OptionValues *ovs = NULL;
char *error = NULL;
const char *directory = NULL;
ovs = options_parse(options, tpmstate_opt_desc, &error);
if (!ovs) {
fprintf(stderr, "Error parsing pid options: %s\n",
error);
goto error;
}
directory = option_get_string(ovs, "dir", NULL);
if (!directory) {
fprintf(stderr, "The file parameter is required for the tpmstate option.\n");
goto error;
}
*tpmstatedir = strdup(directory);
if (!*tpmstatedir) {
fprintf(stderr, "Out of memory.");
goto error;
}
option_values_free(ovs);
return 0;
error:
option_values_free(ovs);
return -1;
}
/*
* handle_tpmstate_options:
* Parse and act upon the parsed 'tpmstate' options.
*
* @options: the tpmstate options to parse
*
* Returns 0 on success, -1 on failure.
*/
int
handle_tpmstate_options(char *options)
{
char *tpmstatedir = NULL;
if (!options)
return 0;
if (parse_tpmstate_options(options, &tpmstatedir) < 0)
return -1;
if (tpmstate_set_dir(tpmstatedir) < 0)
return -1;
free(tpmstatedir);
return 0;
}

View File

@ -41,6 +41,7 @@ int handle_log_options(char *options);
int handle_key_options(char *options);
int handle_migration_key_options(char *options);
int handle_pid_options(char *options);
int handle_tpmstate_options(char *options);
#endif /* _SWTPM_COMMON_H_ */

View File

@ -63,6 +63,7 @@
#include "main.h"
#include "common.h"
#include "pidfile.h"
#include "tpmstate.h"
#include <glib.h>
@ -112,6 +113,7 @@ struct ptm_param {
char *keydata;
char *migkeydata;
char *piddata;
char *tpmstatedata;
};
@ -197,10 +199,13 @@ static const char *usage =
"--log file=<path>|fd=<filedescriptor>\n"
" : write the TPM's log into the given file rather than\n"
" to the console; provide '-' for path to avoid logging\n"
"--pid file=<path> : write the process ID into the given file\n"
"--tpmstate dir=<dir>\n"
" : set the directory where the TPM's state will be written\n"
" into; the TPM_PATH environment variable can be used\n"
" instead\n"
""
"-h|--help : display this help screen and terminate\n"
"\n"
"Make sure that TPM_PATH environment variable points to directory\n"
"where TPM's NV storage file is kept\n"
"\n";
const static unsigned char TPM_Resp_FatalError[] = {
@ -372,24 +377,22 @@ _TPM_IO_TpmEstablished_Reset(fuse_req_t req,
static int tpm_start(uint32_t flags)
{
DIR *dir;
char * tpmdir = NULL;
const char *tpmdir = tpmstate_get_dir();
/* temporary - the backend script lacks the perms to do this */
if (tpmdir == NULL) {
tpmdir = getenv("TPM_PATH");
if (!tpmdir) {
logprintf(STDOUT_FILENO,
"Error: TPM_PATH is not set\n");
return -1;
}
logprintf(STDOUT_FILENO,
"Error: TPM_PATH is not set\n");
return -1;
}
dir = opendir(tpmdir);
if (dir) {
closedir(dir);
} else {
if (mkdir(tpmdir, 0775)) {
logprintf(STDERR_FILENO,
"Error: Could not open TPM_PATH dir\n");
"Error: Could not open tpmstate dir %s\n",
tpmdir);
return -1;
}
}
@ -1305,6 +1308,7 @@ static const struct fuse_opt ptm_opts[] = {
PTM_OPT("--key %s", keydata),
PTM_OPT("--migration-key %s", migkeydata),
PTM_OPT("--pid %s", piddata),
PTM_OPT("--tpmstate %s", tpmstatedata),
FUSE_OPT_KEY("-h", 0),
FUSE_OPT_KEY("--help", 0),
FUSE_OPT_KEY("-v", 1),
@ -1349,6 +1353,8 @@ int main(int argc, char **argv)
.logging = NULL,
.keydata = NULL,
.migkeydata = NULL,
.piddata = NULL,
.tpmstatedata = NULL,
};
char dev_name[128] = "DEVNAME=";
const char *dev_info_argv[] = { dev_name };
@ -1373,7 +1379,8 @@ int main(int argc, char **argv)
if (handle_log_options(param.logging) < 0 ||
handle_key_options(param.keydata) < 0 ||
handle_migration_key_options(param.migkeydata) < 0 ||
handle_pid_options(param.piddata) < 0)
handle_pid_options(param.piddata) < 0 ||
handle_tpmstate_options(param.tpmstatedata) < 0)
return -3;
if (setuid(0)) {

View File

@ -51,8 +51,10 @@ static char *g_pidfile;
int pidfile_set(const char *pidfile)
{
g_pidfile = strdup(pidfile);
if (!g_pidfile)
if (!g_pidfile) {
logprintf(STDERR_FILENO, "Out of memory.\n");
return -1;
}
return 0;
}

View File

@ -102,13 +102,12 @@ static void usage(FILE *file, const char *prgname, const char *iface)
"The following options are supported:\n"
"\n"
"-p|--port <port> : use the given port\n"
"-i|--dir <dir> : use the given directory\n"
"-f|--fd <fd> : use the given socket file descriptor\n"
"-t|--terminate : terminate the TPM once a connection has been lost\n"
"-d|--daemon : daemonize the TPM\n"
"--log file=<path>|fd=<filedescriptor>\n"
" : write the TPM's log into the given file rather than\n"
" to the console; provide '-' for path to avoid logging\n"
" : write the TPM's log into the given file rather than\n"
" to the console; provide '-' for path to avoid logging\n"
"--key file=<path>[,mode=aes-cbc][,format=hex|binary][,remove=[true|false]]\n"
" : use an AES key for the encryption of the TPM's state\n"
" files; use the given mode for the block encryption;\n"
@ -116,8 +115,14 @@ static void usage(FILE *file, const char *prgname, const char *iface)
" format; the keyfile can be automatically removed using\n"
" the remove parameter\n"
"--key pwdfile=<path>[,mode=aes-cbc][,remove=[true|false]]\n"
" : provide a passphrase in a file; the AES key will be\n"
" derived from this passphrase\n"
" : provide a passphrase in a file; the AES key will be\n"
" derived from this passphrase\n"
"--pid file=<path>\n"
" : write the process ID into the given file\n"
"--tpmstate dir=<dir>\n"
" : set the directory where the TPM's state will be written\n"
" into; the TPM_PATH environment variable can be used\n"
" instead\n"
"-h|--help : display this help screen and terminate\n"
"\n",
prgname, iface);
@ -148,6 +153,7 @@ int swtpm_main(int argc, char **argv, const char *prgname, const char *iface)
char *keydata = NULL;
char *logdata = NULL;
char *piddata = NULL;
char *tpmstatedata = NULL;
#ifdef DEBUG
time_t start_time;
#endif
@ -155,17 +161,17 @@ int swtpm_main(int argc, char **argv, const char *prgname, const char *iface)
{"daemon" , no_argument, 0, 'd'},
{"help" , no_argument, 0, 'h'},
{"port" , required_argument, 0, 'p'},
{"dir" , required_argument, 0, 'i'},
{"fd" , required_argument, 0, 'f'},
{"terminate" , no_argument, 0, 't'},
{"log" , required_argument, 0, 'l'},
{"key" , required_argument, 0, 'k'},
{"pid" , required_argument, 0, 'P'},
{"tpmstate" , required_argument, 0, 's'},
{NULL , 0 , 0, 0 },
};
while (TRUE) {
opt = getopt_long(argc, argv, "dhp:i:f:tk:", longopts, &longindex);
opt = getopt_long(argc, argv, "dhp:f:tk:P:s:", longopts, &longindex);
if (opt == -1)
break;
@ -194,13 +200,6 @@ int swtpm_main(int argc, char **argv, const char *prgname, const char *iface)
}
break;
case 'i':
if (setenv("TPM_PATH", optarg, 1) != 0) {
fprintf(stderr, "Could not set path: %s\n", strerror(errno));
exit(1);
}
break;
case 'f':
val = strtoul(optarg, &end_ptr, 10);
if (val != (unsigned int)val || errno || end_ptr[0] != '\0') {
@ -239,6 +238,10 @@ int swtpm_main(int argc, char **argv, const char *prgname, const char *iface)
piddata = optarg;
break;
case 's':
tpmstatedata = optarg;
break;
case 'h':
usage(stdout, prgname, iface);
exit(EXIT_SUCCESS);
@ -251,7 +254,8 @@ int swtpm_main(int argc, char **argv, const char *prgname, const char *iface)
if (handle_log_options(logdata) < 0 ||
handle_key_options(keydata) < 0 ||
handle_pid_options(piddata) < 0)
handle_pid_options(piddata) < 0 ||
handle_tpmstate_options(tpmstatedata) < 0)
return EXIT_FAILURE;
if (daemonize) {

View File

@ -80,6 +80,7 @@
#include "swtpm_nvfile.h"
#include "key.h"
#include "logging.h"
#include "tpmstate.h"
/* local structures */
typedef struct {
@ -157,14 +158,14 @@ char state_directory[FILENAME_MAX];
TPM_RESULT SWTPM_NVRAM_Init(void)
{
TPM_RESULT rc = 0;
char *tpm_state_path;
const char *tpm_state_path;
size_t length;
TPM_DEBUG(" SWTPM_NVRAM_Init:\n");
/* TPM_NV_DISK TPM emulation stores in local directory determined by environment variable. */
if (rc == 0) {
tpm_state_path = getenv("TPM_PATH");
tpm_state_path = tpmstate_get_dir();
if (tpm_state_path == NULL) {
fprintf(stderr,
"SWTPM_NVRAM_Init: Error (fatal), TPM_PATH environment "

67
src/swtpm/tpmstate.c Normal file
View File

@ -0,0 +1,67 @@
/*
* tpmstate.c -- tpmstate parameter handling
*
* (c) Copyright IBM Corporation 2015.
*
* Author: Stefan Berger <stefanb@us.ibm.com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the names of the IBM Corporation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include "tpmstate.h"
#include "logging.h"
static char *g_tpmstatedir;
int tpmstate_set_dir(char *tpmstatedir)
{
g_tpmstatedir = strdup(tpmstatedir);
if (!g_tpmstatedir) {
logprintf(STDERR_FILENO, "Out of memory.\n");
return -1;
}
return 0;
}
const char *tpmstate_get_dir(void)
{
if (g_tpmstatedir)
return g_tpmstatedir;
return getenv("TPM_PATH");
}

44
src/swtpm/tpmstate.h Normal file
View File

@ -0,0 +1,44 @@
/*
* tpmstate.h -- tpmstate parameter handling
*
* (c) Copyright IBM Corporation 2015.
*
* Author: Stefan Berger <stefanb@us.ibm.com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the names of the IBM Corporation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SWTPM_TPMSTATE_H_
#define _SWTPM_TPMSTATE_H_
int tpmstate_set_dir(char *tpmstatdir);
const char *tpmstate_get_dir(void);
#endif /* _SWTPM_TPMSTATE_H_ */

View File

@ -66,7 +66,7 @@ function wait_port_closed()
# Test 1: test port and directory command line parameters
$SWTPM_EXE socket -p $PORT -i $TPMDIR --pid file=$PID_FILE &>/dev/null &
$SWTPM_EXE socket -p $PORT --tpmstate dir=$TPMDIR --pid file=$PID_FILE &>/dev/null &
PID=$!
wait_port_open $PORT $PID
@ -117,7 +117,7 @@ cleanup
# that causes the swtpm process to exit upon connection close
TPMDIR=`mktemp -d`
$SWTPM_EXE socket -p $PORT -i $TPMDIR -t &>/dev/null &
$SWTPM_EXE socket -p $PORT --tpmstate dir=$TPMDIR -t &>/dev/null &
PID=$!
wait_port_open $PORT $PID

View File

@ -14,7 +14,7 @@ SWTPM=swtpm_cuse
SWTPM_EXE=$ROOT/src/swtpm/$SWTPM
CUSE_TPM_IOCTL=$ROOT/src/swtpm_ioctl/swtpm_ioctl
VTPM_NAME="vtpm-test-init"
export TPM_PATH=$(mktemp -d)
TPM_PATH=$(mktemp -d)
STATE_FILE=$TPM_PATH/tpm-00.permall
VOLATILE_STATE_FILE=$TPM_PATH/tpm-00.volatilestate
PID_FILE=$TPM_PATH/${SWTPM}.pid
@ -37,7 +37,7 @@ fi
rm -f $STATE_FILE $VOLATILE_STATE_FILE 2>/dev/null
$SWTPM_EXE --pid file=$PID_FILE -n $VTPM_NAME
$SWTPM_EXE --tpmstate dir=$TPM_PATH --pid file=$PID_FILE -n $VTPM_NAME
sleep 0.5
PID=$(ps aux | grep $SWTPM | grep -E "$VTPM_NAME\$" | gawk '{print $2}')