|
|
3cf992 |
From 6bf725c07c25b56937c494b6c7e83e6ca27ec54c Mon Sep 17 00:00:00 2001
|
|
|
3cf992 |
Message-Id: <6bf725c07c25b56937c494b6c7e83e6ca27ec54c@dist-git>
|
|
|
3cf992 |
From: Michal Privoznik <mprivozn@redhat.com>
|
|
|
3cf992 |
Date: Mon, 8 Mar 2021 12:57:31 +0100
|
|
|
3cf992 |
Subject: [PATCH] virdevmapper: Don't use libdevmapper to obtain dependencies
|
|
|
3cf992 |
MIME-Version: 1.0
|
|
|
3cf992 |
Content-Type: text/plain; charset=UTF-8
|
|
|
3cf992 |
Content-Transfer-Encoding: 8bit
|
|
|
3cf992 |
|
|
|
3cf992 |
CVE-2020-14339
|
|
|
3cf992 |
|
|
|
3cf992 |
When building domain's private /dev in a namespace, libdevmapper
|
|
|
3cf992 |
is consulted for getting full dependency tree of domain's disks.
|
|
|
3cf992 |
The reason is that for a multipath devices all dependent devices
|
|
|
3cf992 |
must be created in the namespace and allowed in CGroups.
|
|
|
3cf992 |
|
|
|
3cf992 |
However, this approach is very fragile as building of namespace
|
|
|
3cf992 |
happens in the forked off child process, after mass close of FDs
|
|
|
3cf992 |
and just before dropping privileges and execing QEMU. And it so
|
|
|
3cf992 |
happens that when calling libdevmapper APIs, one of them opens
|
|
|
3cf992 |
/dev/mapper/control and saves the FD into a global variable. The
|
|
|
3cf992 |
FD is kept open until the lib is unlinked or dm_lib_release() is
|
|
|
3cf992 |
called explicitly. We are doing neither.
|
|
|
3cf992 |
|
|
|
3cf992 |
However, the virDevMapperGetTargets() function is called also
|
|
|
3cf992 |
from libvirtd (when setting up CGroups) and thus has to be thread
|
|
|
3cf992 |
safe. Unfortunately, libdevmapper APIs are not thread safe (nor
|
|
|
3cf992 |
async signal safe) and thus we can't use them. Reimplement what
|
|
|
3cf992 |
libdevmapper would do using plain C (ioctl()-s, /proc/devices
|
|
|
3cf992 |
parsing, /dev/mapper dirwalking, and so on).
|
|
|
3cf992 |
|
|
|
3cf992 |
Fixes: a30078cb832646177defd256e77c632905f1e6d0
|
|
|
3cf992 |
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1858260
|
|
|
3cf992 |
|
|
|
3cf992 |
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
|
|
|
3cf992 |
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
|
|
3cf992 |
(cherry picked from commit 22494556542c676d1b9e7f1c1f2ea13ac17e1e3e)
|
|
|
3cf992 |
|
|
|
3cf992 |
Conflicts:
|
|
|
3cf992 |
- po/POTFILES.in: This file doesn't exist, only POTFILES does.
|
|
|
3cf992 |
- src/util/virdevmapper.c: Couple of problems. Firstly,
|
|
|
3cf992 |
03c532cf9711dd6ad35380455a77141ef7d492ab isn't backported, so
|
|
|
3cf992 |
the header files include looks a bit different. Secondly,
|
|
|
3cf992 |
91d88aaf23994691ea94973dd988ca5825c1e1b1 isn't backported, so
|
|
|
3cf992 |
we have to stick with virAsprintf() instead of
|
|
|
3cf992 |
g_strdup_printf(). Thirdly, virStrncpy() behaves a bit
|
|
|
3cf992 |
differently: with the old code it returns pointer to copied
|
|
|
3cf992 |
string or NULL, with the new code (cherry-picked one) it
|
|
|
3cf992 |
already returns an integer, and on the top of that, specifying
|
|
|
3cf992 |
-1 for the source len means strlen() is used under the hood
|
|
|
3cf992 |
(see 6c0d0210cbcd5d647f0d882c07f077d444bc707d and
|
|
|
3cf992 |
7d70a63b947e9a654a4e3fffa0ffa355f5549ec7 - neither is
|
|
|
3cf992 |
backported).
|
|
|
3cf992 |
|
|
|
3cf992 |
In addition, I had to de-GLib the code. In RHEL-7 there is no
|
|
|
3cf992 |
g_autofree, G_STATIC_ASSERT, g_new0, g_strdup, g_strdup_printf,
|
|
|
3cf992 |
or g_steal_pointer. I had switch these to their old counterparts
|
|
|
3cf992 |
we used to use.
|
|
|
3cf992 |
|
|
|
3cf992 |
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1933557
|
|
|
3cf992 |
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
|
|
|
3cf992 |
Message-Id: <3c7fd3071d8a9a58c8716f850880e3a0869243d3.1615203117.git.mprivozn@redhat.com>
|
|
|
3cf992 |
Reviewed-by: Ján Tomko <jtomko@redhat.com>
|
|
|
3cf992 |
---
|
|
|
3cf992 |
po/POTFILES | 1 +
|
|
|
3cf992 |
src/util/virdevmapper.c | 315 +++++++++++++++++++++++++++++-----------
|
|
|
3cf992 |
2 files changed, 228 insertions(+), 88 deletions(-)
|
|
|
3cf992 |
|
|
|
3cf992 |
diff --git a/po/POTFILES b/po/POTFILES
|
|
|
3cf992 |
index be2874487c..82a08da04a 100644
|
|
|
3cf992 |
--- a/po/POTFILES
|
|
|
3cf992 |
+++ b/po/POTFILES
|
|
|
3cf992 |
@@ -206,6 +206,7 @@ src/util/vircommand.c
|
|
|
3cf992 |
src/util/virconf.c
|
|
|
3cf992 |
src/util/vircrypto.c
|
|
|
3cf992 |
src/util/virdbus.c
|
|
|
3cf992 |
+src/util/virdevmapper.c
|
|
|
3cf992 |
src/util/virdnsmasq.c
|
|
|
3cf992 |
src/util/virerror.c
|
|
|
3cf992 |
src/util/virerror.h
|
|
|
3cf992 |
diff --git a/src/util/virdevmapper.c b/src/util/virdevmapper.c
|
|
|
3cf992 |
index 50d12ea0f1..ebf446d966 100644
|
|
|
3cf992 |
--- a/src/util/virdevmapper.c
|
|
|
3cf992 |
+++ b/src/util/virdevmapper.c
|
|
|
3cf992 |
@@ -23,40 +23,67 @@
|
|
|
3cf992 |
|
|
|
3cf992 |
#include <config.h>
|
|
|
3cf992 |
|
|
|
3cf992 |
-#ifdef MAJOR_IN_MKDEV
|
|
|
3cf992 |
-# include <sys/mkdev.h>
|
|
|
3cf992 |
-#elif MAJOR_IN_SYSMACROS
|
|
|
3cf992 |
+#include "virdevmapper.h"
|
|
|
3cf992 |
+#include "internal.h"
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+#ifdef __linux__
|
|
|
3cf992 |
# include <sys/sysmacros.h>
|
|
|
3cf992 |
-#endif
|
|
|
3cf992 |
+# include <linux/dm-ioctl.h>
|
|
|
3cf992 |
+# include <sys/ioctl.h>
|
|
|
3cf992 |
+# include <sys/types.h>
|
|
|
3cf992 |
+# include <sys/stat.h>
|
|
|
3cf992 |
+# include <fcntl.h>
|
|
|
3cf992 |
|
|
|
3cf992 |
-#ifdef WITH_DEVMAPPER
|
|
|
3cf992 |
-# include <libdevmapper.h>
|
|
|
3cf992 |
-#endif
|
|
|
3cf992 |
+# include "virthread.h"
|
|
|
3cf992 |
+# include "viralloc.h"
|
|
|
3cf992 |
+# include "virstring.h"
|
|
|
3cf992 |
+# include "virfile.h"
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+# define VIR_FROM_THIS VIR_FROM_STORAGE
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+# define PROC_DEVICES "/proc/devices"
|
|
|
3cf992 |
+# define DM_NAME "device-mapper"
|
|
|
3cf992 |
+# define DEV_DM_DIR "/dev/" DM_DIR
|
|
|
3cf992 |
+# define CONTROL_PATH DEV_DM_DIR "/" DM_CONTROL_NODE
|
|
|
3cf992 |
+# define BUF_SIZE (16 * 1024)
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+verify(BUF_SIZE > sizeof(struct dm_ioctl));
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+static unsigned int virDMMajor;
|
|
|
3cf992 |
|
|
|
3cf992 |
-#include "virdevmapper.h"
|
|
|
3cf992 |
-#include "internal.h"
|
|
|
3cf992 |
-#include "virthread.h"
|
|
|
3cf992 |
-#include "viralloc.h"
|
|
|
3cf992 |
-#include "virstring.h"
|
|
|
3cf992 |
-
|
|
|
3cf992 |
-#ifdef WITH_DEVMAPPER
|
|
|
3cf992 |
-static void
|
|
|
3cf992 |
-virDevMapperDummyLogger(int level ATTRIBUTE_UNUSED,
|
|
|
3cf992 |
- const char *file ATTRIBUTE_UNUSED,
|
|
|
3cf992 |
- int line ATTRIBUTE_UNUSED,
|
|
|
3cf992 |
- int dm_errno ATTRIBUTE_UNUSED,
|
|
|
3cf992 |
- const char *fmt ATTRIBUTE_UNUSED,
|
|
|
3cf992 |
- ...)
|
|
|
3cf992 |
-{
|
|
|
3cf992 |
- return;
|
|
|
3cf992 |
-}
|
|
|
3cf992 |
|
|
|
3cf992 |
static int
|
|
|
3cf992 |
virDevMapperOnceInit(void)
|
|
|
3cf992 |
{
|
|
|
3cf992 |
- /* Ideally, we would not need this. But libdevmapper prints
|
|
|
3cf992 |
- * error messages to stderr by default. Sad but true. */
|
|
|
3cf992 |
- dm_log_with_errno_init(virDevMapperDummyLogger);
|
|
|
3cf992 |
+ VIR_AUTOFREE(char *) buf = NULL;
|
|
|
3cf992 |
+ VIR_AUTOSTRINGLIST lines = NULL;
|
|
|
3cf992 |
+ size_t i;
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ if (virFileReadAll(PROC_DEVICES, BUF_SIZE, &buf) < 0)
|
|
|
3cf992 |
+ return -1;
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ lines = virStringSplit(buf, "\n", 0);
|
|
|
3cf992 |
+ if (!lines)
|
|
|
3cf992 |
+ return -1;
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ for (i = 0; lines[i]; i++) {
|
|
|
3cf992 |
+ VIR_AUTOFREE(char *) dev = NULL;
|
|
|
3cf992 |
+ unsigned int maj;
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ if (sscanf(lines[i], "%u %ms\n", &maj, &dev) == 2 &&
|
|
|
3cf992 |
+ STREQ(dev, DM_NAME)) {
|
|
|
3cf992 |
+ virDMMajor = maj;
|
|
|
3cf992 |
+ break;
|
|
|
3cf992 |
+ }
|
|
|
3cf992 |
+ }
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ if (!lines[i]) {
|
|
|
3cf992 |
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
3cf992 |
+ _("Unable to find major for %s"),
|
|
|
3cf992 |
+ DM_NAME);
|
|
|
3cf992 |
+ return -1;
|
|
|
3cf992 |
+ }
|
|
|
3cf992 |
+
|
|
|
3cf992 |
return 0;
|
|
|
3cf992 |
}
|
|
|
3cf992 |
|
|
|
3cf992 |
@@ -64,95 +91,200 @@ virDevMapperOnceInit(void)
|
|
|
3cf992 |
VIR_ONCE_GLOBAL_INIT(virDevMapper)
|
|
|
3cf992 |
|
|
|
3cf992 |
|
|
|
3cf992 |
+static void *
|
|
|
3cf992 |
+virDMIoctl(int controlFD, int cmd, struct dm_ioctl *dm, char **buf)
|
|
|
3cf992 |
+{
|
|
|
3cf992 |
+ size_t bufsize = BUF_SIZE;
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ reread:
|
|
|
3cf992 |
+ if (VIR_ALLOC_N(*buf, bufsize) < 0)
|
|
|
3cf992 |
+ return NULL;
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ dm->version[0] = DM_VERSION_MAJOR;
|
|
|
3cf992 |
+ dm->version[1] = 0;
|
|
|
3cf992 |
+ dm->version[2] = 0;
|
|
|
3cf992 |
+ dm->data_size = bufsize;
|
|
|
3cf992 |
+ dm->data_start = sizeof(struct dm_ioctl);
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ memcpy(*buf, dm, sizeof(struct dm_ioctl));
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ if (ioctl(controlFD, cmd, *buf) < 0) {
|
|
|
3cf992 |
+ VIR_FREE(*buf);
|
|
|
3cf992 |
+ return NULL;
|
|
|
3cf992 |
+ }
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ memcpy(dm, *buf, sizeof(struct dm_ioctl));
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ if (dm->flags & DM_BUFFER_FULL_FLAG) {
|
|
|
3cf992 |
+ bufsize += BUF_SIZE;
|
|
|
3cf992 |
+ VIR_FREE(*buf);
|
|
|
3cf992 |
+ goto reread;
|
|
|
3cf992 |
+ }
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ return *buf + dm->data_start;
|
|
|
3cf992 |
+}
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+
|
|
|
3cf992 |
static int
|
|
|
3cf992 |
-virDevMapperGetTargetsImpl(const char *path,
|
|
|
3cf992 |
- char ***devPaths_ret,
|
|
|
3cf992 |
- unsigned int ttl)
|
|
|
3cf992 |
+virDMOpen(void)
|
|
|
3cf992 |
{
|
|
|
3cf992 |
- struct dm_task *dmt = NULL;
|
|
|
3cf992 |
- struct dm_deps *deps;
|
|
|
3cf992 |
- struct dm_info info;
|
|
|
3cf992 |
- VIR_AUTOSTRINGLIST devPaths = NULL;
|
|
|
3cf992 |
- size_t i;
|
|
|
3cf992 |
- int ret = -1;
|
|
|
3cf992 |
+ VIR_AUTOCLOSE controlFD = -1;
|
|
|
3cf992 |
+ struct dm_ioctl dm;
|
|
|
3cf992 |
+ VIR_AUTOFREE(char *) tmp = NULL;
|
|
|
3cf992 |
+ int ret;
|
|
|
3cf992 |
|
|
|
3cf992 |
- *devPaths_ret = NULL;
|
|
|
3cf992 |
+ memset(&dm, 0, sizeof(dm));
|
|
|
3cf992 |
|
|
|
3cf992 |
- if (virDevMapperInitialize() < 0)
|
|
|
3cf992 |
- return ret;
|
|
|
3cf992 |
+ if ((controlFD = open(CONTROL_PATH, O_RDWR)) < 0)
|
|
|
3cf992 |
+ return -1;
|
|
|
3cf992 |
|
|
|
3cf992 |
- if (ttl == 0) {
|
|
|
3cf992 |
- errno = ELOOP;
|
|
|
3cf992 |
+ if (!virDMIoctl(controlFD, DM_VERSION, &dm, &tmp)) {
|
|
|
3cf992 |
+ virReportSystemError(errno, "%s",
|
|
|
3cf992 |
+ _("Unable to get device-mapper version"));
|
|
|
3cf992 |
+ return -1;
|
|
|
3cf992 |
+ }
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ if (dm.version[0] != DM_VERSION_MAJOR) {
|
|
|
3cf992 |
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
|
|
|
3cf992 |
+ _("Unsupported device-mapper version. Expected %d got %d"),
|
|
|
3cf992 |
+ DM_VERSION_MAJOR, dm.version[0]);
|
|
|
3cf992 |
+ return -1;
|
|
|
3cf992 |
+ }
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ ret = controlFD;
|
|
|
3cf992 |
+ controlFD = -1;
|
|
|
3cf992 |
+ return ret;
|
|
|
3cf992 |
+}
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+static char *
|
|
|
3cf992 |
+virDMSanitizepath(const char *path)
|
|
|
3cf992 |
+{
|
|
|
3cf992 |
+ VIR_AUTOFREE(char *) dmDirPath = NULL;
|
|
|
3cf992 |
+ struct dirent *ent = NULL;
|
|
|
3cf992 |
+ struct stat sb[2];
|
|
|
3cf992 |
+ DIR *dh = NULL;
|
|
|
3cf992 |
+ const char *p;
|
|
|
3cf992 |
+ char *ret = NULL;
|
|
|
3cf992 |
+ int rc;
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ /* If a path is NOT provided then assume it's DM name */
|
|
|
3cf992 |
+ p = strrchr(path, '/');
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ if (!p) {
|
|
|
3cf992 |
+ ignore_value(VIR_STRDUP(ret, path));
|
|
|
3cf992 |
return ret;
|
|
|
3cf992 |
+ } else {
|
|
|
3cf992 |
+ p++;
|
|
|
3cf992 |
}
|
|
|
3cf992 |
|
|
|
3cf992 |
- if (!virIsDevMapperDevice(path))
|
|
|
3cf992 |
- return 0;
|
|
|
3cf992 |
+ /* It's a path. Check if the last component is DM name */
|
|
|
3cf992 |
+ if (stat(path, &sb[0]) < 0) {
|
|
|
3cf992 |
+ virReportError(errno,
|
|
|
3cf992 |
+ _("Unable to stat %p"),
|
|
|
3cf992 |
+ path);
|
|
|
3cf992 |
+ return NULL;
|
|
|
3cf992 |
+ }
|
|
|
3cf992 |
|
|
|
3cf992 |
- if (!(dmt = dm_task_create(DM_DEVICE_DEPS))) {
|
|
|
3cf992 |
- if (errno == ENOENT || errno == ENODEV) {
|
|
|
3cf992 |
- /* It's okay. Kernel is probably built without
|
|
|
3cf992 |
- * devmapper support. */
|
|
|
3cf992 |
- ret = 0;
|
|
|
3cf992 |
- }
|
|
|
3cf992 |
+ if (virAsprintf(&dmDirPath, DEV_DM_DIR "/%s", p) < 0)
|
|
|
3cf992 |
+ return NULL;
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ if (stat(dmDirPath, &sb[1]) == 0 &&
|
|
|
3cf992 |
+ sb[0].st_rdev == sb[1].st_rdev) {
|
|
|
3cf992 |
+ ignore_value(VIR_STRDUP(ret, p));
|
|
|
3cf992 |
return ret;
|
|
|
3cf992 |
}
|
|
|
3cf992 |
|
|
|
3cf992 |
- if (!dm_task_set_name(dmt, path)) {
|
|
|
3cf992 |
- if (errno == ENOENT) {
|
|
|
3cf992 |
- /* It's okay, @path is not managed by devmapper =>
|
|
|
3cf992 |
- * not a devmapper device. */
|
|
|
3cf992 |
- ret = 0;
|
|
|
3cf992 |
+ /* The last component of @path wasn't DM name. Let's check if
|
|
|
3cf992 |
+ * there's a device under /dev/mapper/ with the same rdev. */
|
|
|
3cf992 |
+ if (virDirOpen(&dh, DEV_DM_DIR) < 0)
|
|
|
3cf992 |
+ return NULL;
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ while ((rc = virDirRead(dh, &ent, DEV_DM_DIR)) > 0) {
|
|
|
3cf992 |
+ VIR_AUTOFREE(char *) tmp = NULL;
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ if (virAsprintf(&tmp, DEV_DM_DIR "/%s", ent->d_name) < 0)
|
|
|
3cf992 |
+ return NULL;
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ if (stat(tmp, &sb[1]) == 0 &&
|
|
|
3cf992 |
+ sb[0].st_rdev == sb[0].st_rdev) {
|
|
|
3cf992 |
+ VIR_STEAL_PTR(ret, tmp);
|
|
|
3cf992 |
+ break;
|
|
|
3cf992 |
}
|
|
|
3cf992 |
- goto cleanup;
|
|
|
3cf992 |
}
|
|
|
3cf992 |
|
|
|
3cf992 |
- dm_task_no_open_count(dmt);
|
|
|
3cf992 |
+ virDirClose(&dh);
|
|
|
3cf992 |
+ return ret;
|
|
|
3cf992 |
+}
|
|
|
3cf992 |
|
|
|
3cf992 |
- if (!dm_task_run(dmt)) {
|
|
|
3cf992 |
- if (errno == ENXIO) {
|
|
|
3cf992 |
- /* If @path = "/dev/mapper/control" ENXIO is returned. */
|
|
|
3cf992 |
- ret = 0;
|
|
|
3cf992 |
- }
|
|
|
3cf992 |
- goto cleanup;
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+static int
|
|
|
3cf992 |
+virDevMapperGetTargetsImpl(int controlFD,
|
|
|
3cf992 |
+ const char *path,
|
|
|
3cf992 |
+ char ***devPaths_ret,
|
|
|
3cf992 |
+ unsigned int ttl)
|
|
|
3cf992 |
+{
|
|
|
3cf992 |
+ VIR_AUTOFREE(char *) sanitizedPath = NULL;
|
|
|
3cf992 |
+ VIR_AUTOFREE(char *) buf = NULL;
|
|
|
3cf992 |
+ struct dm_ioctl dm;
|
|
|
3cf992 |
+ struct dm_target_deps *deps = NULL;
|
|
|
3cf992 |
+ VIR_AUTOSTRINGLIST devPaths = NULL;
|
|
|
3cf992 |
+ size_t i;
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ memset(&dm, 0, sizeof(dm));
|
|
|
3cf992 |
+ *devPaths_ret = NULL;
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ if (ttl == 0) {
|
|
|
3cf992 |
+ errno = ELOOP;
|
|
|
3cf992 |
+ return -1;
|
|
|
3cf992 |
}
|
|
|
3cf992 |
|
|
|
3cf992 |
- if (!dm_task_get_info(dmt, &info))
|
|
|
3cf992 |
- goto cleanup;
|
|
|
3cf992 |
+ if (!virIsDevMapperDevice(path))
|
|
|
3cf992 |
+ return 0;
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ if (!(sanitizedPath = virDMSanitizepath(path)))
|
|
|
3cf992 |
+ return 0;
|
|
|
3cf992 |
|
|
|
3cf992 |
- if (!info.exists) {
|
|
|
3cf992 |
- ret = 0;
|
|
|
3cf992 |
- goto cleanup;
|
|
|
3cf992 |
+ if (virStrcpy(dm.name, sanitizedPath, DM_TABLE_DEPS) == NULL) {
|
|
|
3cf992 |
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
|
|
|
3cf992 |
+ _("Resolved device mapper name too long"));
|
|
|
3cf992 |
+ return -1;
|
|
|
3cf992 |
}
|
|
|
3cf992 |
|
|
|
3cf992 |
- if (!(deps = dm_task_get_deps(dmt)))
|
|
|
3cf992 |
- goto cleanup;
|
|
|
3cf992 |
+ deps = virDMIoctl(controlFD, DM_TABLE_DEPS, &dm, &buf;;
|
|
|
3cf992 |
+ if (!deps) {
|
|
|
3cf992 |
+ if (errno == ENXIO)
|
|
|
3cf992 |
+ return 0;
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ virReportSystemError(errno,
|
|
|
3cf992 |
+ _("Unable to query dependencies for %s"),
|
|
|
3cf992 |
+ path);
|
|
|
3cf992 |
+ return -1;
|
|
|
3cf992 |
+ }
|
|
|
3cf992 |
|
|
|
3cf992 |
if (VIR_ALLOC_N_QUIET(devPaths, deps->count + 1) < 0)
|
|
|
3cf992 |
- goto cleanup;
|
|
|
3cf992 |
+ return -1;
|
|
|
3cf992 |
|
|
|
3cf992 |
for (i = 0; i < deps->count; i++) {
|
|
|
3cf992 |
if (virAsprintfQuiet(&devPaths[i], "/dev/block/%u:%u",
|
|
|
3cf992 |
- major(deps->device[i]),
|
|
|
3cf992 |
- minor(deps->device[i])) < 0)
|
|
|
3cf992 |
- goto cleanup;
|
|
|
3cf992 |
+ major(deps->dev[i]),
|
|
|
3cf992 |
+ minor(deps->dev[i])) < 0) {
|
|
|
3cf992 |
+ return -1;
|
|
|
3cf992 |
+ }
|
|
|
3cf992 |
}
|
|
|
3cf992 |
|
|
|
3cf992 |
for (i = 0; i < deps->count; i++) {
|
|
|
3cf992 |
VIR_AUTOSTRINGLIST tmpPaths = NULL;
|
|
|
3cf992 |
|
|
|
3cf992 |
- if (virDevMapperGetTargetsImpl(devPaths[i], &tmpPaths, ttl - 1) < 0)
|
|
|
3cf992 |
- goto cleanup;
|
|
|
3cf992 |
+ if (virDevMapperGetTargetsImpl(controlFD, devPaths[i], &tmpPaths, ttl - 1) < 0)
|
|
|
3cf992 |
+ return -1;
|
|
|
3cf992 |
|
|
|
3cf992 |
if (virStringListMerge(&devPaths, &tmpPaths) < 0)
|
|
|
3cf992 |
- goto cleanup;
|
|
|
3cf992 |
+ return -1;
|
|
|
3cf992 |
}
|
|
|
3cf992 |
|
|
|
3cf992 |
VIR_STEAL_PTR(*devPaths_ret, devPaths);
|
|
|
3cf992 |
- ret = 0;
|
|
|
3cf992 |
- cleanup:
|
|
|
3cf992 |
- dm_task_destroy(dmt);
|
|
|
3cf992 |
- return ret;
|
|
|
3cf992 |
+ return 0;
|
|
|
3cf992 |
}
|
|
|
3cf992 |
|
|
|
3cf992 |
|
|
|
3cf992 |
@@ -171,9 +303,6 @@ virDevMapperGetTargetsImpl(const char *path,
|
|
|
3cf992 |
* If @path consists of yet another devmapper targets these are
|
|
|
3cf992 |
* consulted recursively.
|
|
|
3cf992 |
*
|
|
|
3cf992 |
- * If we don't have permissions to talk to kernel, -1 is returned
|
|
|
3cf992 |
- * and errno is set to EBADF.
|
|
|
3cf992 |
- *
|
|
|
3cf992 |
* Returns 0 on success,
|
|
|
3cf992 |
* -1 otherwise (with errno set, no libvirt error is
|
|
|
3cf992 |
* reported)
|
|
|
3cf992 |
@@ -182,13 +311,20 @@ int
|
|
|
3cf992 |
virDevMapperGetTargets(const char *path,
|
|
|
3cf992 |
char ***devPaths)
|
|
|
3cf992 |
{
|
|
|
3cf992 |
+ VIR_AUTOCLOSE controlFD = -1;
|
|
|
3cf992 |
const unsigned int ttl = 32;
|
|
|
3cf992 |
|
|
|
3cf992 |
/* Arbitrary limit on recursion level. A devmapper target can
|
|
|
3cf992 |
* consist of devices or yet another targets. If that's the
|
|
|
3cf992 |
* case, we have to stop recursion somewhere. */
|
|
|
3cf992 |
|
|
|
3cf992 |
- return virDevMapperGetTargetsImpl(path, devPaths, ttl);
|
|
|
3cf992 |
+ if (virDevMapperInitialize() < 0)
|
|
|
3cf992 |
+ return -1;
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ if ((controlFD = virDMOpen()) < 0)
|
|
|
3cf992 |
+ return -1;
|
|
|
3cf992 |
+
|
|
|
3cf992 |
+ return virDevMapperGetTargetsImpl(controlFD, path, devPaths, ttl);
|
|
|
3cf992 |
}
|
|
|
3cf992 |
|
|
|
3cf992 |
|
|
|
3cf992 |
@@ -197,15 +333,18 @@ virIsDevMapperDevice(const char *dev_name)
|
|
|
3cf992 |
{
|
|
|
3cf992 |
struct stat buf;
|
|
|
3cf992 |
|
|
|
3cf992 |
+ if (virDevMapperInitialize() < 0)
|
|
|
3cf992 |
+ return false;
|
|
|
3cf992 |
+
|
|
|
3cf992 |
if (!stat(dev_name, &buf) &&
|
|
|
3cf992 |
S_ISBLK(buf.st_mode) &&
|
|
|
3cf992 |
- dm_is_dm_major(major(buf.st_rdev)))
|
|
|
3cf992 |
- return true;
|
|
|
3cf992 |
+ major(buf.st_rdev) == virDMMajor)
|
|
|
3cf992 |
+ return true;
|
|
|
3cf992 |
|
|
|
3cf992 |
return false;
|
|
|
3cf992 |
}
|
|
|
3cf992 |
|
|
|
3cf992 |
-#else /* ! WITH_DEVMAPPER */
|
|
|
3cf992 |
+#else /* !defined(__linux__) */
|
|
|
3cf992 |
|
|
|
3cf992 |
int
|
|
|
3cf992 |
virDevMapperGetTargets(const char *path ATTRIBUTE_UNUSED,
|
|
|
3cf992 |
@@ -221,4 +360,4 @@ virIsDevMapperDevice(const char *dev_name G_GNUC_UNUSED)
|
|
|
3cf992 |
{
|
|
|
3cf992 |
return false;
|
|
|
3cf992 |
}
|
|
|
3cf992 |
-#endif /* ! WITH_DEVMAPPER */
|
|
|
3cf992 |
+#endif /* ! defined(__linux__) */
|
|
|
3cf992 |
--
|
|
|
3cf992 |
2.31.0
|
|
|
3cf992 |
|