[PATCH v2 0/2] qemu_dbus: Escape path to dbus-daemon socket if needed
v2 of: $(you know which patch, the list archive is down) diff to v1: - New function to escape a string according to DBus rules is introduced (virStringEscapeDBus()) and used. Michal Prívozník (2): util: Introduce virStringEscapeDBus() qemu_dbus: Escape path to dbus-daemon socket if needed src/libvirt_private.syms | 1 + src/qemu/qemu_dbus.c | 4 ++- src/util/virstring.c | 64 ++++++++++++++++++++++++++++++++++++++++ src/util/virstring.h | 1 + tests/virstringtest.c | 43 +++++++++++++++++++++++++++ 5 files changed, 112 insertions(+), 1 deletion(-) -- 2.51.2
From: Michal Privoznik <mprivozn@redhat.com> DBus allows only some characters to be specified verbatim [1]. Everything else must be specified via '%NN' syntax where NN is hex value of the escaped character. Introduce virStringEscapeDBus() helper to handle string escaping. 1: https://gitlab.freedesktop.org/dbus/dbus/-/blob/2dee5236088bcf690ba92b743a58... Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/libvirt_private.syms | 1 + src/util/virstring.c | 64 ++++++++++++++++++++++++++++++++++++++++ src/util/virstring.h | 1 + tests/virstringtest.c | 43 +++++++++++++++++++++++++++ 4 files changed, 109 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 4e57e4a8f6..ef8ddd0330 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -3478,6 +3478,7 @@ virSkipSpacesBackwards; virSkipToDigit; virStrcpy; virStringBufferIsPrintable; +virStringEscapeDBus; virStringFilterChars; virStringFormatHex; virStringHasCaseSuffix; diff --git a/src/util/virstring.c b/src/util/virstring.c index e001d76bf1..0729002d12 100644 --- a/src/util/virstring.c +++ b/src/util/virstring.c @@ -1118,3 +1118,67 @@ virStringFormatHex(const unsigned char *buf, size_t len) return g_steal_pointer(&hex); } + + +/** + * virStringEscapeDBus: + * @str: string to escape + * + * Produces new string that's safe to pass to DBUS. Specifically, + * alphanumerical characters, digits, '-', '_', '/', '\\', '*' and '.' are + * kept. Everything else is escaped using "%NN", where NN is value of the + * character in hex. + * + * Returns: newly allocated string. Caller must free. + */ +char * +virStringEscapeDBus(const char *str) +{ + size_t len; + size_t i; + size_t j = 0; + size_t alloc = 1; + char *ret; + + if (!str) + return NULL; + + len = strlen(str); + alloc = len * 1.25; /* assume some escaping */ + ret = g_new0(char, alloc + 1); + + for (i = 0; str[i]; i++) { + const char c = str[i]; + + if ((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + (c == '-') || + (c == '_') || + (c == '/') || + (c == '\\') || + (c == '*') || + (c == '.')) { + if (j >= alloc) { + ret = g_renew(char, ret, alloc + 11); + alloc += 10; + } + + ret[j++] = c; + } else { + static const char hextable[] = "0123456789ABCDEF"; + + if (j + 3 >= alloc) { + ret = g_renew(char, ret, alloc + 11); + alloc += 10; + } + + ret[j++] = '%'; + ret[j++] = hextable[(c >> 4) & 15]; + ret[j++] = hextable[c & 15]; + } + } + + ret[j++] = '\0'; + return ret; +} diff --git a/src/util/virstring.h b/src/util/virstring.h index 8c2208ece8..aadfc37e41 100644 --- a/src/util/virstring.h +++ b/src/util/virstring.h @@ -141,3 +141,4 @@ int virStringParseVersion(unsigned long long *version, void virStringListRemoveDuplicates(char ***list); char *virStringFormatHex(const unsigned char *buf, size_t len); +char *virStringEscapeDBus(const char *str); diff --git a/tests/virstringtest.c b/tests/virstringtest.c index 0792155cc3..50b0e2cc5c 100644 --- a/tests/virstringtest.c +++ b/tests/virstringtest.c @@ -486,6 +486,29 @@ static int testFilterChars(const void *args) return 0; } + +struct testDBusData { + const char *string; + const char *expected; +}; + + +static int +testDBusEscape(const void *args) +{ + const struct testDBusData *data = args; + g_autofree char *res = virStringEscapeDBus(data->string); + + if (STRNEQ_NULLABLE(res, data->expected)) { + fprintf(stderr, "%s: returned '%s', expected '%s'\n", + __FUNCTION__, NULLSTR(res), NULLSTR(data->expected)); + return -1; + } + + return 0; +} + + static int mymain(void) { @@ -767,6 +790,26 @@ mymain(void) TEST_FILTER_CHARS(NULL, NULL, NULL); TEST_FILTER_CHARS("hello 123 hello", "helo", "hellohello"); +#define TEST_DBUS_ESCAPE(str, exp) \ + do { \ + struct testDBusData dbusData = { \ + .string = str, \ + .expected = exp, \ + }; \ + if (virTestRun("DBus escape " #str, \ + testDBusEscape, &dbusData) < 0) \ + ret = -1; \ + } while (0) + + TEST_DBUS_ESCAPE(NULL, NULL); + TEST_DBUS_ESCAPE("", ""); + TEST_DBUS_ESCAPE("-_/\\*.", "-_/\\*."); + TEST_DBUS_ESCAPE("abcdefghijklmnopqrstuvwxyz", + "abcdefghijklmnopqrstuvwxyz"); + TEST_DBUS_ESCAPE("/some/~/path/with space/-_\\*./#$", + "/some/%7E/path/with%20space/-_\\*./%23%24"); + + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- 2.51.2
From: Michal Privoznik <mprivozn@redhat.com> Inside of qemuDBusWriteConfig() the config file for dbus-daemon is written. In it is path to the socket where the daemon should listen to. But the path is derived from guest name and as such may contain characters that DBus requires escaped (e.g. a space). Use virStringEscapeDBus() to escape the path before writing it into the config file. Closes: https://gitlab.com/libvirt/libvirt/-/issues/834 Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_dbus.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_dbus.c b/src/qemu/qemu_dbus.c index 625884ad46..777facbcf4 100644 --- a/src/qemu/qemu_dbus.c +++ b/src/qemu/qemu_dbus.c @@ -25,6 +25,7 @@ #include "virtime.h" #include "virpidfile.h" #include "virutil.h" +#include "virstring.h" #define VIR_FROM_THIS VIR_FROM_NONE @@ -119,6 +120,7 @@ static int qemuDBusWriteConfig(const char *filename, const char *path, bool privileged) { g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER; + g_autofree char *escapedPath = virStringEscapeDBus(path); g_autofree char *config = NULL; virBufferAddLit(&buf, "<!DOCTYPE busconfig PUBLIC \"-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN\"\n"); @@ -127,7 +129,7 @@ qemuDBusWriteConfig(const char *filename, const char *path, bool privileged) virBufferAdjustIndent(&buf, 2); virBufferAddLit(&buf, "<type>org.libvirt.qemu</type>\n"); - virBufferAsprintf(&buf, "<listen>unix:path=%s</listen>\n", path); + virBufferAsprintf(&buf, "<listen>unix:path=%s</listen>\n", escapedPath); virBufferAddLit(&buf, "<auth>EXTERNAL</auth>\n"); virBufferAddLit(&buf, "<policy context='default'>\n"); -- 2.51.2
participants (1)
-
Michal Privoznik