From 024851fa3a1ded52dbb6fb1bf228edac8145a532 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 23 Jan 2016 22:48:19 +0000 Subject: [PATCH] fuse: break infinite loop in fuse_fill_write_pages() This doesn't have a CVE ID yet. --- debian/changelog | 3 + ...finite-loop-in-fuse_fill_write_pages.patch | 56 +++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 60 insertions(+) create mode 100644 debian/patches/bugfix/all/fuse-break-infinite-loop-in-fuse_fill_write_pages.patch diff --git a/debian/changelog b/debian/changelog index 7d35ae95b..914e3b752 100644 --- a/debian/changelog +++ b/debian/changelog @@ -51,6 +51,9 @@ linux (4.3.4-1) UNRELEASED; urgency=medium - tcp: restore fastopen with no data in SYN packet - rhashtable: Fix walker list corruption + [ Ben Hutchings ] + * fuse: break infinite loop in fuse_fill_write_pages() (CVE-2015-XXXX) + -- Ben Hutchings Sat, 23 Jan 2016 11:51:46 +0000 linux (4.3.3-7) unstable; urgency=medium diff --git a/debian/patches/bugfix/all/fuse-break-infinite-loop-in-fuse_fill_write_pages.patch b/debian/patches/bugfix/all/fuse-break-infinite-loop-in-fuse_fill_write_pages.patch new file mode 100644 index 000000000..3c67f75ea --- /dev/null +++ b/debian/patches/bugfix/all/fuse-break-infinite-loop-in-fuse_fill_write_pages.patch @@ -0,0 +1,56 @@ +From: Roman Gushchin +Date: Mon, 12 Oct 2015 16:33:44 +0300 +Subject: fuse: break infinite loop in fuse_fill_write_pages() +Origin: https://git.kernel.org/linus/3ca8138f014a913f98e6ef40e939868e1e9ea876 + +I got a report about unkillable task eating CPU. Further +investigation shows, that the problem is in the fuse_fill_write_pages() +function. If iov's first segment has zero length, we get an infinite +loop, because we never reach iov_iter_advance() call. + +Fix this by calling iov_iter_advance() before repeating an attempt to +copy data from userspace. + +A similar problem is described in 124d3b7041f ("fix writev regression: +pan hanging unkillable and un-straceable"). If zero-length segmend +is followed by segment with invalid address, +iov_iter_fault_in_readable() checks only first segment (zero-length), +iov_iter_copy_from_user_atomic() skips it, fails at second and +returns zero -> goto again without skipping zero-length segment. + +Patch calls iov_iter_advance() before goto again: we'll skip zero-length +segment at second iteraction and iov_iter_fault_in_readable() will detect +invalid address. + +Special thanks to Konstantin Khlebnikov, who helped a lot with the commit +description. + +Cc: Andrew Morton +Cc: Maxim Patlasov +Cc: Konstantin Khlebnikov +Signed-off-by: Roman Gushchin +Signed-off-by: Miklos Szeredi +Fixes: ea9b9907b82a ("fuse: implement perform_write") +Signed-off-by: Ben Hutchings +--- + fs/fuse/file.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -1049,6 +1049,7 @@ static ssize_t fuse_fill_write_pages(str + tmp = iov_iter_copy_from_user_atomic(page, ii, offset, bytes); + flush_dcache_page(page); + ++ iov_iter_advance(ii, tmp); + if (!tmp) { + unlock_page(page); + page_cache_release(page); +@@ -1061,7 +1062,6 @@ static ssize_t fuse_fill_write_pages(str + req->page_descs[req->num_pages].length = tmp; + req->num_pages++; + +- iov_iter_advance(ii, tmp); + count += tmp; + pos += tmp; + offset += tmp; diff --git a/debian/patches/series b/debian/patches/series index 725582e07..94af25d11 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -140,3 +140,4 @@ bugfix/all/bcache-unregister-reboot-notifier-if-bcache-fails-to.patch bugfix/all/bcache-allows-use-of-register-in-udev-to-avoid-devic.patch bugfix/all/bcache-prevent-crash-on-changing-writeback_running.patch bugfix/all/bcache-change-refill_dirty-to-always-scan-entire-dis.patch +bugfix/all/fuse-break-infinite-loop-in-fuse_fill_write_pages.patch