Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for file-backend locking #932

Merged
merged 8 commits into from
Oct 15, 2024
15 changes: 14 additions & 1 deletion man/man8/swtpm.pod
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ The following options are support by all interfaces:

=over 4

=item B<--tpmstate dir=E<lt>dirE<gt>[,mode=E<lt>0...E<gt>]|backend-uri=E<lt>uriE<gt>>
=item B<--tpmstate dir=E<lt>dirE<gt>|backend-uri=E<lt>uriE<gt>[,mode=E<lt>0...E<gt>][,lock]>

Use the given path rather than using the environment variable TPM_PATH.

Expand All @@ -174,6 +174,14 @@ For 'file://', the URI should specify a single file or block device where TPM st
will be stored. A blockdevice must exist already and be big enough to store all
state. (since v0.7)

If I<lock> is specified then the TPM storage backend will lock the TPM state
file to avoid concurrent access to it by another swtpm instance. The default
value, if this option parameter is missing, depends on the storage backend.
For the directory-backend the default is that locking is always enabled, and
therefore this option parameter does not need to be given. For the file backend
it is required since the default is that locking is not automatically
enabled. To avoid locking, I<lock=false> can be used.

=item B<--tpm2>

Choose TPM 2 functionality; by default a TPM 1.2 is chosen.
Expand Down Expand Up @@ -338,6 +346,7 @@ may contain the following:
"cmdarg-print-profiles",
"profile-opt-remove-disabled",
"cmdarg-print-info",
"tpmstate-opt-lock"
],
"version": "0.7.0"
}
Expand Down Expand Up @@ -430,6 +439,10 @@ parameter.

The option I<--print-info> is supported.

=item B<tpmstate-opt-lock> (since v0.10)

The option parameter I<lock> for the I<--tpmstate> option is supported.

=back

=item B<--print-states> (since v0.7)
Expand Down
3 changes: 2 additions & 1 deletion src/swtpm/capabilities.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ int capabilities_print_json(bool cusetpm, TPMLIB_TPMVersion tpmversion)
"{ "
"\"type\": \"swtpm\", "
"\"features\": [ "
"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
" ], "
"\"profiles\": { %s}, "
"\"version\": \"" VERSION "\" "
Expand All @@ -294,6 +294,7 @@ int capabilities_print_json(bool cusetpm, TPMLIB_TPMVersion tpmversion)
true ? ", \"cmdarg-print-profiles\"" : "",
true ? ", \"profile-opt-remove-disabled\"" : "",
true ? ", \"cmdarg-print-info\"" : "",
true ? ", \"tpmstate-opt-lock\"" : "",
profiles ? profiles : ""
);

Expand Down
29 changes: 19 additions & 10 deletions src/swtpm/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ static const OptionDesc tpmstate_opt_desc[] = {
}, {
.name = "backend-uri",
.type = OPT_TYPE_STRING,
}, {
.name = "lock",
.type = OPT_TYPE_BOOLEAN,
},
END_OPTION_DESC
};
Expand Down Expand Up @@ -658,17 +661,21 @@ handle_pid_options(const char *options)
* @mode: the mode of the TPM's state files
* @mode_is_default: true if user did not provide mode bits but using default
* @tpmbackend_uri: Point to pointer for backend URI
* @do_locking: whether the backend should file-lock the storage
*
* Returns 0 on success, -1 on failure.
*/
static int
parse_tpmstate_options(const char *options, char **tpmstatedir, mode_t *mode,
bool *mode_is_default, char **tpmbackend_uri)
bool *mode_is_default, char **tpmbackend_uri,
bool *do_locking)
{
OptionValues *ovs = NULL;
char *error = NULL;
const char *directory = NULL;
const char *backend_uri = NULL;
/* historically dir backend always locked, file backend did not */
bool lock_default = true;

ovs = options_parse(options, tpmstate_opt_desc, &error);
if (!ovs) {
Expand Down Expand Up @@ -698,13 +705,17 @@ parse_tpmstate_options(const char *options, char **tpmstatedir, mode_t *mode,
logprintf(STDERR_FILENO, "Out of memory.");
goto error;
}
if (strncmp(*tpmbackend_uri, "file://", 7) == 0)
lock_default = false;
} else {
logprintf(STDERR_FILENO,
"The dir or backend-uri parameters is required "
"for the tpmstate option.\n");
goto error;
}

*do_locking = option_get_bool(ovs, "lock", lock_default);

option_values_free(ovs);

return 0;
Expand Down Expand Up @@ -733,12 +744,14 @@ handle_tpmstate_options(const char *options)
int ret = 0;
mode_t mode;
bool mode_is_default = true;
bool do_locking = false;

if (!options)
return 0;

if (parse_tpmstate_options(options, &tpmstatedir, &mode,
&mode_is_default, &tpmbackend_uri) < 0) {
&mode_is_default, &tpmbackend_uri,
&do_locking) < 0) {
ret = -1;
goto error;
}
Expand All @@ -753,8 +766,7 @@ handle_tpmstate_options(const char *options)
goto error;
}

