]> git.proxmox.com Git - pve-qemu.git/blame - debian/patches/extra/0015-9pfs-local-forbid-client-access-to-metadata-CVE-2017.patch
bump version to 2.9.0-5
[pve-qemu.git] / debian / patches / extra / 0015-9pfs-local-forbid-client-access-to-metadata-CVE-2017.patch
CommitLineData
e74c0f31 1From 209fb3054000bd3a45da63e3758b9c220fba0a25 Mon Sep 17 00:00:00 2001
90a6d957
WB
2From: Greg Kurz <groug@kaod.org>
3Date: Fri, 5 May 2017 14:48:08 +0200
e74c0f31 4Subject: [PATCH 15/23] 9pfs: local: forbid client access to metadata
90a6d957
WB
5 (CVE-2017-7493)
6
7When using the mapped-file security mode, we shouldn't let the client mess
8with the metadata. The current code already tries to hide the metadata dir
9from the client by skipping it in local_readdir(). But the client can still
10access or modify it through several other operations. This can be used to
11escalate privileges in the guest.
12
13Affected backend operations are:
14- local_mknod()
15- local_mkdir()
16- local_open2()
17- local_symlink()
18- local_link()
19- local_unlinkat()
20- local_renameat()
21- local_rename()
22- local_name_to_path()
23
24Other operations are safe because they are only passed a fid path, which
25is computed internally in local_name_to_path().
26
27This patch converts all the functions listed above to fail and return
28EINVAL when being passed the name of the metadata dir. This may look
29like a poor choice for errno, but there's no such thing as an illegal
30path name on Linux and I could not think of anything better.
31
32This fixes CVE-2017-7493.
33
34Reported-by: Leo Gaspard <leo@gaspard.io>
35Signed-off-by: Greg Kurz <groug@kaod.org>
36Reviewed-by: Eric Blake <eblake@redhat.com>
37---
38 hw/9pfs/9p-local.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
39 1 file changed, 56 insertions(+), 2 deletions(-)
40
41diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
42index 7a0c383e7e..226234d386 100644
43--- a/hw/9pfs/9p-local.c
44+++ b/hw/9pfs/9p-local.c
45@@ -452,6 +452,11 @@ static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs)
46 return telldir(fs->dir.stream);
47 }
48
49+static bool local_is_mapped_file_metadata(FsContext *fs_ctx, const char *name)
50+{
51+ return !strcmp(name, VIRTFS_META_DIR);
52+}
53+
54 static struct dirent *local_readdir(FsContext *ctx, V9fsFidOpenState *fs)
55 {
56 struct dirent *entry;
57@@ -465,8 +470,8 @@ again:
58 if (ctx->export_flags & V9FS_SM_MAPPED) {
59 entry->d_type = DT_UNKNOWN;
60 } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
61- if (!strcmp(entry->d_name, VIRTFS_META_DIR)) {
62- /* skp the meta data directory */
63+ if (local_is_mapped_file_metadata(ctx, entry->d_name)) {
64+ /* skip the meta data directory */
65 goto again;
66 }
67 entry->d_type = DT_UNKNOWN;
68@@ -559,6 +564,12 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
69 int err = -1;
70 int dirfd;
71
72+ if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
73+ local_is_mapped_file_metadata(fs_ctx, name)) {
74+ errno = EINVAL;
75+ return -1;
76+ }
77+
78 dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
79 if (dirfd == -1) {
80 return -1;
81@@ -605,6 +616,12 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
82 int err = -1;
83 int dirfd;
84
85+ if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
86+ local_is_mapped_file_metadata(fs_ctx, name)) {
87+ errno = EINVAL;
88+ return -1;
89+ }
90+
91 dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
92 if (dirfd == -1) {
93 return -1;
94@@ -694,6 +711,12 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
95 int err = -1;
96 int dirfd;
97
98+ if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
99+ local_is_mapped_file_metadata(fs_ctx, name)) {
100+ errno = EINVAL;
101+ return -1;
102+ }
103+
104 /*
105 * Mark all the open to not follow symlinks
106 */
107@@ -752,6 +775,12 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
108 int err = -1;
109 int dirfd;
110
111+ if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
112+ local_is_mapped_file_metadata(fs_ctx, name)) {
113+ errno = EINVAL;
114+ return -1;
115+ }
116+
117 dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
118 if (dirfd == -1) {
119 return -1;
120@@ -826,6 +855,12 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
121 int ret = -1;
122 int odirfd, ndirfd;
123
124+ if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
125+ local_is_mapped_file_metadata(ctx, name)) {
126+ errno = EINVAL;
127+ return -1;
128+ }
129+
130 odirfd = local_opendir_nofollow(ctx, odirpath);
131 if (odirfd == -1) {
132 goto out;
133@@ -1092,6 +1127,12 @@ static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
134 static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
135 const char *name, V9fsPath *target)
136 {
137+ if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
138+ local_is_mapped_file_metadata(ctx, name)) {
139+ errno = EINVAL;
140+ return -1;
141+ }
142+
143 if (dir_path) {
144 v9fs_path_sprintf(target, "%s/%s", dir_path->data, name);
145 } else if (strcmp(name, "/")) {
146@@ -1112,6 +1153,13 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
147 int ret;
148 int odirfd, ndirfd;
149
150+ if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
151+ (local_is_mapped_file_metadata(ctx, old_name) ||
152+ local_is_mapped_file_metadata(ctx, new_name))) {
153+ errno = EINVAL;
154+ return -1;
155+ }
156+
157 odirfd = local_opendir_nofollow(ctx, olddir->data);
158 if (odirfd == -1) {
159 return -1;
160@@ -1202,6 +1250,12 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
161 int ret;
162 int dirfd;
163
164+ if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
165+ local_is_mapped_file_metadata(ctx, name)) {
166+ errno = EINVAL;
167+ return -1;
168+ }
169+
170 dirfd = local_opendir_nofollow(ctx, dir->data);
171 if (dirfd == -1) {
172 return -1;
173--
1742.11.0
175