]> git.proxmox.com Git - pve-qemu.git/blob - debian/patches/extra/0004-9pfs-local-fix-unlink-of-alien-files-in-mapped-file-.patch
merge various stable fixes
[pve-qemu.git] / debian / patches / extra / 0004-9pfs-local-fix-unlink-of-alien-files-in-mapped-file-.patch
1 From 575b9657b84e7c35d4a378448cdb43939fb5e730 Mon Sep 17 00:00:00 2001
2 From: Greg Kurz <groug@kaod.org>
3 Date: Thu, 25 May 2017 10:30:13 +0200
4 Subject: [PATCH 04/15] 9pfs: local: fix unlink of alien files in mapped-file
5 mode
6
7 When trying to remove a file from a directory, both created in non-mapped
8 mode, the file remains and EBADF is returned to the guest.
9
10 This is a regression introduced by commit "df4938a6651b 9pfs: local:
11 unlinkat: don't follow symlinks" when fixing CVE-2016-9602. It changed the
12 way we unlink the metadata file from
13
14 ret = remove("$dir/.virtfs_metadata/$name");
15 if (ret < 0 && errno != ENOENT) {
16 /* Error out */
17 }
18 /* Ignore absence of metadata */
19
20 to
21
22 fd = openat("$dir/.virtfs_metadata")
23 unlinkat(fd, "$name")
24 if (ret < 0 && errno != ENOENT) {
25 /* Error out */
26 }
27 /* Ignore absence of metadata */
28
29 If $dir was created in non-mapped mode, openat() fails with ENOENT and
30 we pass -1 to unlinkat(), which fails in turn with EBADF.
31
32 We just need to check the return of openat() and ignore ENOENT, in order
33 to restore the behaviour we had with remove().
34
35 Signed-off-by: Greg Kurz <groug@kaod.org>
36 Reviewed-by: Eric Blake <eblake@redhat.com>
37 [groug: rewrote the comments as suggested by Eric]
38 ---
39 hw/9pfs/9p-local.c | 34 +++++++++++++++-------------------
40 1 file changed, 15 insertions(+), 19 deletions(-)
41
42 diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
43 index f3ebca4f7a..7a0c383e7e 100644
44 --- a/hw/9pfs/9p-local.c
45 +++ b/hw/9pfs/9p-local.c
46 @@ -957,6 +957,14 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
47 if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
48 int map_dirfd;
49
50 + /* We need to remove the metadata as well:
51 + * - the metadata directory if we're removing a directory
52 + * - the metadata file in the parent's metadata directory
53 + *
54 + * If any of these are missing (ie, ENOENT) then we're probably
55 + * trying to remove something that wasn't created in mapped-file
56 + * mode. We just ignore the error.
57 + */
58 if (flags == AT_REMOVEDIR) {
59 int fd;
60
61 @@ -964,32 +972,20 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
62 if (fd == -1) {
63 goto err_out;
64 }
65 - /*
66 - * If directory remove .virtfs_metadata contained in the
67 - * directory
68 - */
69 ret = unlinkat(fd, VIRTFS_META_DIR, AT_REMOVEDIR);
70 close_preserve_errno(fd);
71 if (ret < 0 && errno != ENOENT) {
72 - /*
73 - * We didn't had the .virtfs_metadata file. May be file created
74 - * in non-mapped mode ?. Ignore ENOENT.
75 - */
76 goto err_out;
77 }
78 }
79 - /*
80 - * Now remove the name from parent directory
81 - * .virtfs_metadata directory.
82 - */
83 map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR);
84 - ret = unlinkat(map_dirfd, name, 0);
85 - close_preserve_errno(map_dirfd);
86 - if (ret < 0 && errno != ENOENT) {
87 - /*
88 - * We didn't had the .virtfs_metadata file. May be file created
89 - * in non-mapped mode ?. Ignore ENOENT.
90 - */
91 + if (map_dirfd != -1) {
92 + ret = unlinkat(map_dirfd, name, 0);
93 + close_preserve_errno(map_dirfd);
94 + if (ret < 0 && errno != ENOENT) {
95 + goto err_out;
96 + }
97 + } else if (errno != ENOENT) {
98 goto err_out;
99 }
100 }
101 --
102 2.11.0
103