crobinso pushed to libvirt (master). "Fix LXC domain startup (bz #1210397) (..more)"

notifications at fedoraproject.org notifications at fedoraproject.org
Wed Apr 15 18:40:50 UTC 2015


>From c5b0b3ef9d4eb1ae07ef2ee83d8bfd8f7b4d4eac Mon Sep 17 00:00:00 2001
From: Cole Robinson <crobinso at redhat.com>
Date: Wed, 15 Apr 2015 14:40:41 -0400
Subject: Fix LXC domain startup (bz #1210397) Fix race starting multiple
 session daemons (bz #1200149) Fix change-media success messages Strip invalid
 control codes from XML (bz #1066564, bz #1184131)


diff --git a/0001-lxc-create-the-required-directories-upon-driver-star.patch b/0001-lxc-create-the-required-directories-upon-driver-star.patch
new file mode 100644
index 0000000..1e9df00
--- /dev/null
+++ b/0001-lxc-create-the-required-directories-upon-driver-star.patch
@@ -0,0 +1,35 @@
+From: Lubomir Rintel <lkundrak at v3.sk>
+Date: Wed, 8 Apr 2015 19:16:52 +0200
+Subject: [PATCH] lxc: create the required directories upon driver start
+
+/var/run may reside on a tmpfs and we fail to create the PID file if
+/var/run/lxc does not exist.
+
+Since commit 0a8addc1, the lxc driver's state directory isn't
+automatically created before starting a domain. Now, the lxc driver
+makes sure the state directory exists when it initializes.
+
+Signed-off-by: Lubomir Rintel <lkundrak at v3.sk>
+(cherry picked from commit da33a1ac1f6c0ae2ebe72bc385bbc7c407026956)
+---
+ src/lxc/lxc_driver.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
+index 245000d..8dfa686 100644
+--- a/src/lxc/lxc_driver.c
++++ b/src/lxc/lxc_driver.c
+@@ -1648,6 +1648,13 @@ static int lxcStateInitialize(bool privileged,
+     if (!(caps = virLXCDriverGetCapabilities(lxc_driver, false)))
+         goto cleanup;
+ 
++    if (virFileMakePath(cfg->stateDir) < 0) {
++        virReportSystemError(errno,
++                             _("Failed to mkdir %s"),
++                             cfg->stateDir);
++        goto cleanup;
++    }
++
+     /* Get all the running persistent or transient configs first */
+     if (virDomainObjListLoadAllConfigs(lxc_driver->domains,
+                                        cfg->stateDir,
diff --git a/0002-virNetSocketNewConnectUNIX-Use-flocks-when-spawning-.patch b/0002-virNetSocketNewConnectUNIX-Use-flocks-when-spawning-.patch
new file mode 100644
index 0000000..70cce7b
--- /dev/null
+++ b/0002-virNetSocketNewConnectUNIX-Use-flocks-when-spawning-.patch
@@ -0,0 +1,267 @@
+From: Michal Privoznik <mprivozn at redhat.com>
+Date: Thu, 2 Apr 2015 14:41:17 +0200
+Subject: [PATCH] virNetSocketNewConnectUNIX: Use flocks when spawning a daemon
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1200149
+
+Even though we have a mutex mechanism so that two clients don't spawn
+two daemons, it's not strong enough. It can happen that while one
+client is spawning the daemon, the other one fails to connect.
+Basically two possible errors can happen:
+
+  error: Failed to connect socket to '/home/mprivozn/.cache/libvirt/libvirt-sock': Connection refused
+
+or:
+
+  error: Failed to connect socket to '/home/mprivozn/.cache/libvirt/libvirt-sock': No such file or directory
+
+The problem in both cases is, the daemon is only starting up, while we
+are trying to connect (and fail). We should postpone the connecting
+phase until the daemon is started (by the other thread that is
+spawning it). In order to do that, create a file lock 'libvirt-lock'
+in the directory where session daemon would create its socket. So even
+when called from multiple processes, spawning a daemon will serialize
+on the file lock. So only the first to come will spawn the daemon.
+
+Tested-by: Richard W. M. Jones <rjones at redhat.com>
+Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
+(cherry picked from commit be78814ae07f092d9c4e71fd82dd1947aba2f029)
+---
+ src/rpc/virnetsocket.c | 164 +++++++++++++++++--------------------------------
+ 1 file changed, 55 insertions(+), 109 deletions(-)
+
+diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c
+index 6b019cc..b824285 100644
+--- a/src/rpc/virnetsocket.c
++++ b/src/rpc/virnetsocket.c
+@@ -123,7 +123,7 @@ VIR_ONCE_GLOBAL_INIT(virNetSocket)
+ 
+ 
+ #ifndef WIN32
+-static int virNetSocketForkDaemon(const char *binary, int passfd)
++static int virNetSocketForkDaemon(const char *binary)
+ {
+     int ret;
+     virCommandPtr cmd = virCommandNewArgList(binary,
+@@ -136,10 +136,6 @@ static int virNetSocketForkDaemon(const char *binary, int passfd)
+     virCommandAddEnvPassBlockSUID(cmd, "XDG_RUNTIME_DIR", NULL);
+     virCommandClearCaps(cmd);
+     virCommandDaemonize(cmd);
+-    if (passfd) {
+-        virCommandPassFD(cmd, passfd, VIR_COMMAND_PASS_FD_CLOSE_PARENT);
+-        virCommandPassListenFDs(cmd);
+-    }
+     ret = virCommandRun(cmd, NULL);
+     virCommandFree(cmd);
+     return ret;
+@@ -543,45 +539,26 @@ int virNetSocketNewConnectUNIX(const char *path,
+                                const char *binary,
+                                virNetSocketPtr *retsock)
+ {
+-    char *binname = NULL;
+-    char *pidpath = NULL;
+-    int fd, passfd = -1;
+-    int pidfd = -1;
++    char *lockpath = NULL;
++    int lockfd = -1;
++    int fd = -1;
++    int retries = 100;
+     virSocketAddr localAddr;
+     virSocketAddr remoteAddr;
++    char *rundir = NULL;
+ 
+     memset(&localAddr, 0, sizeof(localAddr));
+     memset(&remoteAddr, 0, sizeof(remoteAddr));
+ 
+     remoteAddr.len = sizeof(remoteAddr.data.un);
+ 
+-    if (spawnDaemon && !binary) {
+-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+-                       _("Auto-spawn of daemon requested, but no binary specified"));
+-        return -1;
+-    }
+-
+-    if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
+-        virReportSystemError(errno, "%s", _("Failed to create socket"));
+-        goto error;
+-    }
+-
+-    remoteAddr.data.un.sun_family = AF_UNIX;
+-    if (virStrcpyStatic(remoteAddr.data.un.sun_path, path) == NULL) {
+-        virReportSystemError(ENOMEM, _("Path %s too long for unix socket"), path);
+-        goto error;
+-    }
+-    if (remoteAddr.data.un.sun_path[0] == '@')
+-        remoteAddr.data.un.sun_path[0] = '\0';
+-
+- retry:
+-    if (connect(fd, &remoteAddr.data.sa, remoteAddr.len) < 0) {
+-        int status = 0;
+-        pid_t pid = 0;
++    if (spawnDaemon) {
++        const char *binname;
+ 
+-        if (!spawnDaemon) {
+-            virReportSystemError(errno, _("Failed to connect socket to '%s'"),
+-                                 path);
++        if (spawnDaemon && !binary) {
++            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
++                           _("Auto-spawn of daemon requested, "
++                             "but no binary specified"));
+             goto error;
+         }
+ 
+@@ -592,90 +569,63 @@ int virNetSocketNewConnectUNIX(const char *path,
+             goto error;
+         }
+ 
+-        if (virPidFileConstructPath(false, NULL, binname, &pidpath) < 0)
++        if (!(rundir = virGetUserRuntimeDirectory()))
+             goto error;
+ 
+-        pidfd = virPidFileAcquirePath(pidpath, false, getpid());
+-        if (pidfd < 0) {
+-            /*
+-             * This can happen in a very rare case of two clients spawning two
+-             * daemons at the same time, and the error in the logs that gets
+-             * reset here can be a clue to some future debugging.
+-             */
+-            virResetLastError();
+-            spawnDaemon = false;
+-            goto retry;
+-        }
+-
+-        if ((passfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
+-            virReportSystemError(errno, "%s", _("Failed to create socket"));
++        if (virFileMakePathWithMode(rundir, 0700) < 0) {
++            virReportSystemError(errno,
++                                 _("Cannot create user runtime directory '%s'"),
++                                 rundir);
+             goto error;
+         }
+ 
+-        /*
+-         * We already even acquired the pidfile, so no one else should be using
+-         * @path right now.  So we're OK to unlink it and paying attention to
+-         * the return value makes no real sense here.  Only if it's not an
+-         * abstract socket, of course.
+-         */
+-        if (path[0] != '@')
+-            unlink(path);
+-
+-        /*
+-         * We have to fork() here, because umask() is set per-process, chmod()
+-         * is racy and fchmod() has undefined behaviour on sockets according to
+-         * POSIX, so it doesn't work outside Linux.
+-         */
+-        if ((pid = virFork()) < 0)
++        if (virAsprintf(&lockpath, "%s/%s.lock", rundir, binname) < 0)
+             goto error;
+ 
+-        if (pid == 0) {
+-            umask(0077);
+-            if (bind(passfd, &remoteAddr.data.sa, remoteAddr.len) < 0)
+-                _exit(EXIT_FAILURE);
+-
+-            _exit(EXIT_SUCCESS);
+-        }
+-
+-        if (virProcessWait(pid, &status, false) < 0)
++        if ((lockfd = open(lockpath, O_RDWR | O_CREAT, 0600)) < 0 ||
++            virSetCloseExec(lockfd) < 0) {
++            virReportSystemError(errno, _("Unable to create lock '%s'"), lockpath);
+             goto error;
+-
+-        if (status != EXIT_SUCCESS) {
+-            /*
+-             * OK, so the child failed to bind() the socket.  This may mean that
+-             * another daemon was starting at the same time and succeeded with
+-             * its bind() (even though it should not happen because we using a
+-             * pidfile for the race).  So we'll try connecting again, but this
+-             * time without spawning the daemon.
+-             */
+-            spawnDaemon = false;
+-            virPidFileDeletePath(pidpath);
+-            VIR_FORCE_CLOSE(pidfd);
+-            VIR_FORCE_CLOSE(passfd);
+-            goto retry;
+         }
+ 
+-        if (listen(passfd, 0) < 0) {
+-            virReportSystemError(errno, "%s",
+-                                 _("Failed to listen on socket that's about "
+-                                   "to be passed to the daemon"));
++        if (virFileLock(lockfd, false, 0, 1, true) < 0) {
++            virReportSystemError(errno, _("Unable to lock '%s'"), lockpath);
+             goto error;
+         }
++    }
++
++    if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
++        virReportSystemError(errno, "%s", _("Failed to create socket"));
++        goto error;
++    }
+ 
+-        if (connect(fd, &remoteAddr.data.sa, remoteAddr.len) < 0) {
++    remoteAddr.data.un.sun_family = AF_UNIX;
++    if (virStrcpyStatic(remoteAddr.data.un.sun_path, path) == NULL) {
++        virReportSystemError(ENOMEM, _("Path %s too long for unix socket"), path);
++        goto error;
++    }
++    if (remoteAddr.data.un.sun_path[0] == '@')
++        remoteAddr.data.un.sun_path[0] = '\0';
++
++    while (retries &&
++           connect(fd, &remoteAddr.data.sa, remoteAddr.len) < 0) {
++        if (!(spawnDaemon && errno == ENOENT)) {
+             virReportSystemError(errno, _("Failed to connect socket to '%s'"),
+                                  path);
+             goto error;
+         }
+ 
+-        /*
+-         * Do we need to eliminate the super-rare race here any more?  It would
+-         * need incorporating the following VIR_FORCE_CLOSE() into a
+-         * virCommandHook inside a virNetSocketForkDaemon().
+-         */
+-        VIR_FORCE_CLOSE(pidfd);
+-        if (virNetSocketForkDaemon(binary, passfd) < 0)
++        if (virNetSocketForkDaemon(binary) < 0)
+             goto error;
++
++        retries--;
++        usleep(5000);
++    }
++
++    if (lockfd) {
++        unlink(lockpath);
++        VIR_FORCE_CLOSE(lockfd);
++        VIR_FREE(lockpath);
+     }
+ 
+     localAddr.len = sizeof(localAddr.data);
+@@ -687,19 +637,15 @@ int virNetSocketNewConnectUNIX(const char *path,
+     if (!(*retsock = virNetSocketNew(&localAddr, &remoteAddr, true, fd, -1, 0)))
+         goto error;
+ 
+-    VIR_FREE(pidpath);
+-
+     return 0;
+ 
+  error:
+-    if (pidfd >= 0)
+-        virPidFileDeletePath(pidpath);
+-    VIR_FREE(pidpath);
++    if (lockfd)
++        unlink(lockpath);
++    VIR_FREE(lockpath);
++    VIR_FREE(rundir);
+     VIR_FORCE_CLOSE(fd);
+-    VIR_FORCE_CLOSE(passfd);
+-    VIR_FORCE_CLOSE(pidfd);
+-    if (spawnDaemon)
+-        unlink(path);
++    VIR_FORCE_CLOSE(lockfd);
+     return -1;
+ }
+ #else
diff --git a/0003-virsh-Improve-change-media-success-message.patch b/0003-virsh-Improve-change-media-success-message.patch
new file mode 100644
index 0000000..8791b5e
--- /dev/null
+++ b/0003-virsh-Improve-change-media-success-message.patch
@@ -0,0 +1,58 @@
+From: Cole Robinson <crobinso at redhat.com>
+Date: Mon, 6 Apr 2015 13:59:46 -0400
+Subject: [PATCH] virsh: Improve change-media success message
+
+$ sudo virsh change-media f19 hdc /mnt/data/devel/media/Fedora-16-x86_64-Live-KDE.iso
+succeeded to complete action update on media
+
+Change the message to:
+
+  Successfully {inserted,ejected,changed} media.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=967946
+(cherry picked from commit e3aa4c91c8b54cdfb1c312a142fd9fb79daec65a)
+---
+ tools/virsh-domain.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
+index 9bbb964..a735649 100644
+--- a/tools/virsh-domain.c
++++ b/tools/virsh-domain.c
+@@ -12295,6 +12295,7 @@ cmdChangeMedia(vshControl *ctl, const vshCmd *cmd)
+     bool ret = false;
+     vshUpdateDiskXMLType update_type;
+     const char *action = NULL;
++    const char *success_msg = NULL;
+     bool config = vshCommandOptBool(cmd, "config");
+     bool live = vshCommandOptBool(cmd, "live");
+     bool current = vshCommandOptBool(cmd, "current");
+@@ -12314,16 +12315,19 @@ cmdChangeMedia(vshControl *ctl, const vshCmd *cmd)
+     if (eject) {
+         update_type = VSH_UPDATE_DISK_XML_EJECT;
+         action = "eject";
++        success_msg = _("Successfully ejected media.");
+     }
+ 
+     if (insert) {
+         update_type = VSH_UPDATE_DISK_XML_INSERT;
+         action = "insert";
++        success_msg = _("Successfully inserted media.");
+     }
+ 
+     if (update || (!eject && !insert)) {
+         update_type = VSH_UPDATE_DISK_XML_UPDATE;
+         action = "update";
++        success_msg = _("Successfully updated media.");
+     }
+ 
+     VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
+@@ -12367,7 +12371,7 @@ cmdChangeMedia(vshControl *ctl, const vshCmd *cmd)
+             goto cleanup;
+         }
+ 
+-        vshPrint(ctl, _("succeeded to complete action %s on media\n"), action);
++        vshPrint(ctl, "%s", success_msg);
+     }
+ 
+     ret = true;
diff --git a/0004-tests-rename-testStripIPv6BracketsData-to-testStripD.patch b/0004-tests-rename-testStripIPv6BracketsData-to-testStripD.patch
new file mode 100644
index 0000000..e4e2ee0
--- /dev/null
+++ b/0004-tests-rename-testStripIPv6BracketsData-to-testStripD.patch
@@ -0,0 +1,41 @@
+From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko at redhat.com>
+Date: Tue, 14 Apr 2015 12:06:44 +0200
+Subject: [PATCH] tests: rename testStripIPv6BracketsData to testStripData
+
+For reuse with other Strip* functions.
+
+(cherry picked from commit e892842dfd3c7bad8fbfbfcf0501d01804e9e7c3)
+---
+ tests/virstringtest.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/tests/virstringtest.c b/tests/virstringtest.c
+index a0bfd61..9d0b438 100644
+--- a/tests/virstringtest.c
++++ b/tests/virstringtest.c
+@@ -522,14 +522,14 @@ testVirStringFreeListCount(const void *opaque ATTRIBUTE_UNUSED)
+ }
+ 
+ 
+-struct testStripIPv6BracketsData {
++struct testStripData {
+     const char *string;
+     const char *result;
+ };
+ 
+ static int testStripIPv6Brackets(const void *args)
+ {
+-    const struct testStripIPv6BracketsData *data = args;
++    const struct testStripData *data = args;
+     int ret = -1;
+     char *res = NULL;
+ 
+@@ -766,7 +766,7 @@ mymain(void)
+ 
+ #define TEST_STRIP_IPV6_BRACKETS(str, res)                              \
+     do {                                                                \
+-        struct testStripIPv6BracketsData stripData = {                  \
++        struct testStripData stripData = {                              \
+             .string = str,                                              \
+             .result = res,                                              \
+         };                                                              \
diff --git a/0005-Add-functions-dealing-with-control-characters-in-str.patch b/0005-Add-functions-dealing-with-control-characters-in-str.patch
new file mode 100644
index 0000000..dca9932
--- /dev/null
+++ b/0005-Add-functions-dealing-with-control-characters-in-str.patch
@@ -0,0 +1,155 @@
+From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko at redhat.com>
+Date: Tue, 14 Apr 2015 12:30:16 +0200
+Subject: [PATCH] Add functions dealing with control characters in strings
+
+Add virStringHasControlChars that checks if the string has
+any control characters other than \t\r\n,
+and virStringStripControlChars that removes them in-place.
+
+(cherry picked from commit 2a530a3e50d9314950cff0a5790c81910b0750a9)
+---
+ src/libvirt_private.syms |  2 ++
+ src/util/virstring.c     | 42 ++++++++++++++++++++++++++++++++++++++++++
+ src/util/virstring.h     |  2 ++
+ tests/virstringtest.c    | 39 +++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 85 insertions(+)
+
+diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
+index 5716ece..21b6aa5 100644
+--- a/src/libvirt_private.syms
++++ b/src/libvirt_private.syms
+@@ -2121,6 +2121,7 @@ virStrdup;
+ virStringArrayHasString;
+ virStringFreeList;
+ virStringFreeListCount;
++virStringHasControlChars;
+ virStringIsEmpty;
+ virStringJoin;
+ virStringListLength;
+@@ -2130,6 +2131,7 @@ virStringSortCompare;
+ virStringSortRevCompare;
+ virStringSplit;
+ virStringSplitCount;
++virStringStripControlChars;
+ virStringStripIPv6Brackets;
+ virStrncpy;
+ virStrndup;
+diff --git a/src/util/virstring.c b/src/util/virstring.c
+index 3dad9dd..1cd4987 100644
+--- a/src/util/virstring.c
++++ b/src/util/virstring.c
+@@ -968,3 +968,45 @@ virStringStripIPv6Brackets(char *str)
+         str[len - 2] = '\0';
+     }
+ }
++
++
++static const char control_chars[] =
++    "\x01\x02\x03\x04\x05\x06\x07"
++    "\x08" /* \t \n */ "\x0B\x0C" /* \r */ "\x0E\x0F"
++    "\x10\x11\x12\x13\x14\x15\x16\x17"
++    "\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
++
++bool
++virStringHasControlChars(const char *str)
++{
++    if (!str)
++        return false;
++
++    return str[strcspn(str, control_chars)] != '\0';
++}
++
++
++/**
++ * virStringStripControlChars:
++ * @str: the string to strip
++ *
++ * Modify the string in-place to remove the control characters
++ * in the interval: [0x01, 0x20)
++ */
++void
++virStringStripControlChars(char *str)
++{
++    size_t len, i, j;
++
++    if (!str)
++        return;
++
++    len = strlen(str);
++    for (i = 0, j = 0; i < len; i++) {
++        if (index(control_chars, str[i]))
++            continue;
++
++        str[j++] = str[i];
++    }
++    str[j] = '\0';
++}
+diff --git a/src/util/virstring.h b/src/util/virstring.h
+index 2ec60fa..e6dcb32 100644
+--- a/src/util/virstring.h
++++ b/src/util/virstring.h
+@@ -271,5 +271,7 @@ char *virStringReplace(const char *haystack,
+     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+ 
+ void virStringStripIPv6Brackets(char *str);
++bool virStringHasControlChars(const char *str);
++void virStringStripControlChars(char *str);
+ 
+ #endif /* __VIR_STRING_H__ */
+diff --git a/tests/virstringtest.c b/tests/virstringtest.c
+index 9d0b438..38d0126 100644
+--- a/tests/virstringtest.c
++++ b/tests/virstringtest.c
+@@ -551,6 +551,29 @@ static int testStripIPv6Brackets(const void *args)
+     return ret;
+ }
+ 
++static int testStripControlChars(const void *args)
++{
++    const struct testStripData *data = args;
++    int ret = -1;
++    char *res = NULL;
++
++    if (VIR_STRDUP(res, data->string) < 0)
++        goto cleanup;
++
++    virStringStripControlChars(res);
++
++    if (STRNEQ_NULLABLE(res, data->result)) {
++        fprintf(stderr, "Returned '%s', expected '%s'\n",
++                NULLSTR(res), NULLSTR(data->result));
++        goto cleanup;
++    }
++
++    ret = 0;
++
++ cleanup:
++    VIR_FREE(res);
++    return ret;
++}
+ 
+ static int
+ mymain(void)
+@@ -783,6 +806,22 @@ mymain(void)
+     TEST_STRIP_IPV6_BRACKETS(":hello]", ":hello]");
+     TEST_STRIP_IPV6_BRACKETS(":[]:", ":[]:");
+ 
++#define TEST_STRIP_CONTROL_CHARS(str, res)                              \
++    do {                                                                \
++        struct testStripData stripData = {                              \
++            .string = str,                                              \
++            .result = res,                                              \
++        };                                                              \
++        if (virtTestRun("Strip control chars from " #str,               \
++                        testStripControlChars, &stripData) < 0)         \
++            ret = -1;                                                   \
++    } while (0)
++
++    TEST_STRIP_CONTROL_CHARS(NULL, NULL);
++    TEST_STRIP_CONTROL_CHARS("\nhello \r hello\t", "\nhello \r hello\t");
++    TEST_STRIP_CONTROL_CHARS("\x01H\x02" "E\x03L\x04L\x05O", "HELLO");
++    TEST_STRIP_CONTROL_CHARS("\x01\x02\x03\x04HELL\x05O", "HELLO");
++    TEST_STRIP_CONTROL_CHARS("\nhello \x01\x07hello\t", "\nhello hello\t");
+     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+ }
+ 
diff --git a/0006-Strip-control-characters-from-sysfs-attributes.patch b/0006-Strip-control-characters-from-sysfs-attributes.patch
new file mode 100644
index 0000000..9c14e89
--- /dev/null
+++ b/0006-Strip-control-characters-from-sysfs-attributes.patch
@@ -0,0 +1,36 @@
+From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko at redhat.com>
+Date: Tue, 14 Apr 2015 12:30:34 +0200
+Subject: [PATCH] Strip control characters from sysfs attributes
+
+Including them in the XML makes them unparsable.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184131
+(cherry picked from commit 557107500b22d4a5ba7d1b09f5f516512dfca67b)
+---
+ src/node_device/node_device_udev.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c
+index 8c39e5f..0d691e0 100644
+--- a/src/node_device/node_device_udev.c
++++ b/src/node_device/node_device_udev.c
+@@ -194,7 +194,9 @@ static int udevGetUintProperty(struct udev_device *udev_device,
+ 
+ 
+ /* This function allocates memory from the heap for the property
+- * value.  That memory must be later freed by some other code. */
++ * value.  That memory must be later freed by some other code.
++ * Any control characters that cannot be printed in the XML are stripped
++ * from the string */
+ static int udevGetDeviceSysfsAttr(struct udev_device *udev_device,
+                                   const char *attr_name,
+                                   char **attr_value)
+@@ -239,6 +241,8 @@ static int udevGetStringSysfsAttr(struct udev_device *udev_device,
+ 
+     ret = udevGetDeviceSysfsAttr(udev_device, attr_name, &tmp);
+ 
++    virStringStripControlChars(tmp);
++
+     if (tmp != NULL && (STREQ(tmp, ""))) {
+         VIR_FREE(tmp);
+         tmp = NULL;
diff --git a/0007-Ignore-storage-volumes-with-control-codes-in-their-n.patch b/0007-Ignore-storage-volumes-with-control-codes-in-their-n.patch
new file mode 100644
index 0000000..8a067b4
--- /dev/null
+++ b/0007-Ignore-storage-volumes-with-control-codes-in-their-n.patch
@@ -0,0 +1,29 @@
+From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko at redhat.com>
+Date: Tue, 14 Apr 2015 12:30:55 +0200
+Subject: [PATCH] Ignore storage volumes with control codes in their names
+
+To prevent generating invalid XML.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1066564
+(cherry picked from commit 60db2bc80fb5048b227c77c5138fe0e2c97e9c14)
+---
+ src/storage/storage_backend_fs.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
+index 35385db..4561ee0 100644
+--- a/src/storage/storage_backend_fs.c
++++ b/src/storage/storage_backend_fs.c
+@@ -861,6 +861,12 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED,
+     while ((direrr = virDirRead(dir, &ent, pool->def->target.path)) > 0) {
+         int ret;
+ 
++        if (virStringHasControlChars(ent->d_name)) {
++            VIR_WARN("Ignoring file with control characters under '%s'",
++                     pool->def->target.path);
++            continue;
++        }
++
+         if (VIR_ALLOC(vol) < 0)
+             goto error;
+ 
diff --git a/0008-Strip-control-codes-in-virBufferEscapeString.patch b/0008-Strip-control-codes-in-virBufferEscapeString.patch
new file mode 100644
index 0000000..845f1c4
--- /dev/null
+++ b/0008-Strip-control-codes-in-virBufferEscapeString.patch
@@ -0,0 +1,133 @@
+From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko at redhat.com>
+Date: Mon, 30 Mar 2015 12:41:40 +0200
+Subject: [PATCH] Strip control codes in virBufferEscapeString
+
+These cannot be represented in XML.
+
+We have been stripping them, but only if the string had
+characters that needed escaping: <>"'&
+
+Extend the strcspn check to include control codes, and strip
+them even if we don't do any escaping.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184131
+https://bugzilla.redhat.com/show_bug.cgi?id=1066564
+(cherry picked from commit aeb5262e4397528d582682471cb8075141189465)
+---
+ src/util/virbuffer.c | 14 +++++++++++---
+ tests/virbuftest.c   | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 60 insertions(+), 3 deletions(-)
+
+diff --git a/src/util/virbuffer.c b/src/util/virbuffer.c
+index 706dbfa..3d13c90 100644
+--- a/src/util/virbuffer.c
++++ b/src/util/virbuffer.c
+@@ -438,6 +438,13 @@ virBufferEscapeString(virBufferPtr buf, const char *format, const char *str)
+     int len;
+     char *escaped, *out;
+     const char *cur;
++    const char forbidden_characters[] = {
++        0x01,   0x02,   0x03,   0x04,   0x05,   0x06,   0x07,   0x08,
++        /*\t*/  /*\n*/  0x0B,   0x0C,   /*\r*/  0x0E,   0x0F,   0x10,
++        0x11,   0x12,   0x13,   0x14,   0x15,   0x16,   0x17,   0x18,
++        0x19,   '"',    '&',    '\'',   '<',    '>',
++        '\0'
++    };
+ 
+     if ((format == NULL) || (buf == NULL) || (str == NULL))
+         return;
+@@ -446,7 +453,7 @@ virBufferEscapeString(virBufferPtr buf, const char *format, const char *str)
+         return;
+ 
+     len = strlen(str);
+-    if (strcspn(str, "<>&'\"") == len) {
++    if (strcspn(str, forbidden_characters) == len) {
+         virBufferAsprintf(buf, format, str);
+         return;
+     }
+@@ -490,8 +497,7 @@ virBufferEscapeString(virBufferPtr buf, const char *format, const char *str)
+             *out++ = 'o';
+             *out++ = 's';
+             *out++ = ';';
+-        } else if (((unsigned char)*cur >= 0x20) || (*cur == '\n') || (*cur == '\t') ||
+-                   (*cur == '\r')) {
++        } else if (!strchr(forbidden_characters, *cur)) {
+             /*
+              * default case, just copy !
+              * Note that character over 0x80 are likely to give problem
+@@ -499,6 +505,8 @@ virBufferEscapeString(virBufferPtr buf, const char *format, const char *str)
+              * it's hard to handle properly we have to assume it's UTF-8 too
+              */
+             *out++ = *cur;
++        } else {
++            /* silently ignore control characters */
+         }
+         cur++;
+     }
+diff --git a/tests/virbuftest.c b/tests/virbuftest.c
+index 21cb18b..10398d5 100644
+--- a/tests/virbuftest.c
++++ b/tests/virbuftest.c
+@@ -349,6 +349,39 @@ testBufAddStr(const void *opaque ATTRIBUTE_UNUSED)
+ 
+ 
+ static int
++testBufEscapeStr(const void *opaque ATTRIBUTE_UNUSED)
++{
++    const struct testBufAddStrData *data = opaque;
++    virBuffer buf = VIR_BUFFER_INITIALIZER;
++    char *actual;
++    int ret = -1;
++
++    virBufferAddLit(&buf, "<c>\n");
++    virBufferAdjustIndent(&buf, 2);
++    virBufferEscapeString(&buf, "<el>%s</el>\n", data->data);
++    virBufferAdjustIndent(&buf, -2);
++    virBufferAddLit(&buf, "</c>");
++
++    if (!(actual = virBufferContentAndReset(&buf))) {
++        TEST_ERROR("buf is empty");
++        goto cleanup;
++    }
++
++    if (STRNEQ_NULLABLE(actual, data->expect)) {
++        TEST_ERROR("testBufEscapeStr(): Strings don't match:\n");
++        virtTestDifference(stderr, data->expect, actual);
++        goto cleanup;
++    }
++
++    ret = 0;
++
++ cleanup:
++    VIR_FREE(actual);
++    return ret;
++}
++
++
++static int
+ mymain(void)
+ {
+     int ret = 0;
+@@ -379,6 +412,22 @@ mymain(void)
+     DO_TEST_ADD_STR("<a/>\n", "<c>\n  <a/>\n</c>");
+     DO_TEST_ADD_STR("<b>\n  <a/>\n</b>\n", "<c>\n  <b>\n    <a/>\n  </b>\n</c>");
+ 
++#define DO_TEST_ESCAPE(data, expect)                                   \
++    do {                                                               \
++        struct testBufAddStrData info = { data, expect };              \
++        if (virtTestRun("Buf: EscapeStr", testBufEscapeStr, &info) < 0)   \
++            ret = -1;                                                  \
++    } while (0)
++
++    DO_TEST_ESCAPE("<td></td><td></td>",
++                   "<c>\n  <el>&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;</el>\n</c>");
++    DO_TEST_ESCAPE("\007\"&&\"\x15",
++                   "<c>\n  <el>&quot;&amp;&amp;&quot;</el>\n</c>");
++    DO_TEST_ESCAPE(",,'..',,",
++                   "<c>\n  <el>,,&apos;..&apos;,,</el>\n</c>");
++    DO_TEST_ESCAPE("\x01\x01\x02\x03\x05\x08",
++                   "<c>\n  <el></el>\n</c>");
++
+     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+ }
+ 
diff --git a/libvirt.spec b/libvirt.spec
index 8617b8d..e17ce05 100644
--- a/libvirt.spec
+++ b/libvirt.spec
@@ -372,7 +372,7 @@
 Summary: Library providing a simple virtualization API
 Name: libvirt
 Version: 1.2.14
-Release: 1%{?dist}%{?extra_release}
+Release: 2%{?dist}%{?extra_release}
 License: LGPLv2+
 Group: Development/Libraries
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
@@ -383,6 +383,19 @@ URL: http://libvirt.org/
 %endif
 Source: http://libvirt.org/sources/%{?mainturl}libvirt-%{version}.tar.gz
 
+# Fix LXC domain startup (bz #1210397)
+Patch0001: 0001-lxc-create-the-required-directories-upon-driver-star.patch
+# Fix race starting multiple session daemons (bz #1200149)
+Patch0002: 0002-virNetSocketNewConnectUNIX-Use-flocks-when-spawning-.patch
+# Fix change-media success messages
+Patch0003: 0003-virsh-Improve-change-media-success-message.patch
+# Strip invalid control codes from XML (bz #1066564, bz #1184131)
+Patch0004: 0004-tests-rename-testStripIPv6BracketsData-to-testStripD.patch
+Patch0005: 0005-Add-functions-dealing-with-control-characters-in-str.patch
+Patch0006: 0006-Strip-control-characters-from-sysfs-attributes.patch
+Patch0007: 0007-Ignore-storage-volumes-with-control-codes-in-their-n.patch
+Patch0008: 0008-Strip-control-codes-in-virBufferEscapeString.patch
+
 %if %{with_libvirtd}
 Requires: libvirt-daemon = %{version}-%{release}
     %if %{with_network}
@@ -2291,6 +2304,12 @@ exit 0
 %doc examples/systemtap
 
 %changelog
+* Wed Apr 15 2015 Cole Robinson <crobinso at redhat.com> - 1.2.14-2
+- Fix LXC domain startup (bz #1210397)
+- Fix race starting multiple session daemons (bz #1200149)
+- Fix change-media success messages
+- Strip invalid control codes from XML (bz #1066564, bz #1184131)
+
 * Thu Apr 02 2015 Cole Robinson <crobinso at redhat.com> - 1.2.14-1
 - Rebased to version 1.2.14
 
-- 
cgit v0.10.2


	http://pkgs.fedoraproject.org/cgit/libvirt.git/commit/?h=master&id=c5b0b3ef9d4eb1ae07ef2ee83d8bfd8f7b4d4eac


More information about the scm-commits mailing list