diff mbox series

[v2,2/3] qga: Add new option --allow-rpcs

Message ID 20230710095136.1022704-3-kkostiuk@redhat.com
State New
Headers show
Series qga: Add new option --allow-rpcs | expand

Commit Message

Konstantin Kostiuk July 10, 2023, 9:51 a.m. UTC
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

Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
 docs/interop/qemu-ga.rst |  5 +++
 qga/main.c               | 85 +++++++++++++++++++++++++++++++++++++---
 2 files changed, 84 insertions(+), 6 deletions(-)

Comments

Marc-André Lureau July 10, 2023, 10:34 a.m. UTC | #1
On Mon, Jul 10, 2023 at 1:53 PM Konstantin Kostiuk <kkostiuk@redhat.com>
wrote:

> 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
>
> Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
>

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

> ---
>  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.34.1
>
>
>
diff mbox series

Patch

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;