9c6c51
From 666d4aacfd91d8c0447a1e4f8d44d50a3fe40198 Mon Sep 17 00:00:00 2001
9c6c51
Message-Id: <666d4aacfd91d8c0447a1e4f8d44d50a3fe40198@dist-git>
9c6c51
From: Michal Privoznik <mprivozn@redhat.com>
9c6c51
Date: Tue, 23 Oct 2018 11:40:58 +0100
9c6c51
Subject: [PATCH] virfile: Take symlink into account in virFileIsSharedFixFUSE
9c6c51
9c6c51
RHEL-7.7: https://bugzilla.redhat.com/show_bug.cgi?id=1640465
9c6c51
RHEL-7.6.z: https://bugzilla.redhat.com/show_bug.cgi?id=1641798
9c6c51
RHEL-8.0: https://bugzilla.redhat.com/show_bug.cgi?id=1634782
9c6c51
9c6c51
Weirdly enough, there can be symlinks in the path we are trying
9c6c51
to fix. If it is the case our clever algorithm that finds matches
9c6c51
against mount table won't work. Canonicalize path at the
9c6c51
beginning then.
9c6c51
9c6c51
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
9c6c51
Reviewed-by: Erik Skultety <eskultet@redhat.com>
9c6c51
(cherry picked from commit c0790e3a09f57da0bd25c7eac4a35ed6e7e9e858)
9c6c51
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
9c6c51
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
9c6c51
---
9c6c51
 cfg.mk              |  2 +-
9c6c51
 src/util/virfile.c  | 15 +++++++++++++--
9c6c51
 tests/virfilemock.c | 33 ++++++++++++++++++++++++++++++++-
9c6c51
 tests/virfiletest.c |  1 +
9c6c51
 4 files changed, 47 insertions(+), 4 deletions(-)
9c6c51
9c6c51
diff --git a/cfg.mk b/cfg.mk
9c6c51
index 6bebd0ad9f..e3e94bf6f0 100644
9c6c51
--- a/cfg.mk
9c6c51
+++ b/cfg.mk
9c6c51
@@ -1216,7 +1216,7 @@ exclude_file_name_regexp--sc_prohibit_select = \
9c6c51
 	^cfg\.mk$$
9c6c51
 
9c6c51
 exclude_file_name_regexp--sc_prohibit_canonicalize_file_name = \
9c6c51
-  ^cfg\.mk$$
9c6c51
+  ^(cfg\.mk|tests/virfilemock\.c)$$
9c6c51
 
9c6c51
 exclude_file_name_regexp--sc_prohibit_raw_allocation = \
9c6c51
   ^(docs/hacking\.html\.in|src/util/viralloc\.[ch]|examples/.*|tests/(securityselinuxhelper|(vircgroup|nss)mock|commandhelper)\.c|tools/wireshark/src/packet-libvirt\.c)$$