if (tpmstate_set_backend_uri(temp_uri) < 0 ||
tpmstate_set_mode(mode, mode_is_default) < 0) {
if (tpmstate_set_backend_uri(temp_uri) < 0) {
ret = -1;
goto error;
}
Expand All @@ -763,14 +775,11 @@ handle_tpmstate_options(const char *options)
ret = -1;
goto error;
}
if ((strncmp(tpmbackend_uri, "dir://", 6) == 0 ||
strncmp(tpmbackend_uri, "file://", 7)) &&
tpmstate_set_mode(mode, mode_is_default) < 0) {
ret = -1;
goto error;
}
}

tpmstate_set_mode(mode, mode_is_default);
tpmstate_set_locking(do_locking);

error:
free(tpmstatedir);
free(tpmbackend_uri);
Expand Down
3 changes: 2 additions & 1 deletion src/swtpm/cuse_tpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,12 +248,13 @@ static void usage(FILE *file, const char *prgname, const char *iface)
" the log file can be reset (truncate)\n"
"--pid file=<path>|fd=<filedescriptor>\n"
" : write the process ID into the given file\n"
"--tpmstate dir=<dir>[,mode=0...]|backend-uri=<uri>\n"
"--tpmstate dir=<dir>|backend-uri=<uri>[,mode=0...][,lock]\n"
" : set the directory or uri where the TPM's state will be written\n"
" into; the TPM_PATH environment variable can be used\n"
" instead of dir option;\n"
" mode allows a user to set the file mode bits of the state\n"
" files; the default mode is 0640;\n"
" lock enables file-locking by the storage backend;\n"
"--flags [not-need-init][,startup-clear|startup-state|startup-deactivated|startup-none][,disable-auto-shutdown]\n"
" : not-need-init: commands can be sent without needing to\n"
" send an INIT via control channel;\n"
Expand Down
3 changes: 2 additions & 1 deletion src/swtpm/swtpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,13 @@ static void usage(FILE *file, const char *prgname, const char *iface)
" allow-set-locality: accept SetLocality command\n"
"--pid file=<path>|fd=<filedescriptor>\n"
" : write the process ID into the given file\n"
"--tpmstate dir=<dir>[,mode=0...]|backend-uri=<uri>\n"
"--tpmstate dir=<dir>|backend-uri=<uri>[,mode=0...][,lock]\n"
" : set the directory or uri where the TPM's state will be written\n"
" into; the TPM_PATH environment variable can be used\n"
" instead dir option;\n"
" mode allows a user to set the file mode bits of the state files;\n"
" the default mode is 0640;\n"
" lock enables file-locking by the storage backend;\n"
"--server [type=tcp][,port=port[,bindaddr=address[,ifname=ifname]]][,fd=fd][,disconnect]\n"
" : Expect TCP connections on the given port;\n"
" if fd is provided, packets will be read from it directly;\n"
Expand Down
3 changes: 2 additions & 1 deletion src/swtpm/swtpm_chardev.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,13 @@ static void usage(FILE *file, const char *prgname, const char *iface)
" derived from this passphrase; default kdf is PBKDF2\n"
"--pid file=<path>|fd=<filedescriptor>\n"
" : write the process ID into the given file\n"
"--tpmstate dir=<dir>[,mode=0...]|backend-uri=<uri>\n"
"--tpmstate dir=<dir>|backend-uri=<uri>[,mode=0...][,lock]\n"
" : set the directory or uri where the TPM's state will be written\n"
" into; the TPM_PATH environment variable can be used\n"
" instead of dir option;\n"
" mode allows a user to set the file mode bits of the state files;\n"
" the default mode is 0640;\n"
" lock enables file-locking by the storage backend;\n"
"-r|--runas <user>: change to the given user\n"
"-R|--chroot <path>\n"
" : chroot to the given directory at startup\n"
Expand Down
18 changes: 12 additions & 6 deletions src/swtpm/swtpm_nvstore.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,11 @@ TPM_RESULT SWTPM_NVRAM_Lock_Storage(unsigned int retries)
{
const char *backend_uri;

if (!tpmstate_get_locking()) {
/* no locking requested by user */
return TPM_SUCCESS;
}

if (!g_nvram_backend_ops)
return TPM_RETRY;

Expand All @@ -220,16 +225,17 @@ TPM_RESULT SWTPM_NVRAM_Lock_Storage(unsigned int retries)
"SWTPM_NVRAM_Lock: Missing backend URI.\n");
return TPM_FAIL;
}
if (g_nvram_backend_ops->lock)
return g_nvram_backend_ops->lock(backend_uri, retries);

