From 133789e1bf369d592a67297f57e4adb2b7c64c3f Mon Sep 17 00:00:00 2001 From: Konstantin Kostiuk Date: Mon, 10 Jul 2023 12:51:35 +0300 Subject: [PATCH] qga: Add new option --allow-rpcs MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The allow-rpcs option accepts a comma-separated list of RPCs to enable. This option is opposite to --block-rpcs. Using --block-rpcs and --allow-rpcs at the same time is not allowed. resolves: https://gitlab.com/qemu-project/qemu/-/issues/1505 Reviewed-by: Marc-André Lureau Signed-off-by: Konstantin Kostiuk --- docs/interop/qemu-ga.rst | 5 +++ qga/main.c | 85 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 84 insertions(+), 6 deletions(-) diff --git a/docs/interop/qemu-ga.rst b/docs/interop/qemu-ga.rst index a9183802d1..461c5a35ee 100644 --- a/docs/interop/qemu-ga.rst +++ b/docs/interop/qemu-ga.rst @@ -84,6 +84,11 @@ Options Comma-separated list of RPCs to disable (no spaces, use ``help`` to list available RPCs). +.. option:: -a, --allow-rpcs=LIST + + Comma-separated list of RPCs to enable (no spaces, use ``help`` to + list available RPCs). + .. option:: -D, --dump-conf Dump the configuration in a format compatible with ``qemu-ga.conf`` diff --git a/qga/main.c b/qga/main.c index 121ff7a748..002161a0cc 100644 --- a/qga/main.c +++ b/qga/main.c @@ -87,6 +87,7 @@ struct GAState { bool delimit_response; bool frozen; GList *blockedrpcs; + GList *allowedrpcs; char *state_filepath_isfrozen; struct { const char *log_filepath; @@ -261,6 +262,8 @@ QEMU_COPYRIGHT "\n" #endif " -b, --block-rpcs comma-separated list of RPCs to disable (no spaces,\n" " use \"help\" to list available RPCs)\n" +" -a, --allow-rpcs comma-separated list of RPCs to enable (no spaces,\n" +" use \"help\" to list available RPCs)\n" " -D, --dump-conf dump a qemu-ga config file based on current config\n" " options / command-line parameters to stdout\n" " -r, --retry-path attempt re-opening path if it's unavailable or closed\n" @@ -416,16 +419,38 @@ static void ga_disable_not_allowed_freeze(const QmpCommand *cmd, void *opaque) /* [re-]enable all commands, except those explicitly blocked by user */ static void ga_enable_non_blocked(const QmpCommand *cmd, void *opaque) { - GList *blockedrpcs = opaque; + GAState *s = opaque; + GList *blockedrpcs = s->blockedrpcs; + GList *allowedrpcs = s->allowedrpcs; const char *name = qmp_command_name(cmd); - if (g_list_find_custom(blockedrpcs, name, ga_strcmp) == NULL && - !qmp_command_is_enabled(cmd)) { + if (g_list_find_custom(blockedrpcs, name, ga_strcmp) == NULL) { + if (qmp_command_is_enabled(cmd)) { + return; + } + + if (allowedrpcs && + g_list_find_custom(allowedrpcs, name, ga_strcmp) == NULL) { + return; + } + g_debug("enabling command: %s", name); qmp_enable_command(&ga_commands, name); } } +/* disable commands that aren't allowed */ +static void ga_disable_not_allowed(const QmpCommand *cmd, void *opaque) +{ + GList *allowedrpcs = opaque; + const char *name = qmp_command_name(cmd); + + if (g_list_find_custom(allowedrpcs, name, ga_strcmp) == NULL) { + g_debug("disabling command: %s", name); + qmp_disable_command(&ga_commands, name, "the command is not allowed"); + } +} + static bool ga_create_file(const char *path) { int fd = open(path, O_CREAT | O_WRONLY, S_IWUSR | S_IRUSR); @@ -497,8 +522,8 @@ void ga_unset_frozen(GAState *s) s->deferred_options.pid_filepath = NULL; } - /* enable all disabled, non-blocked commands */ - qmp_for_each_command(&ga_commands, ga_enable_non_blocked, s->blockedrpcs); + /* enable all disabled, non-blocked and allowed commands */ + qmp_for_each_command(&ga_commands, ga_enable_non_blocked, s); s->frozen = false; if (!ga_delete_file(s->state_filepath_isfrozen)) { g_warning("unable to delete %s, fsfreeze may not function properly", @@ -984,7 +1009,9 @@ struct GAConfig { const char *service; #endif gchar *bliststr; /* blockedrpcs may point to this string */ + gchar *aliststr; /* allowedrpcs may point to this string */ GList *blockedrpcs; + GList *allowedrpcs; int daemonize; GLogLevelFlags log_level; int dumpconf; @@ -1055,6 +1082,19 @@ static void config_load(GAConfig *config) config->blockedrpcs = g_list_concat(config->blockedrpcs, split_list(config->bliststr, ",")); } + if (g_key_file_has_key(keyfile, "general", "allow-rpcs", NULL)) { + config->aliststr = + g_key_file_get_string(keyfile, "general", "allow-rpcs", &gerr); + config->allowedrpcs = g_list_concat(config->allowedrpcs, + split_list(config->aliststr, ",")); + } + + if (g_key_file_has_key(keyfile, "general", blockrpcs_key, NULL) && + g_key_file_has_key(keyfile, "general", "allow-rpcs", NULL)) { + g_critical("wrong config, using 'block-rpcs' and 'allow-rpcs' keys at" + " the same time is not allowed"); + exit(EXIT_FAILURE); + } end: g_key_file_free(keyfile); @@ -1115,6 +1155,9 @@ static void config_dump(GAConfig *config) tmp = list_join(config->blockedrpcs, ','); g_key_file_set_string(keyfile, "general", "block-rpcs", tmp); g_free(tmp); + tmp = list_join(config->allowedrpcs, ','); + g_key_file_set_string(keyfile, "general", "allow-rpcs", tmp); + g_free(tmp); tmp = g_key_file_to_data(keyfile, NULL, &error); if (error) { @@ -1130,8 +1173,9 @@ static void config_dump(GAConfig *config) static void config_parse(GAConfig *config, int argc, char **argv) { - const char *sopt = "hVvdm:p:l:f:F::b:s:t:Dr"; + const char *sopt = "hVvdm:p:l:f:F::b:a:s:t:Dr"; int opt_ind = 0, ch; + bool block_rpcs = false, allow_rpcs = false; const struct option lopt[] = { { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'V' }, @@ -1147,6 +1191,7 @@ static void config_parse(GAConfig *config, int argc, char **argv) { "daemonize", 0, NULL, 'd' }, { "block-rpcs", 1, NULL, 'b' }, { "blacklist", 1, NULL, 'b' }, /* deprecated alias for 'block-rpcs' */ + { "allow-rpcs", 1, NULL, 'a' }, #ifdef _WIN32 { "service", 1, NULL, 's' }, #endif @@ -1206,6 +1251,17 @@ static void config_parse(GAConfig *config, int argc, char **argv) } config->blockedrpcs = g_list_concat(config->blockedrpcs, split_list(optarg, ",")); + block_rpcs = true; + break; + } + case 'a': { + if (is_help_option(optarg)) { + qmp_for_each_command(&ga_commands, ga_print_cmd, NULL); + exit(EXIT_SUCCESS); + } + config->allowedrpcs = g_list_concat(config->allowedrpcs, + split_list(optarg, ",")); + allow_rpcs = true; break; } #ifdef _WIN32 @@ -1246,6 +1302,12 @@ static void config_parse(GAConfig *config, int argc, char **argv) exit(EXIT_FAILURE); } } + + if (block_rpcs && allow_rpcs) { + g_critical("wrong commandline, using --block-rpcs and --allow-rpcs at the" + " same time is not allowed"); + exit(EXIT_FAILURE); + } } static void config_free(GAConfig *config) @@ -1256,10 +1318,12 @@ static void config_free(GAConfig *config) g_free(config->state_dir); g_free(config->channel_path); g_free(config->bliststr); + g_free(config->aliststr); #ifdef CONFIG_FSFREEZE g_free(config->fsfreeze_hook); #endif g_list_free_full(config->blockedrpcs, g_free); + g_list_free_full(config->allowedrpcs, g_free); g_free(config); } @@ -1374,6 +1438,15 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation) return NULL; } + if (config->allowedrpcs) { + qmp_for_each_command(&ga_commands, ga_disable_not_allowed, config->allowedrpcs); + s->allowedrpcs = config->allowedrpcs; + } + + /* + * Some commands can be blocked due to system limitation. + * Initialize blockedrpcs list even if allowedrpcs specified. + */ config->blockedrpcs = ga_command_init_blockedrpcs(config->blockedrpcs); if (config->blockedrpcs) { GList *l = config->blockedrpcs; -- 2.11.0