qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
To: qemu-devel@nongnu.org, "Daniel P. Berrangé " <berrange@redhat.com>
Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>,
	"Philippe Mathieu-Daudé " <philmd@linaro.org>,
	"Konstantin Kostiuk" <kkostiuk@redhat.com>,
	"Daniel P. Berrangé " <berrange@redhat.com>,
	"Thomas Huth" <thuth@redhat.com>,
	"Michael Roth" <michael.roth@amd.com>,
	"Paolo Bonzini" <pbonzini@redhat.com>
Subject: Re: [PATCH v2 22/22] qga: centralize logic for disabling/enabling commands
Date: Wed, 03 Jul 2024 13:01:11 +0300	[thread overview]
Message-ID: <g1m2c.r93vk15jos2y@linaro.org> (raw)
In-Reply-To: <20240613154406.1365469-17-berrange@redhat.com>

Hello Daniel,

This cleanup seems like a good idea,

On Thu, 13 Jun 2024 18:44, "Daniel P. Berrangé" <berrange@redhat.com> wrote:
>It is confusing having many different pieces of code enabling and
>disabling commands, and it is not clear that they all have the same
>semantics, especially wrt prioritization of the block/allow lists.
>The code attempted to prevent the user from setting both the block
>and allow lists concurrently, however, the logic was flawed as it
>checked settings in the configuration file  separately from the
>command line arguments. Thus it was possible to set a block list
>in the config file and an allow list via a command line argument.
>The --dump-conf option also creates a configuration file with both
>keys present, even if unset, which means it is creating a config
>that cannot actually be loaded again.
>
>Centralizing the code in a single method "ga_apply_command_filters"
>will provide a strong guarantee of consistency and clarify the
>intended behaviour. With this there is no compelling technical
>reason to prevent concurrent setting of both the allow and block
>lists, so this flawed restriction is removed.
>
>Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
>---
> docs/interop/qemu-ga.rst |  14 +++++
> qga/commands-posix.c     |   6 --
> qga/commands-win32.c     |   6 --
> qga/main.c               | 128 +++++++++++++++++----------------------
> 4 files changed, 70 insertions(+), 84 deletions(-)
>
>diff --git a/docs/interop/qemu-ga.rst b/docs/interop/qemu-ga.rst
>index e42b370319..e35dcaf0e7 100644
>--- a/docs/interop/qemu-ga.rst
>+++ b/docs/interop/qemu-ga.rst
>@@ -28,6 +28,20 @@ configuration options on the command line. For the same key, the last
> option wins, but the lists accumulate (see below for configuration
> file format).
> 
>+If an allowed RPCs list is defined in the configuration, then all
>+RPCs will be blocked by default, except for the allowed list.
>+
>+If a blocked RPCs list is defined in the configuration, then all
>+RPCs will be allowed by default, except for the blocked list.
>+
>+If both allowed and blocked RPCs lists are defined in the configuration,
>+then all RPCs will be blocked by default, and then allowed list will
>+be applied, followed by the blocked list.

Nit: Missing an article here

-then all RPCs will be blocked by default, and then allowed list will
+then all RPCs will be blocked by default, then the allowed list will


