]> git.proxmox.com Git - pve-qemu.git/blob - debian/patches/extra/0015-9pfs-local-forbid-client-access-to-metadata-CVE-2017.patch
merge various stable fixes
[pve-qemu.git] / debian / patches / extra / 0015-9pfs-local-forbid-client-access-to-metadata-CVE-2017.patch
1 From 6364ef68ee01ec566617ffa6982a8d551cec0f75 Mon Sep 17 00:00:00 2001
2 From: Greg Kurz <groug@kaod.org>
3 Date: Fri, 5 May 2017 14:48:08 +0200
4 Subject: [PATCH 15/15] 9pfs: local: forbid client access to metadata
5 (CVE-2017-7493)
6
7 When using the mapped-file security mode, we shouldn't let the client mess
8 with the metadata. The current code already tries to hide the metadata dir
9 from the client by skipping it in local_readdir(). But the client can still
10 access or modify it through several other operations. This can be used to
11 escalate privileges in the guest.
12
13 Affected 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
24 Other operations are safe because they are only passed a fid path, which
25 is computed internally in local_name_to_path().
26
27 This patch converts all the functions listed above to fail and return
28 EINVAL when being passed the name of the metadata dir. This may look
29 like a poor choice for errno, but there's no such thing as an illegal
30 path name on Linux and I could not think of anything better.
31
32 This fixes CVE-2017-7493.
33
34 Reported-by: Leo Gaspard <leo@gaspard.io>
35 Signed-off-by: Greg Kurz <groug@kaod.org>
36 Reviewed-by: Eric Blake <eblake@redhat.com>
37 ---
38 hw/9pfs/9p-local.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
39 1 file changed, 56 insertions(+), 2 deletions(-)
40
41 diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
42 index 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 --
174 2.11.0
175