- Track Linux filesystem id (FSID) for quiesced (frozen) filesystems

This commit is contained in:
eabdullin 2023-09-21 13:25:45 +03:00
parent 7a51a30c62
commit 574359d30a
2 changed files with 213 additions and 1 deletions

View File

@ -0,0 +1,206 @@
From 9d458c53a7a656d4d1ba3a28d090cce82ac4af0e Mon Sep 17 00:00:00 2001
From: Katy Feng <fkaty@vmware.com>
Date: Tue, 17 Jan 2023 19:08:33 -0800
Subject: [PATCH] Track Linux filesystem id (FSID) for quiesced (frozen)
filesystems
Tracking the filesystem FSID along with each file descriptor (FD)
as the ioctl FIFREEZE is done. An EBUSY could be seen because of
an attempt to freeze the same superblock more than once depending
on the OS configuration (e.g. usage of bind mounts). An EBUSY could
also mean another process has locked or frozen that filesystem.
When an EBUSY is received, the filesyste FSID is checked against the
list of filesystems that have already be quiesced. If not previously
seen, a warning that the filesystem is controlled by another process
is logged and the quiesced snapshot request will be rejected.
---
.../lib/syncDriver/syncDriverLinux.c | 112 +++++++++++++++---
1 file changed, 96 insertions(+), 16 deletions(-)
diff --git a/open-vm-tools/lib/syncDriver/syncDriverLinux.c b/open-vm-tools/lib/syncDriver/syncDriverLinux.c
index eef65a2eb..6d9a35687 100644
--- a/open-vm-tools/lib/syncDriver/syncDriverLinux.c
+++ b/open-vm-tools/lib/syncDriver/syncDriverLinux.c
@@ -1,5 +1,5 @@
/*********************************************************
- * Copyright (C) 2011-2018 VMware, Inc. All rights reserved.
+ * Copyright (C) 2011-2018, 2023 VMware, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
@@ -32,6 +32,7 @@
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/statfs.h>
#include "debug.h"
#include "dynbuf.h"
#include "syncDriverInt.h"
@@ -43,12 +44,53 @@
#endif
+
+typedef struct LinuxFsInfo {
+ int fd;
+ fsid_t fsid;
+} LinuxFsInfo;
+
typedef struct LinuxDriver {
SyncHandle driver;
size_t fdCnt;
- int *fds;
+ LinuxFsInfo *fds;
} LinuxDriver;
+static
+const fsid_t MISSING_FSID = {};
+
+
+/*
+ *******************************************************************************
+ * LinuxFiFsIdMatch --
+ *
+ * Check the collection of filesystems previously frozen for the specific
+ * FSID.
+ *
+ * @param[in] fds List of LinuxFsInfo data for filesystems previously
+ * frozen.
+ * @param[in] count Number of fds in the list.
+ * @param[in] nfsid The Filesystem ID of interest.
+ *
+ * @return TRUE if the FSID matches one previously processed. Otherwise FALSE
+ *
+ *******************************************************************************
+ */
+
+static Bool
+LinuxFiFsIdMatch(const LinuxFsInfo *fds,
+ const size_t count,
+ const fsid_t *nfsid) {
+ size_t i;
+
+ for (i = 0; i < count; i++) {
+ if (fds[i].fsid.__val[0] == nfsid->__val[0] &&
+ fds[i].fsid.__val[1] == nfsid->__val[1]) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
/*
*******************************************************************************
@@ -75,9 +117,11 @@ LinuxFiThaw(const SyncDriverHandle handle)
* Thaw in the reverse order of freeze
*/
for (i = sync->fdCnt; i > 0; i--) {
- Debug(LGPFX "Thawing fd=%d.\n", sync->fds[i-1]);
- if (ioctl(sync->fds[i-1], FITHAW) == -1) {
- Debug(LGPFX "Thaw failed for fd=%d.\n", sync->fds[i-1]);
+ int fd = sync->fds[i-1].fd;
+
+ Debug(LGPFX "Thawing fd=%d.\n", fd);
+ if (ioctl(fd, FITHAW) == -1) {
+ Debug(LGPFX "Thaw failed for fd=%d.\n", fd);
err = SD_ERROR;
}
}
@@ -108,8 +152,10 @@ LinuxFiClose(SyncDriverHandle handle)
* Close in the reverse order of open
*/
for (i = sync->fdCnt; i > 0; i--) {
- Debug(LGPFX "Closing fd=%d.\n", sync->fds[i-1]);
- close(sync->fds[i-1]);
+ int fd = sync->fds[i-1].fd;
+
+ Debug(LGPFX "Closing fd=%d.\n", fd);
+ close(fd);
}
free(sync->fds);
free(sync);
@@ -196,8 +242,11 @@ LinuxDriver_Freeze(const GSList *paths,
*/
while (paths != NULL) {
int fd;
+ LinuxFsInfo fsInfo;
struct stat sbuf;
+ struct statfs fsbuf;
const char *path = paths->data;
+
Debug(LGPFX "opening path '%s'.\n", path);
paths = g_slist_next(paths);
fd = open(path, O_RDONLY);
@@ -258,23 +307,53 @@ LinuxDriver_Freeze(const GSList *paths,
continue;
}
+ if (fstatfs(fd, &fsbuf) == 0) {
+ fsInfo.fsid = fsbuf.f_fsid;
+ } else {
+ Debug(LGPFX "failed to get file system id for path '%s'.\n", path);
+ fsInfo.fsid = MISSING_FSID;
+ }
Debug(LGPFX "freezing path '%s' (fd=%d).\n", path, fd);
if (ioctl(fd, FIFREEZE) == -1) {
int ioctlerr = errno;
+
+ close(fd);
+ Debug(LGPFX "freeze on '%s' returned: %d (%s)\n",
+ path, ioctlerr, strerror(ioctlerr));
+ /*
+ * Previously, an EBUSY error was ignored, assuming that we may try
+ * to freeze the same superblock more than once depending on the
+ * OS configuration (e.g., usage of bind mounts).
+ * Using the filesystem Id to check if this is a filesystem that we
+ * have seen previously and will ignore this FD only if that is
+ * the case. Log a warning otherwise since the quiesced snapshot
+ * attempt will fail.
+ */
+ if (ioctlerr == EBUSY) {
+ if (LinuxFiFsIdMatch(DynBuf_Get(&fds),
+ DynBuf_GetSize(&fds),
+ &fsInfo.fsid)) {
+ /*
+ * We have previous knowledge of this file system by another
+ * mount point. Safe to ignore.
+ */
+ Debug(LGPFX "skipping path '%s' - previously frozen", path);
+ continue;
+ }
+ /*
+ * It appears that this FS has been locked or frozen by another
+ * process. We cannot proceed with the quiesced snapshot request.
+ */
+ Warning(LGPFX "'%s' appears locked or frozen by another process. "
+ "Cannot complete the quiesced snapshot request.\n", path);
+ }
/*
* If the ioctl does not exist, Linux will return ENOTTY. If it's not
* supported on the device, we get EOPNOTSUPP. Ignore the latter,
* since freezing does not make sense for all fs types, and some
* Linux fs drivers may not have been hooked up in the running kernel.
- *
- * Also ignore EBUSY since we may try to freeze the same superblock
- * more than once depending on the OS configuration (e.g., usage of
- * bind mounts).
*/
- close(fd);
- Debug(LGPFX "freeze on '%s' returned: %d (%s)\n",
- path, ioctlerr, strerror(ioctlerr));
- if (ioctlerr != EBUSY && ioctlerr != EOPNOTSUPP) {
+ if (ioctlerr != EOPNOTSUPP) {
Debug(LGPFX "failed to freeze '%s': %d (%s)\n",
path, ioctlerr, strerror(ioctlerr));
err = first && ioctlerr == ENOTTY ? SD_UNAVAILABLE : SD_ERROR;
@@ -282,7 +361,8 @@ LinuxDriver_Freeze(const GSList *paths,
}
} else {
Debug(LGPFX "successfully froze '%s' (fd=%d).\n", path, fd);
- if (!DynBuf_Append(&fds, &fd, sizeof fd)) {
+ fsInfo.fd = fd;
+ if (!DynBuf_Append(&fds, &fsInfo, sizeof fsInfo)) {
if (ioctl(fd, FITHAW) == -1) {
Warning(LGPFX "failed to thaw '%s': %d (%s)\n",
path, errno, strerror(errno));

View File

@ -32,7 +32,7 @@
Name: open-vm-tools
Version: %{toolsversion}
Release: 2%{?dist}.alma
Release: 2%{?dist}.2.alma.1
Summary: Open Virtual Machine Tools for virtual machines hosted on VMware
License: GPLv2
URL: https://github.com/vmware/%{name}
@ -54,6 +54,9 @@ ExclusiveArch: %{ix86} x86_64 aarch64
#Patch0: name.patch
# [CISA Major Incident] CVE-2023-20867 open-vm-tools: authentication bypass vulnerability in the vgauth module
Patch1: ovt-Remove-some-dead-code.patch
# Patches were taken from:
# https://github.com/vmware/open-vm-tools/commit/9d458c53a7a656d4d1ba3a28d090cce82ac4af0e.patch
Patch2: Track-Linux-filesystem-id-FSID-for-quiesced-frozen-filesystems.patch
BuildRequires: autoconf
BuildRequires: automake
@ -412,6 +415,9 @@ fi
%{_bindir}/vmware-vgauth-smoketest
%changelog
* Tue Sep 12 2023 Eduard Abdullin <eabdullin@almalinux.org> - 12.1.5-1.el8_8.2.alma.1
- Track Linux filesystem id (FSID) for quiesced (frozen) filesystems
* Wed Jul 12 2023 Andrew Lukoshko <alukoshko@almalinux.org> - 12.1.5-2.el8_8.alma
- [CISA Major Incident] CVE-2023-20867 open-vm-tools: authentication bypass vulnerability in the vgauth module