return TPM_SUCCESS;
return g_nvram_backend_ops->lock(backend_uri, retries);
}

void SWTPM_NVRAM_Unlock(void)
{
if (g_nvram_backend_ops->unlock)
g_nvram_backend_ops->unlock();
if (!tpmstate_get_locking()) {
/* no locking requested by user */
return;
}

g_nvram_backend_ops->unlock();
}

/* SWTPM_NVRAM_GetFilenameForName() constructs a file name from the name.
Expand Down
15 changes: 15 additions & 0 deletions src/swtpm/swtpm_nvstore_linear.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,19 @@ SWTPM_NVRAM_Prepare_Linear(const char *uri)
return rc;
}

static TPM_RESULT
SWTPM_NVRAM_Lock_Linear(const char *backend_uri,
unsigned int retries)
{
return state.ops->lock(backend_uri, retries);
}

static void
SWTPM_NVRAM_Unlock_Linear(void)
{
state.ops->unlock();
}

static TPM_RESULT
SWTPM_NVRAM_LoadData_Linear(unsigned char **data,
uint32_t *length,
Expand Down Expand Up @@ -476,6 +489,8 @@ SWTPM_NVRAM_CheckState_Linear(const char *uri SWTPM_ATTR_UNUSED,

struct nvram_backend_ops nvram_linear_ops = {
.prepare = SWTPM_NVRAM_Prepare_Linear,
.lock = SWTPM_NVRAM_Lock_Linear,
.unlock = SWTPM_NVRAM_Unlock_Linear,
.load = SWTPM_NVRAM_LoadData_Linear,
.store = SWTPM_NVRAM_StoreData_Linear,
.delete = SWTPM_NVRAM_DeleteName_Linear,
Expand Down
15 changes: 15 additions & 0 deletions src/swtpm/swtpm_nvstore_linear.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
#define SWTPM_NVSTORE_LINEAR_MAGIC 0x737774706d6c696e /* 'swtpmlin' */
#define SWTPM_NVSTORE_LINEAR_VERSION 1
/* TODO: Make this user configurable? */
/*
* Without distributed locking to coordinate concurrent access on
* block devices: 1 TPM only
*/
#define SWTPM_NVSTORE_LINEAR_MAX_STATES 15 /* 3 files per TPM = 5 TPMs */

struct nvram_linear_hdr_file {
Expand Down Expand Up @@ -47,6 +51,17 @@ struct nvram_linear_store_ops {
unsigned char **data,
uint32_t *length);

/*
File-lock the storage backend from concurrent usage by other processes.
*/
TPM_RESULT (*lock)(const char *uri,
unsigned int retries);

/*
Unlock the file-locked storage backend.
*/
void (*unlock)(void);

/*
Called whenever the data in the provided buffer has changed. Will be
called for every changed region, offset is relative to base (0 is for
Expand Down
Loading