From 19556f7295b8390966e91f75f31c46fc7d0511072fd892f8b7550858c27427bc Mon Sep 17 00:00:00 2001 From: Bruce Rogers Date: Mon, 22 May 2017 20:33:55 +0000 Subject: [PATCH] Accepting request 497385 from home:bfrogers:branches:Virtualization One more security fix. OBS-URL: https://build.opensuse.org/request/show/497385 OBS-URL: https://build.opensuse.org/package/show/Virtualization/qemu?expand=0&rev=340 --- ...-9pfs-local-forbid-client-access-to-.patch | 174 ++++++++++++++++++ qemu-linux-user.changes | 7 + qemu-linux-user.spec | 2 + qemu-testsuite.changes | 7 + qemu-testsuite.spec | 2 + qemu.changes | 7 + qemu.spec | 2 + 7 files changed, 201 insertions(+) create mode 100644 0055-9pfs-local-forbid-client-access-to-.patch diff --git a/0055-9pfs-local-forbid-client-access-to-.patch b/0055-9pfs-local-forbid-client-access-to-.patch new file mode 100644 index 0000000..cc68364 --- /dev/null +++ b/0055-9pfs-local-forbid-client-access-to-.patch @@ -0,0 +1,174 @@ +From 385fd07f1627cb73ed2ad266e23923cb7eae30f7 Mon Sep 17 00:00:00 2001 +From: Greg Kurz +Date: Fri, 5 May 2017 14:48:08 +0200 +Subject: [PATCH] 9pfs: local: forbid client access to metadata (CVE-2017-7493) + +When using the mapped-file security mode, we shouldn't let the client mess +with the metadata. The current code already tries to hide the metadata dir +from the client by skipping it in local_readdir(). But the client can still +access or modify it through several other operations. This can be used to +escalate privileges in the guest. + +Affected backend operations are: +- local_mknod() +- local_mkdir() +- local_open2() +- local_symlink() +- local_link() +- local_unlinkat() +- local_renameat() +- local_rename() +- local_name_to_path() + +Other operations are safe because they are only passed a fid path, which +is computed internally in local_name_to_path(). + +This patch converts all the functions listed above to fail and return +EINVAL when being passed the name of the metadata dir. This may look +like a poor choice for errno, but there's no such thing as an illegal +path name on Linux and I could not think of anything better. + +This fixes CVE-2017-7493. + +Reported-by: Leo Gaspard +Signed-off-by: Greg Kurz +Reviewed-by: Eric Blake +(cherry picked from commit 7a95434e0ca8a037fd8aa1a2e2461f92585eb77b) +[BR: BSC#1039495] +Signed-off-by: Bruce Rogers +--- + hw/9pfs/9p-local.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 56 insertions(+), 2 deletions(-) + +diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c +index f3ebca4f7a..a2486566af 100644 +--- a/hw/9pfs/9p-local.c ++++ b/hw/9pfs/9p-local.c +@@ -452,6 +452,11 @@ static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs) + return telldir(fs->dir.stream); + } + ++static bool local_is_mapped_file_metadata(FsContext *fs_ctx, const char *name) ++{ ++ return !strcmp(name, VIRTFS_META_DIR); ++} ++ + static struct dirent *local_readdir(FsContext *ctx, V9fsFidOpenState *fs) + { + struct dirent *entry; +@@ -465,8 +470,8 @@ again: + if (ctx->export_flags & V9FS_SM_MAPPED) { + entry->d_type = DT_UNKNOWN; + } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { +- if (!strcmp(entry->d_name, VIRTFS_META_DIR)) { +- /* skp the meta data directory */ ++ if (local_is_mapped_file_metadata(ctx, entry->d_name)) { ++ /* skip the meta data directory */ + goto again; + } + entry->d_type = DT_UNKNOWN; +@@ -559,6 +564,12 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, + int err = -1; + int dirfd; + ++ if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE && ++ local_is_mapped_file_metadata(fs_ctx, name)) { ++ errno = EINVAL; ++ return -1; ++ } ++ + dirfd = local_opendir_nofollow(fs_ctx, dir_path->data); + if (dirfd == -1) { + return -1; +@@ -605,6 +616,12 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, + int err = -1; + int dirfd; + ++ if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE && ++ local_is_mapped_file_metadata(fs_ctx, name)) { ++ errno = EINVAL; ++ return -1; ++ } ++ + dirfd = local_opendir_nofollow(fs_ctx, dir_path->data); + if (dirfd == -1) { + return -1; +@@ -694,6 +711,12 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, + int err = -1; + int dirfd; + ++ if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE && ++ local_is_mapped_file_metadata(fs_ctx, name)) { ++ errno = EINVAL; ++ return -1; ++ } ++ + /* + * Mark all the open to not follow symlinks + */ +@@ -752,6 +775,12 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, + int err = -1; + int dirfd; + ++ if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE && ++ local_is_mapped_file_metadata(fs_ctx, name)) { ++ errno = EINVAL; ++ return -1; ++ } ++ + dirfd = local_opendir_nofollow(fs_ctx, dir_path->data); + if (dirfd == -1) { + return -1; +@@ -826,6 +855,12 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath, + int ret = -1; + int odirfd, ndirfd; + ++ if (ctx->export_flags & V9FS_SM_MAPPED_FILE && ++ local_is_mapped_file_metadata(ctx, name)) { ++ errno = EINVAL; ++ return -1; ++ } ++ + odirfd = local_opendir_nofollow(ctx, odirpath); + if (odirfd == -1) { + goto out; +@@ -1096,6 +1131,12 @@ static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path, + static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path, + const char *name, V9fsPath *target) + { ++ if (ctx->export_flags & V9FS_SM_MAPPED_FILE && ++ local_is_mapped_file_metadata(ctx, name)) { ++ errno = EINVAL; ++ return -1; ++ } ++ + if (dir_path) { + v9fs_path_sprintf(target, "%s/%s", dir_path->data, name); + } else if (strcmp(name, "/")) { +@@ -1116,6 +1157,13 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir, + int ret; + int odirfd, ndirfd; + ++ if (ctx->export_flags & V9FS_SM_MAPPED_FILE && ++ (local_is_mapped_file_metadata(ctx, old_name) || ++ local_is_mapped_file_metadata(ctx, new_name))) { ++ errno = EINVAL; ++ return -1; ++ } ++ + odirfd = local_opendir_nofollow(ctx, olddir->data); + if (odirfd == -1) { + return -1; +@@ -1206,6 +1254,12 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir, + int ret; + int dirfd; + ++ if (ctx->export_flags & V9FS_SM_MAPPED_FILE && ++ local_is_mapped_file_metadata(ctx, name)) { ++ errno = EINVAL; ++ return -1; ++ } ++ + dirfd = local_opendir_nofollow(ctx, dir->data); + if (dirfd == -1) { + return -1; diff --git a/qemu-linux-user.changes b/qemu-linux-user.changes index a1aad42..348e500 100644 --- a/qemu-linux-user.changes +++ b/qemu-linux-user.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Mon May 22 19:06:25 UTC 2017 - brogers@suse.com + +- Patch queue updated from git://github.com/openSUSE/qemu.git opensuse-2.9 +* Patches added: + 0055-9pfs-local-forbid-client-access-to-.patch + ------------------------------------------------------------------- Thu May 11 20:55:59 UTC 2017 - brogers@suse.com diff --git a/qemu-linux-user.spec b/qemu-linux-user.spec index bb38945..f1a1ab1 100644 --- a/qemu-linux-user.spec +++ b/qemu-linux-user.spec @@ -80,6 +80,7 @@ Patch0051: 0051-input-limit-kbd-queue-depth.patch Patch0052: 0052-audio-release-capture-buffers.patch Patch0053: 0053-scsi-avoid-an-off-by-one-error-in-m.patch Patch0054: 0054-vmw_pvscsi-check-message-ring-page-.patch +Patch0055: 0055-9pfs-local-forbid-client-access-to-.patch # Please do not add QEMU patches manually here. # Run update_git.sh to regenerate this queue. Source400: update_git.sh @@ -187,6 +188,7 @@ run cross-architecture builds. %patch0052 -p1 %patch0053 -p1 %patch0054 -p1 +%patch0055 -p1 %build ./configure \ diff --git a/qemu-testsuite.changes b/qemu-testsuite.changes index 468180e..f7c3ed7 100644 --- a/qemu-testsuite.changes +++ b/qemu-testsuite.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Mon May 22 19:06:22 UTC 2017 - brogers@suse.com + +- Protect access to metadata in virtio-9pfs (CVE-2017-7493 bsc#1039495) + 0055-9pfs-local-forbid-client-access-to-.patch +- Patch queue updated from git://github.com/openSUSE/qemu.git opensuse-2.9 + ------------------------------------------------------------------- Thu May 11 20:55:57 UTC 2017 - brogers@suse.com diff --git a/qemu-testsuite.spec b/qemu-testsuite.spec index 2d63903..abe88ae 100644 --- a/qemu-testsuite.spec +++ b/qemu-testsuite.spec @@ -184,6 +184,7 @@ Patch0051: 0051-input-limit-kbd-queue-depth.patch Patch0052: 0052-audio-release-capture-buffers.patch Patch0053: 0053-scsi-avoid-an-off-by-one-error-in-m.patch Patch0054: 0054-vmw_pvscsi-check-message-ring-page-.patch +Patch0055: 0055-9pfs-local-forbid-client-access-to-.patch # Please do not add QEMU patches manually here. # Run update_git.sh to regenerate this queue. @@ -884,6 +885,7 @@ This package provides a service file for starting and stopping KSM. %patch0052 -p1 %patch0053 -p1 %patch0054 -p1 +%patch0055 -p1 pushd roms/ipxe %patch1100 -p1 diff --git a/qemu.changes b/qemu.changes index 468180e..f7c3ed7 100644 --- a/qemu.changes +++ b/qemu.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Mon May 22 19:06:22 UTC 2017 - brogers@suse.com + +- Protect access to metadata in virtio-9pfs (CVE-2017-7493 bsc#1039495) + 0055-9pfs-local-forbid-client-access-to-.patch +- Patch queue updated from git://github.com/openSUSE/qemu.git opensuse-2.9 + ------------------------------------------------------------------- Thu May 11 20:55:57 UTC 2017 - brogers@suse.com diff --git a/qemu.spec b/qemu.spec index 2235491..759da0e 100644 --- a/qemu.spec +++ b/qemu.spec @@ -184,6 +184,7 @@ Patch0051: 0051-input-limit-kbd-queue-depth.patch Patch0052: 0052-audio-release-capture-buffers.patch Patch0053: 0053-scsi-avoid-an-off-by-one-error-in-m.patch Patch0054: 0054-vmw_pvscsi-check-message-ring-page-.patch +Patch0055: 0055-9pfs-local-forbid-client-access-to-.patch # Please do not add QEMU patches manually here. # Run update_git.sh to regenerate this queue. @@ -884,6 +885,7 @@ This package provides a service file for starting and stopping KSM. %patch0052 -p1 %patch0053 -p1 %patch0054 -p1 +%patch0055 -p1 pushd roms/ipxe %patch1100 -p1