9c6c51
diff --git a/src/util/virfile.c b/src/util/virfile.c
9c6c51
index e1dee7633a..716b55d770 100644
9c6c51
--- a/src/util/virfile.c
9c6c51
+++ b/src/util/virfile.c
9c6c51
@@ -3549,9 +3549,19 @@ virFileIsSharedFixFUSE(const char *path,
9c6c51
     char mntbuf[1024];
9c6c51
     char *mntDir = NULL;
9c6c51
     char *mntType = NULL;
9c6c51
+    char *canonPath = NULL;
9c6c51
     size_t maxMatching = 0;
9c6c51
     int ret = -1;
9c6c51
 
9c6c51
+    if (!(canonPath = virFileCanonicalizePath(path))) {
9c6c51
+        virReportSystemError(errno,
9c6c51
+                             _("unable to canonicalize %s"),
9c6c51
+                             path);
9c6c51
+        return -1;
9c6c51
+    }
9c6c51
+
9c6c51
+    VIR_DEBUG("Path canonicalization: %s->%s", path, canonPath);
9c6c51
+
9c6c51
     if (!(f = setmntent(PROC_MOUNTS, "r"))) {
9c6c51
         virReportSystemError(errno,
9c6c51
                              _("Unable to open %s"),
9c6c51
@@ -3563,7 +3573,7 @@ virFileIsSharedFixFUSE(const char *path,
9c6c51
         const char *p;
9c6c51
         size_t len = strlen(mb.mnt_dir);
9c6c51
 
9c6c51
-        if (!(p = STRSKIP(path, mb.mnt_dir)))
9c6c51
+        if (!(p = STRSKIP(canonPath, mb.mnt_dir)))
9c6c51
             continue;
9c6c51
 
9c6c51
         if (*(p - 1) != '/' && *p != '/' && *p != '\0')
9c6c51
@@ -3581,12 +3591,13 @@ virFileIsSharedFixFUSE(const char *path,
9c6c51
 
9c6c51
     if (STREQ_NULLABLE(mntType, "fuse.glusterfs")) {
9c6c51
         VIR_DEBUG("Found gluster FUSE mountpoint=%s for path=%s. "
9c6c51
-                  "Fixing shared FS type", mntDir, path);
9c6c51
+                  "Fixing shared FS type", mntDir, canonPath);
9c6c51
         *f_type = GFS2_MAGIC;
9c6c51
     }
9c6c51
 
9c6c51
     ret = 0;
9c6c51
  cleanup:
9c6c51
+    VIR_FREE(canonPath);
9c6c51
     VIR_FREE(mntType);
9c6c51
     VIR_FREE(mntDir);
9c6c51
     endmntent(f);
9c6c51
diff --git a/tests/virfilemock.c b/tests/virfilemock.c
9c6c51
index 822c757380..ae5c8d025a 100644
9c6c51
--- a/tests/virfilemock.c
9c6c51
+++ b/tests/virfilemock.c
9c6c51
@@ -28,11 +28,14 @@
9c6c51
 #endif
9c6c51
 
9c6c51
 #include "virmock.h"
9c6c51
+#include "virstring.h"
9c6c51
+#include "viralloc.h"
9c6c51
 
9c6c51
 #define VIR_FROM_THIS VIR_FROM_NONE
9c6c51
 
9c6c51
 static FILE *(*real_setmntent)(const char *filename, const char *type);
9c6c51
 static int (*real_statfs)(const char *path, struct statfs *buf);
9c6c51
+static char *(*real_canonicalize_file_name)(const char *path);
9c6c51
 
9c6c51
 
9c6c51
 static void
9c6c51
@@ -43,6 +46,7 @@ init_syms(void)
9c6c51
 
9c6c51
     VIR_MOCK_REAL_INIT(setmntent);
9c6c51
     VIR_MOCK_REAL_INIT(statfs);
9c6c51
+    VIR_MOCK_REAL_INIT(canonicalize_file_name);
9c6c51
 }
9c6c51
 
9c6c51
 
9c6c51
@@ -94,6 +98,7 @@ statfs_mock(const char *mtab,
9c6c51
     FILE *f;
9c6c51
     struct mntent mb;
9c6c51
     char mntbuf[1024];
9c6c51
+    char *canonPath = NULL;
9c6c51
     int ret = -1;
9c6c51
 
9c6c51
     if (!(f = real_setmntent(mtab, "r"))) {
9c6c51
@@ -101,10 +106,16 @@ statfs_mock(const char *mtab,
9c6c51
         return -1;
9c6c51
     }
9c6c51
 
9c6c51
+    /* We don't need to do this in callers because real statfs(2)
9c6c51
+     * does that for us. However, in mocked implementation we
9c6c51
+     * need to do this. */
9c6c51
+    if (!(canonPath = canonicalize_file_name(path)))
9c6c51
+        return -1;
9c6c51
+
9c6c51
     while (getmntent_r(f, &mb, mntbuf, sizeof(mntbuf))) {
9c6c51
         int ftype;
9c6c51
 
9c6c51
-        if (STRNEQ(mb.mnt_dir, path))
9c6c51
+        if (STRNEQ(mb.mnt_dir, canonPath))
9c6c51
             continue;
9c6c51
 
9c6c51
         if (STREQ(mb.mnt_type, "nfs") ||
9c6c51
@@ -136,6 +147,7 @@ statfs_mock(const char *mtab,
9c6c51
     }
9c6c51
 
9c6c51
     endmntent(f);
9c6c51
+    VIR_FREE(canonPath);
9c6c51
     return ret;
9c6c51
 }
9c6c51
 
9c6c51
@@ -152,3 +164,22 @@ statfs(const char *path, struct statfs *buf)
9c6c51
 
9c6c51
     return real_statfs(path, buf);
9c6c51
 }
9c6c51
+
9c6c51
+
9c6c51
+char *
9c6c51
+canonicalize_file_name(const char *path)
9c6c51
+{
9c6c51
+    if (getenv("LIBVIRT_MTAB")) {
9c6c51
+        const char *p;
9c6c51
+        char *ret;
9c6c51
+
9c6c51
+        if ((p = STRSKIP(path, "/some/symlink")))
9c6c51
+            ignore_value(virAsprintfQuiet(&ret, "/gluster%s", p));
9c6c51
+        else
9c6c51
+            ignore_value(VIR_STRDUP_QUIET(ret, path));
9c6c51
+
9c6c51
+        return ret;
9c6c51
+    }
9c6c51
+
9c6c51
+    return real_canonicalize_file_name(path);
9c6c51
+}
9c6c51
diff --git a/tests/virfiletest.c b/tests/virfiletest.c
9c6c51
index be4dbf8910..a246d601ba 100644
9c6c51
--- a/tests/virfiletest.c
9c6c51
+++ b/tests/virfiletest.c
9c6c51
@@ -457,6 +457,7 @@ mymain(void)
9c6c51
     DO_TEST_FILE_IS_SHARED_FS_TYPE("mounts3.txt", "/nfs/blah", false);
9c6c51
     DO_TEST_FILE_IS_SHARED_FS_TYPE("mounts3.txt", "/gluster/file", true);
9c6c51
     DO_TEST_FILE_IS_SHARED_FS_TYPE("mounts3.txt", "/gluster/sshfs/file", false);
9c6c51
+    DO_TEST_FILE_IS_SHARED_FS_TYPE("mounts3.txt", "/some/symlink/file", true);
9c6c51
 
9c6c51
     return ret != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
9c6c51
 }
9c6c51
-- 
9c6c51
2.19.2
9c6c51