From 02ca22e7f67f964eb7c4162ba3fb52aa965e3379 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Tue, 28 Jun 2022 17:21:06 -0400 Subject: [PATCH] swtpm: Support parsing of JSON maps as option values Allow passing a JSON map as part of an option value in the format of --foo name={...},... Prior to this patch this would not have worked since the option values were broken apart around commas, which a map may also contain. Now, if a '{' is following the '=', the value is attempted to be parsed as a JSON map and the end of the map is searched considering possibly embedded maps. Signed-off-by: Stefan Berger --- src/swtpm/options.c | 100 +++++++++++++++++++++++++++- tests/_test_print_capabilities | 4 +- tests/_test_tpm2_print_capabilities | 5 +- 3 files changed, 103 insertions(+), 6 deletions(-) diff --git a/src/swtpm/options.c b/src/swtpm/options.c index fbc3bee6..a21919d2 100644 --- a/src/swtpm/options.c +++ b/src/swtpm/options.c @@ -193,6 +193,97 @@ option_value_add(OptionValues *ovs, const OptionDesc optdesc, const char *val, return ret; } +/* + * option_parse_token: + * Parse an option that may have one of the following formats + * 1) name[,n2=v2[,...]] + * 2) name=value[,n2=v2[,...]] + * 3) name={...}[,n2=v2[,...]] + * Case 3 allows to parse values containing a JSON map. + * + * @str: On first call this must be the string to break into tokens; + * on subsequent calls this should be NULL + * @saveptr: A pointer to a pointer where this function stores the address + * to continue parsing next time + * @tok: The function returns the pointer to the beginning of the token here; + * The token lies withing the given @str and @str may be modified for + * NUL-terminating the token + * @char: A pointer where to store a string pointer in case of error + * + * In case of success this function returns 0, -1 otherwise. + */ +static int +option_parse_token(char *str, char **saveptr, char **tok, char **error) +{ + char *comma, *equals; + + if (!str) + str = *saveptr; + + *tok = str; + if (!str) + return 0; + + equals = strchr(str, '='); + comma = strchr(str, ','); + /* don't care about '=' after a ',' */ + if (equals > comma) + equals = NULL; + + if (equals != NULL && equals[1] == '{') { + unsigned long c = 1; + char *eom = NULL; + size_t i = 2; + + /* find terminating "}" considering nested maps */ + eom = NULL; + while (equals[i] && !eom) { + switch (equals[i]) { + case '{': + c++; + break; + case '}': + c--; + if (c == 0) + eom = &equals[i]; + break; + } + i++; + } + + if (!eom) { + option_error_set(error, "Unterminated JSON map."); + return -1; + } + + /* what follows the "}" ? */ + switch (eom[1]) { + case ',': + eom[1] = 0; + *saveptr = &eom[2]; + break; + case '\0': + /* this was the last item */ + *saveptr = NULL; + break; + default: + option_error_set(error, "Unexpected character following JSON map."); + return -1; + } + } else { + if (!comma) { + /* this is the last item */ + *saveptr = NULL; + } else { + comma[0] = '\0'; + *saveptr = &comma[1]; + } + } + *tok = str; + + return 0; +} + /* * options_parse: * Parse the string of options following the template; return the @@ -226,7 +317,10 @@ options_parse(char *opts, const OptionDesc optdesc[], char **error) saveptr = opts_bak; /* make coverity happy */ - tok = strtok_r(opts_bak, ",", &saveptr); + if (option_parse_token(opts_bak, &saveptr, &tok, error) < 0) { + goto error; + } + while (tok) { size_t toklen = strlen(tok); @@ -256,7 +350,9 @@ options_parse(char *opts, const OptionDesc optdesc[], char **error) goto error; } - tok = strtok_r(NULL, ",", &saveptr); + if (option_parse_token(NULL, &saveptr, &tok, error) < 0) { + goto error; + } } free(opts_bak); diff --git a/tests/_test_print_capabilities b/tests/_test_print_capabilities index 37cb94b9..e543fac2 100755 --- a/tests/_test_print_capabilities +++ b/tests/_test_print_capabilities @@ -28,7 +28,7 @@ exp='\{ "type": "swtpm", '\ '"features": \[ "tpm-1.2",( "tpm-2.0",)? '${noncuse}'"flags-opt-startup", '\ '"flags-opt-disable-auto-shutdown", "ctrl-opt-terminate", '${seccomp}'"cmdarg-key-fd", '\ '"cmdarg-pwd-fd", "cmdarg-print-states", "cmdarg-chroot", "cmdarg-migration", '\ -'"nvram-backend-dir", "nvram-backend-file" \], '\ +'"nvram-backend-dir", "nvram-backend-file"(, "cmdarg-profile")? \], '\ '"version": "[^"]*" \}' if ! [[ ${msg} =~ ${exp} ]]; then echo "Unexpected response from ${SWTPM_IFACE} TPM to --print-capabilities:" @@ -50,7 +50,7 @@ exp='\{ "type": "swtpm_setup", '\ '"features": \[ "tpm-1.2",( "tpm-2.0",)? "cmdarg-keyfile-fd", "cmdarg-pwdfile-fd", '\ '"tpm12-not-need-root", "cmdarg-write-ek-cert-files", "cmdarg-create-config-files", '\ '"cmdarg-reconfigure-pcr-banks"'\ -'(, "tpm2-rsa-keysize-2048")?(, "tpm2-rsa-keysize-3072")? \], '\ +'(, "tpm2-rsa-keysize-2048")?(, "tpm2-rsa-keysize-3072")?(, "cmdarg-profile")? \], '\ '"version": "[^"]*" \}' if ! [[ ${msg} =~ ${exp} ]]; then echo "Unexpected response from ${SWTPM_SETUP} to --print-capabilities:" diff --git a/tests/_test_tpm2_print_capabilities b/tests/_test_tpm2_print_capabilities index 55c689fd..7b271b37 100755 --- a/tests/_test_tpm2_print_capabilities +++ b/tests/_test_tpm2_print_capabilities @@ -30,7 +30,8 @@ exp='\{ "type": "swtpm", '\ '"flags-opt-disable-auto-shutdown", "ctrl-opt-terminate", '${seccomp}'"cmdarg-key-fd", '\ '"cmdarg-pwd-fd", "cmdarg-print-states", "cmdarg-chroot", "cmdarg-migration", '\ '"nvram-backend-dir", "nvram-backend-file"'\ -'(, "rsa-keysize-1024")?(, "rsa-keysize-2048")?(, "rsa-keysize-3072")? \], '\ +'(, "rsa-keysize-1024")?(, "rsa-keysize-2048")?(, "rsa-keysize-3072")?'\ +'(, "cmdarg-profile")? \], '\ '"version": "[^"]*" \}' if ! [[ ${msg} =~ ${exp} ]]; then echo "Unexpected response from ${SWTPM_IFACE} TPM to --print-capabilities:" @@ -52,7 +53,7 @@ exp='\{ "type": "swtpm_setup", '\ '"features": \[( "tpm-1.2",)? "tpm-2.0", "cmdarg-keyfile-fd", "cmdarg-pwdfile-fd", '\ '"tpm12-not-need-root", "cmdarg-write-ek-cert-files", "cmdarg-create-config-files", '\ '"cmdarg-reconfigure-pcr-banks"(, "tpm2-rsa-keysize-2048")?(, "tpm2-rsa-keysize-3072")?'\ -' \], '\ +'(, "cmdarg-profile")? \], '\ '"version": "[^"]*" \}' if ! [[ ${msg} =~ ${exp} ]]; then echo "Unexpected response from ${SWTPM_SETUP} to --print-capabilities:"