diff --git a/3468542f-virFileUnlink.patch b/3468542f-virFileUnlink.patch new file mode 100644 index 0000000..f152f3a --- /dev/null +++ b/3468542f-virFileUnlink.patch @@ -0,0 +1,179 @@ +From 3468542f06f6f5dc94defa1603c6a6adea3e2da8 Mon Sep 17 00:00:00 2001 +From: John Ferlan +Date: Mon, 24 Aug 2015 17:00:02 -0400 +Subject: [PATCH] virfile: Introduce virFileUnlink + +In an NFS root-squashed environment the 'vol-delete' command will fail to +'unlink' the target volume since it was created under a different uid:gid. + +This code continues the concepts introduced in virFileOpenForked and +virDirCreate[NoFork] with respect to running the unlink command under +the uid/gid of the child. Unlike the other two, don't retry on EACCES +(that's why we're here doing this now). + +(cherry picked from commit 35847860f65f92e444db9730e00cdaef45198e0c) +--- + src/libvirt_private.syms | 1 + + src/storage/storage_backend_fs.c | 3 +- + src/util/virfile.c | 106 +++++++++++++++++++++++++++++++++++++++ + src/util/virfile.h | 1 + + 4 files changed, 110 insertions(+), 1 deletion(-) + +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index d57bf5b..a96c985 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -1462,6 +1462,7 @@ virFileSanitizePath; + virFileSkipRoot; + virFileStripSuffix; + virFileTouch; ++virFileUnlink; + virFileUnlock; + virFileUpdatePerm; + virFileWaitForDevices; +diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c +index c0ea1df..f41a41e 100644 +--- a/src/storage/storage_backend_fs.c ++++ b/src/storage/storage_backend_fs.c +@@ -1203,7 +1203,8 @@ virStorageBackendFileSystemVolDelete(virConnectPtr conn ATTRIBUTE_UNUSED, + + switch ((virStorageVolType) vol->type) { + case VIR_STORAGE_VOL_FILE: +- if (unlink(vol->target.path) < 0) { ++ if (virFileUnlink(vol->target.path, vol->target.perms->uid, ++ vol->target.perms->gid) < 0) { + /* Silently ignore failures where the vol has already gone away */ + if (errno != ENOENT) { + virReportSystemError(errno, +diff --git a/src/util/virfile.c b/src/util/virfile.c +index 5f64186..7b14ee8 100644 +--- a/src/util/virfile.c ++++ b/src/util/virfile.c +@@ -2306,6 +2306,112 @@ virFileOpenAs(const char *path, int openflags, mode_t mode, + return ret; + } + ++ ++/* virFileUnlink: ++ * @path: file to unlink ++ * @uid: uid that was used to create the file (not required) ++ * @gid: gid that was used to create the file (not required) ++ * ++ * If a file/volume was created in an NFS root-squash environment, ++ * then we must 'unlink' the file in the same environment. Unlike ++ * the virFileOpenAs[Forked] and virDirCreate[NoFork], this code ++ * takes no extra flags and does not bother with EACCES failures ++ * from the child. ++ */ ++int ++virFileUnlink(const char *path, ++ uid_t uid, ++ gid_t gid) ++{ ++ pid_t pid; ++ int waitret; ++ int status, ret = 0; ++ gid_t *groups; ++ int ngroups; ++ ++ /* If not running as root or if a non explicit uid/gid was being used for ++ * the file/volume, then use unlink directly ++ */ ++ if ((geteuid() != 0) || ++ ((uid == (uid_t) -1) && (gid == (gid_t) -1))) ++ return unlink(path); ++ ++ /* Otherwise, we have to deal with the NFS root-squash craziness ++ * to run under the uid/gid that created the volume in order to ++ * perform the unlink of the volume. ++ */ ++ if (uid == (uid_t) -1) ++ uid = geteuid(); ++ if (gid == (gid_t) -1) ++ gid = getegid(); ++ ++ ngroups = virGetGroupList(uid, gid, &groups); ++ if (ngroups < 0) ++ return -errno; ++ ++ pid = virFork(); ++ ++ if (pid < 0) { ++ ret = -errno; ++ VIR_FREE(groups); ++ return ret; ++ } ++ ++ if (pid) { /* parent */ ++ /* wait for child to complete, and retrieve its exit code */ ++ VIR_FREE(groups); ++ ++ while ((waitret = waitpid(pid, &status, 0)) == -1 && errno == EINTR); ++ if (waitret == -1) { ++ ret = -errno; ++ virReportSystemError(errno, ++ _("failed to wait for child unlinking '%s'"), ++ path); ++ goto parenterror; ++ } ++ ++ /* ++ * If waitpid succeeded, but if the child exited abnormally or ++ * reported non-zero status, report failure ++ */ ++ if (!WIFEXITED(status) || (WEXITSTATUS(status)) != 0) { ++ char *msg = virProcessTranslateStatus(status); ++ virReportError(VIR_ERR_INTERNAL_ERROR, ++ _("child failed to unlink '%s': %s"), ++ path, msg); ++ VIR_FREE(msg); ++ if (WIFEXITED(status)) ++ ret = -WEXITSTATUS(status); ++ else ++ ret = -EACCES; ++ } ++ ++ parenterror: ++ return ret; ++ } ++ ++ /* child */ ++ ++ /* set desired uid/gid, then attempt to unlink the file */ ++ if (virSetUIDGID(uid, gid, groups, ngroups) < 0) { ++ ret = errno; ++ goto childerror; ++ } ++ ++ if (unlink(path) < 0) { ++ ret = errno; ++ goto childerror; ++ } ++ ++ childerror: ++ if ((ret & 0xff) != ret) { ++ VIR_WARN("unable to pass desired return value %d", ret); ++ ret = 0xff; ++ } ++ _exit(ret); ++} ++ ++ + /* return -errno on failure, or 0 on success */ + static int + virDirCreateNoFork(const char *path, +diff --git a/src/util/virfile.h b/src/util/virfile.h +index 2d27e89..797ca65 100644 +--- a/src/util/virfile.h ++++ b/src/util/virfile.h +@@ -219,6 +219,7 @@ int virFileOpenAs(const char *path, int openflags, mode_t mode, + uid_t uid, gid_t gid, + unsigned int flags) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; ++int virFileUnlink(const char *path, uid_t uid, gid_t gid); + + enum { + VIR_DIR_CREATE_NONE = 0, +-- +2.1.4 + diff --git a/8b1d84e6-refreshVol-failure.patch b/8b1d84e6-refreshVol-failure.patch new file mode 100644 index 0000000..ca42d07 --- /dev/null +++ b/8b1d84e6-refreshVol-failure.patch @@ -0,0 +1,39 @@ +From 8b1d84e640f1a6e6ebb47caf23a664e2f651b32d Mon Sep 17 00:00:00 2001 +From: John Ferlan +Date: Mon, 24 Aug 2015 12:38:13 -0400 +Subject: [PATCH] storage: Handle failure from refreshVol + +Commit id '155ca616' added the 'refreshVol' API. In an NFS root-squash +environment it was possible that if the just created volume from XML wasn't +properly created with the right uid/gid and/or mode, then the followup +refreshVol will fail to open the volume in order to get the allocation/ +capacity values. This would leave the volume still on the server and +cause a libvirtd crash because 'voldef' would be in the pool list, but +the cleanup code would free it. + +(cherry picked from commit db9277a39bc364806e8d3e08a08fc128d59b7094) +--- + src/storage/storage_driver.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c +index ea7e0f3..0494e5d 100644 +--- a/src/storage/storage_driver.c ++++ b/src/storage/storage_driver.c +@@ -1867,8 +1867,12 @@ storageVolCreateXML(virStoragePoolPtr obj, + } + + if (backend->refreshVol && +- backend->refreshVol(obj->conn, pool, voldef) < 0) ++ backend->refreshVol(obj->conn, pool, voldef) < 0) { ++ storageVolDeleteInternal(volobj, backend, pool, voldef, ++ 0, false); ++ voldef = NULL; + goto cleanup; ++ } + + /* Update pool metadata ignoring the disk backend since + * it updates the pool values. +-- +2.1.4 + diff --git a/e0025d29-storage-mode-check.patch b/e0025d29-storage-mode-check.patch new file mode 100644 index 0000000..c4de908 --- /dev/null +++ b/e0025d29-storage-mode-check.patch @@ -0,0 +1,49 @@ +From e0025d2967bbe3f283937216c9e2c12b6e9d1010 Mon Sep 17 00:00:00 2001 +From: John Ferlan +Date: Mon, 24 Aug 2015 12:48:40 -0400 +Subject: [PATCH] storage: Correct the 'mode' check + +Commit id '7c2d65dde2' changed the default value of mode to be -1 if not +supplied in the XML, which should cause creation of the volume using the +default mode of VIR_STORAGE_DEFAULT_VOL_PERM_MODE; however, the check +made was whether mode was '0' or not to use default or provided value. + +This patch fixes the issue to check if the 'mode' was provided in the XML +and use that value. + +(cherry picked from commit 691dd388aee99f8b06177540303b690586d5f5b3) +--- + src/storage/storage_backend.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c +index 0418473..6a3146c 100644 +--- a/src/storage/storage_backend.c ++++ b/src/storage/storage_backend.c +@@ -486,6 +486,7 @@ virStorageBackendCreateRaw(virConnectPtr conn ATTRIBUTE_UNUSED, + int fd = -1; + int operation_flags; + bool reflink_copy = false; ++ mode_t open_mode = VIR_STORAGE_DEFAULT_VOL_PERM_MODE; + + virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA | + VIR_STORAGE_VOL_CREATE_REFLINK, +@@ -518,11 +519,12 @@ virStorageBackendCreateRaw(virConnectPtr conn ATTRIBUTE_UNUSED, + if (pool->def->type == VIR_STORAGE_POOL_NETFS) + operation_flags |= VIR_FILE_OPEN_FORK; + ++ if (vol->target.perms->mode != (mode_t) -1) ++ open_mode = vol->target.perms->mode; ++ + if ((fd = virFileOpenAs(vol->target.path, + O_RDWR | O_CREAT | O_EXCL, +- (vol->target.perms->mode ? +- VIR_STORAGE_DEFAULT_VOL_PERM_MODE : +- vol->target.perms->mode), ++ open_mode, + vol->target.perms->uid, + vol->target.perms->gid, + operation_flags)) < 0) { +-- +2.1.4 + diff --git a/libvirt.changes b/libvirt.changes index 33511d8..9e7a29d 100644 --- a/libvirt.changes +++ b/libvirt.changes @@ -1,3 +1,11 @@ +------------------------------------------------------------------- +Mon Sep 14 08:18:12 UTC 2015 - cbosdonnat@suse.com + +- CVE-2015-5247 - denial of service through root-squash NFS storage + 3468542f-virFileUnlink.patch + 8b1d84e6-refreshVol-failure.patch + e0025d29-storage-mode-check.patch + ------------------------------------------------------------------- Wed Sep 2 06:14:17 UTC 2015 - jfehlig@suse.com diff --git a/libvirt.spec b/libvirt.spec index 527a63e..d575602 100644 --- a/libvirt.spec +++ b/libvirt.spec @@ -1,7 +1,7 @@ # # spec file for package libvirt # -# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -446,6 +446,9 @@ Source3: libvirtd.init Source4: libvirtd-relocation-server.fw Source99: baselibs.conf # Upstream patches +Patch0: 3468542f-virFileUnlink.patch +Patch1: 8b1d84e6-refreshVol-failure.patch +Patch2: e0025d29-storage-mode-check.patch # Patches pending upstream review # Need to go upstream Patch150: xen-pv-cdrom.patch @@ -976,6 +979,9 @@ Provides a dissector for the libvirt RPC protocol to help debugging it. %prep %setup -q +%patch0 -p1 +%patch1 -p1 +%patch2 -p1 %patch150 -p1 %patch151 -p1 %patch152 -p1