>+
>+While filesystems are frozen, all except for a designated safe set
>+of RPCs will blocked, regardless of what the general configuration
>+declares.
>+
> Options
> -------
> 
>diff --git a/qga/commands-posix.c b/qga/commands-posix.c
>index f4104f2760..578d29f228 100644
>--- a/qga/commands-posix.c
>+++ b/qga/commands-posix.c
>@@ -1136,12 +1136,6 @@ error:
> 
> #endif /* HAVE_GETIFADDRS */
> 
>-/* add unsupported commands to the list of blocked RPCs */
>-GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
>-{
>-    return blockedrpcs;
>-}
>-
> /* register init/cleanup routines for stateful command groups */
> void ga_command_state_init(GAState *s, GACommandState *cs)
> {
>diff --git a/qga/commands-win32.c b/qga/commands-win32.c
>index 5866cc2e3c..61b36da469 100644
>--- a/qga/commands-win32.c
>+++ b/qga/commands-win32.c
>@@ -1958,12 +1958,6 @@ done:
>     g_free(rawpasswddata);
> }
> 
>-/* add unsupported commands to the list of blocked RPCs */
>-GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
>-{
>-    return blockedrpcs;
>-}
>-
> /* register init/cleanup routines for stateful command groups */
> void ga_command_state_init(GAState *s, GACommandState *cs)
> {
>diff --git a/qga/main.c b/qga/main.c
>index f68a32bf7b..72c16fead8 100644
>--- a/qga/main.c
>+++ b/qga/main.c
>@@ -419,60 +419,79 @@ static gint ga_strcmp(gconstpointer str1, gconstpointer str2)
>     return strcmp(str1, str2);
> }
> 
>-/* disable commands that aren't safe for fsfreeze */
>-static void ga_disable_not_allowed_freeze(const QmpCommand *cmd, void *opaque)
>+static bool ga_command_is_allowed(const QmpCommand *cmd, GAState *state)
> {
>-    bool allowed = false;
>     int i = 0;
>+    GAConfig *config = state->config;
>     const char *name = qmp_command_name(cmd);
>+    /* Fallback policy is allow everything */
>+    bool allowed = true;
> 
>-    while (ga_freeze_allowlist[i] != NULL) {
>-        if (strcmp(name, ga_freeze_allowlist[i]) == 0) {
>+    if (config->allowedrpcs) {
>+        /*
>+         * If an allow-list is given, this changes the fallback
>+         * policy to deny everything
>+         */
>+        allowed = false;
>+
>+        if (g_list_find_custom(config->allowedrpcs, name, ga_strcmp) != NULL) {
>             allowed = true;
>         }
>-        i++;
>     }
>-    if (!allowed) {
>-        g_debug("disabling command: %s", name);
>-        qmp_disable_command(&ga_commands, name, "the agent is in frozen state");
>-    }
>-}
> 
>-/* [re-]enable all commands, except those explicitly blocked by user */
>-static void ga_enable_non_blocked(const QmpCommand *cmd, void *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) {
>-        if (qmp_command_is_enabled(cmd)) {
>-            return;
>+    /*
>+     * If both allowedrpcs and blockedrpcs are set, the blocked
>+     * list will take priority
>+     */
>+    if (config->blockedrpcs) {
>+        if (g_list_find_custom(config->blockedrpcs, name, ga_strcmp) != NULL) {
>+            allowed = false;
>         }
>+    }
> 
>-        if (allowedrpcs &&
>-            g_list_find_custom(allowedrpcs, name, ga_strcmp) == NULL) {
>-            return;
>-        }
>+    /*
>+     * If frozen, this filtering must take priority over
>+     * absolutely everything
>+     */
>+    if (state->frozen) {
>+        allowed = false;
> 
>-        g_debug("enabling command: %s", name);
>-        qmp_enable_command(&ga_commands, name);
>+        while (ga_freeze_allowlist[i] != NULL) {
>+            if (strcmp(name, ga_freeze_allowlist[i]) == 0) {
>+                allowed = true;
>+            }
>+            i++;
>+        }
>     }
>+
>+    return allowed;
> }

IUUC, we can check by priority here: first check if (state->frozen), 
then blockedrpcs, then allowedrpcs and then return a default fallback 
value allowed = config->blockedrpcs != NULL && config->allowedrpcs != 
NULL

This way the function will sort of document what is written on the docs 
as well.


> 
>-/* disable commands that aren't allowed */
>-static void ga_disable_not_allowed(const QmpCommand *cmd, void *opaque)
>+static void ga_apply_command_filters_iter(const QmpCommand *cmd, void *opaque)
> {
>-    GList *allowedrpcs = opaque;
>+    GAState *state = opaque;
>+    bool want = ga_command_is_allowed(cmd, state);
>+    bool have = qmp_command_is_enabled(cmd);
>     const char *name = qmp_command_name(cmd);
> 
>-    if (g_list_find_custom(allowedrpcs, name, ga_strcmp) == NULL) {
>+    if (want == have) {
>+        return;
>+    }
>+
>+    if (qmp_command_is_enabled(cmd)) {

Nit:

  if (have) {

Since it's already declared.

>         g_debug("disabling command: %s", name);
>         qmp_disable_command(&ga_commands, name, "the command is not allowed");
>+    } else {
>+        g_debug("enabling command: %s", name);
>+        qmp_enable_command(&ga_commands, name);
>     }
> }
> 
>+static void ga_apply_command_filters(GAState *state)

Nit: inline?

>+{
>+    qmp_for_each_command(&ga_commands, ga_apply_command_filters_iter, state);
>+}
>+
> static bool ga_create_file(const char *path)
> {
>     int fd = open(path, O_CREAT | O_WRONLY, S_IWUSR | S_IRUSR);
>@@ -505,15 +524,14 @@ void ga_set_frozen(GAState *s)
>     if (ga_is_frozen(s)) {
>         return;
>     }
>-    /* disable all forbidden (for frozen state) commands */
>-    qmp_for_each_command(&ga_commands, ga_disable_not_allowed_freeze, NULL);
>     g_warning("disabling logging due to filesystem freeze");
>-    ga_disable_logging(s);
>     s->frozen = true;
>     if (!ga_create_file(s->state_filepath_isfrozen)) {
>         g_warning("unable to create %s, fsfreeze may not function properly",
>                   s->state_filepath_isfrozen);
>     }
>+    ga_apply_command_filters(s);
>+    ga_disable_logging(s);
> }
> 
> void ga_unset_frozen(GAState *s)
>@@ -545,12 +563,12 @@ void ga_unset_frozen(GAState *s)
>     }
> 
>     /* 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",
>                   s->state_filepath_isfrozen);
>     }
>+    ga_apply_command_filters(s);
> }
> 
> #ifdef CONFIG_FSFREEZE
>@@ -1082,13 +1100,6 @@ static void config_load(GAConfig *config, const char *confpath, bool required)
>                                           split_list(config->aliststr, ","));
>     }
> 
>-    if (g_key_file_has_key(keyfile, "general", "block-rpcs", 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);
>     if (gerr && (required ||
>@@ -1168,7 +1179,6 @@ static void config_parse(GAConfig *config, int argc, char **argv)
> {
>     const char *sopt = "hVvdc:m: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' },
>@@ -1264,7 +1274,6 @@ 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': {
>@@ -1274,7 +1283,6 @@ static void config_parse(GAConfig *config, int argc, char **argv)
>             }
>             config->allowedrpcs = g_list_concat(config->allowedrpcs,
>                                                 split_list(optarg, ","));
>-            allow_rpcs = true;
>             break;
>         }
> #ifdef _WIN32
>@@ -1315,12 +1323,6 @@ 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)
>@@ -1431,7 +1433,6 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
>             s->deferred_options.log_filepath = config->log_filepath;
>         }
>         ga_disable_logging(s);
>-        qmp_for_each_command(&ga_commands, ga_disable_not_allowed_freeze, NULL);
>     } else {
>         if (config->daemonize) {
>             become_daemon(config->pid_filepath);
>@@ -1455,25 +1456,6 @@ 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;
>-        s->blockedrpcs = config->blockedrpcs;
>-        do {
>-            g_debug("disabling command: %s", (char *)l->data);
>-            qmp_disable_command(&ga_commands, l->data, NULL);
>-            l = g_list_next(l);
>-        } while (l);
>-    }
>     s->command_state = ga_command_state_new();
>     ga_command_state_init(s, s->command_state);
>     ga_command_state_init_all(s->command_state);
>@@ -1499,6 +1481,8 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
>     }
> #endif
> 
>+    ga_apply_command_filters(s);
>+
>     ga_state = s;
>     return s;
> }
>-- 
>2.45.1
>
>


  reply	other threads:[~2024-07-03 10:21 UTC|newest]

Thread overview: 70+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-06-13 15:01 [PATCH v2 00/22] qga: clean up command source locations and conditionals Daniel P. Berrangé
2024-06-13 15:01 ` [PATCH v2 01/22] qga: drop blocking of guest-get-memory-block-size command Daniel P. Berrangé
2024-07-12  9:33   ` Konstantin Kostiuk
2024-06-13 15:01 ` [PATCH v2 02/22] qga: move linux vcpu command impls to commands-linux.c Daniel P. Berrangé
2024-07-03  8:45   ` Philippe Mathieu-Daudé
2024-07-12  8:30   ` Konstantin Kostiuk
2024-06-13 15:01 ` [PATCH v2 03/22] qga: move linux suspend " Daniel P. Berrangé
2024-07-03  8:45   ` Philippe Mathieu-Daudé
2024-07-12  8:29   ` Konstantin Kostiuk
2024-06-13 15:01 ` [PATCH v2 04/22] qga: move linux fs/disk " Daniel P. Berrangé
2024-07-03  8:46   ` Philippe Mathieu-Daudé
2024-07-12  8:29   ` Konstantin Kostiuk
2024-06-13 15:01 ` [PATCH v2 05/22] qga: move linux disk/cpu stats " Daniel P. Berrangé
2024-07-03  8:25   ` Philippe Mathieu-Daudé
2024-07-12  8:33   ` Konstantin Kostiuk
2024-06-13 15:43 ` [PATCH v2 06/22] qga: move linux memory block " Daniel P. Berrangé
2024-06-13 15:43   ` [PATCH v2 07/22] qga: move CONFIG_FSFREEZE/TRIM to be meson defined options Daniel P. Berrangé
2024-06-13 15:43   ` [PATCH v2 08/22] qga: conditionalize schema for commands unsupported on Windows Daniel P. Berrangé
2024-07-03  8:30     ` Philippe Mathieu-Daudé
2024-07-12  8:34     ` Konstantin Kostiuk
2024-06-13 15:43   ` [PATCH v2 09/22] qga: conditionalize schema for commands unsupported on non-Linux POSIX Daniel P. Berrangé
2024-07-03  8:31     ` Philippe Mathieu-Daudé
2024-07-12  8:35     ` Konstantin Kostiuk
2024-06-13 15:43   ` [PATCH v2 10/22] qga: conditionalize schema for commands requiring getifaddrs Daniel P. Berrangé
2024-07-03  8:32     ` Philippe Mathieu-Daudé
2024-07-12  8:35     ` Konstantin Kostiuk
2024-06-13 15:43   ` [PATCH v2 11/22] qga: conditionalize schema for commands requiring linux/win32 Daniel P. Berrangé
2024-06-13 15:43   ` [PATCH v2 12/22] qga: conditionalize schema for commands only supported on Windows Daniel P. Berrangé
2024-07-03  8:35     ` Philippe Mathieu-Daudé
2024-07-12  8:37     ` Konstantin Kostiuk
2024-06-13 15:43   ` [PATCH v2 13/22] qga: conditionalize schema for commands requiring fsfreeze Daniel P. Berrangé
2024-07-03  8:37     ` Philippe Mathieu-Daudé
2024-07-12  8:37     ` Konstantin Kostiuk
2024-06-13 15:43   ` [PATCH v2 14/22] qga: conditionalize schema for commands requiring fstrim Daniel P. Berrangé
2024-07-03  8:36     ` Philippe Mathieu-Daudé
2024-07-12  8:38     ` Konstantin Kostiuk
2024-06-13 15:43   ` [PATCH v2 15/22] qga: conditionalize schema for commands requiring libudev Daniel P. Berrangé
2024-07-03  8:37     ` Philippe Mathieu-Daudé
2024-07-12  8:40     ` Konstantin Kostiuk
2024-06-13 15:44   ` [PATCH v2 16/22] qga: conditionalize schema for commands requiring utmpx Daniel P. Berrangé
2024-07-03  8:38     ` Philippe Mathieu-Daudé
2024-07-12  8:43     ` Konstantin Kostiuk
2024-06-13 15:44   ` [PATCH v2 17/22] qga: conditionalize schema for commands not supported on other UNIX Daniel P. Berrangé
2024-07-03  8:39     ` Philippe Mathieu-Daudé
2024-07-12  8:43     ` Konstantin Kostiuk
2024-06-13 15:44   ` [PATCH v2 18/22] qga: don't disable fsfreeze commands if vss_init fails Daniel P. Berrangé
2024-07-03 10:21     ` Manos Pitsidianakis
2024-07-12 12:45       ` Daniel P. Berrangé
2024-06-13 15:44   ` [PATCH v2 19/22] qga: move declare of QGAConfig struct to top of file Daniel P. Berrangé
2024-07-03  8:40     ` Philippe Mathieu-Daudé
2024-07-12  8:44     ` Konstantin Kostiuk
2024-06-13 15:44   ` [PATCH v2 20/22] qga: remove pointless 'blockrpcs_key' variable Daniel P. Berrangé
2024-07-03  8:41     ` Philippe Mathieu-Daudé
2024-07-12  8:46     ` Konstantin Kostiuk
2024-06-13 15:44   ` [PATCH v2 21/22] qga: allow configuration file path via the cli Daniel P. Berrangé
2024-07-03  8:44     ` Philippe Mathieu-Daudé
2024-07-12  9:05     ` Konstantin Kostiuk
2024-07-12  9:18       ` Daniel P. Berrangé
2024-06-13 15:44   ` [PATCH v2 22/22] qga: centralize logic for disabling/enabling commands Daniel P. Berrangé
2024-07-03 10:01     ` Manos Pitsidianakis [this message]
2024-07-03 12:09       ` Philippe Mathieu-Daudé
2024-07-12 13:01       ` Daniel P. Berrangé
2024-07-03  8:26   ` [PATCH v2 06/22] qga: move linux memory block command impls to commands-linux.c Philippe Mathieu-Daudé
2024-07-12  8:34   ` Konstantin Kostiuk
2024-06-14  8:34 ` [PATCH v2 00/22] qga: clean up command source locations and conditionals Marc-André Lureau
2024-06-14  9:19   ` Daniel P. Berrangé
2024-07-02 18:00 ` Daniel P. Berrangé
2024-07-03  6:15   ` Marc-André Lureau
2024-07-03  8:06     ` Daniel P. Berrangé
2024-07-03  8:17       ` Marc-André Lureau

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=g1m2c.r93vk15jos2y@linaro.org \
    --to=manos.pitsidianakis@linaro.org \
    --cc=berrange@redhat.com \
    --cc=kkostiuk@redhat.com \
    --cc=marcandre.lureau@redhat.com \
    --cc=michael.roth@amd.com \
    --cc=pbonzini@redhat.com \
    --cc=philmd@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=thuth@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).