ext4: allocate entire range in zero range (CVE-2015-0275)
plus earlier fixes for this function that it depends on svn path=/dists/sid/linux/; revision=22473
This commit is contained in:
parent
a1a7477708
commit
999727f3c9
|
@ -181,6 +181,9 @@ linux (3.16.7-ckt9-1) UNRELEASED; urgency=medium
|
|||
* IB/core: Prevent integer overflow in ib_umem_get address arithmetic
|
||||
(CVE-2014-8159)
|
||||
* Btrfs: make xattr replace operations atomic (CVE-2014-9710)
|
||||
* ext4: fix ZERO_RANGE bug hidden by flag aliasing
|
||||
* ext4: fix accidental flag aliasing in ext4_map_blocks flags
|
||||
* ext4: allocate entire range in zero range (CVE-2015-0275)
|
||||
|
||||
-- Ian Campbell <ijc@debian.org> Wed, 18 Mar 2015 21:07:15 +0000
|
||||
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
From: Lukas Czerner <lczerner@redhat.com>
|
||||
Date: Fri, 3 Apr 2015 00:09:13 -0400
|
||||
Subject: ext4: allocate entire range in zero range
|
||||
Origin: https://git.kernel.org/cgit/linux/kernel/git/tytso/ext4.git/commit/?id=0f2af21aae11972fa924374ddcf52e88347cf5a8
|
||||
|
||||
Currently there is a bug in zero range code which causes zero range
|
||||
calls to only allocate block aligned portion of the range, while
|
||||
ignoring the rest in some cases.
|
||||
|
||||
In some cases, namely if the end of the range is past i_size, we do
|
||||
attempt to preallocate the last nonaligned block. However this might
|
||||
cause kernel to BUG() in some carefully designed zero range requests
|
||||
on setups where page size > block size.
|
||||
|
||||
Fix this problem by first preallocating the entire range, including
|
||||
the nonaligned edges and converting the written extents to unwritten
|
||||
in the next step. This approach will also give us the advantage of
|
||||
having the range to be as linearly contiguous as possible.
|
||||
|
||||
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
|
||||
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
||||
---
|
||||
--- a/fs/ext4/extents.c
|
||||
+++ b/fs/ext4/extents.c
|
||||
@@ -4795,12 +4795,6 @@ static long ext4_zero_range(struct file
|
||||
else
|
||||
max_blocks -= lblk;
|
||||
|
||||
- flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT |
|
||||
- EXT4_GET_BLOCKS_CONVERT_UNWRITTEN |
|
||||
- EXT4_EX_NOCACHE;
|
||||
- if (mode & FALLOC_FL_KEEP_SIZE)
|
||||
- flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
|
||||
-
|
||||
mutex_lock(&inode->i_mutex);
|
||||
|
||||
/*
|
||||
@@ -4817,15 +4811,28 @@ static long ext4_zero_range(struct file
|
||||
ret = inode_newsize_ok(inode, new_size);
|
||||
if (ret)
|
||||
goto out_mutex;
|
||||
- /*
|
||||
- * If we have a partial block after EOF we have to allocate
|
||||
- * the entire block.
|
||||
- */
|
||||
- if (partial_end)
|
||||
- max_blocks += 1;
|
||||
}
|
||||
|
||||
+ flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT;
|
||||
+ if (mode & FALLOC_FL_KEEP_SIZE)
|
||||
+ flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
|
||||
+
|
||||
+ /* Preallocate the range including the unaligned edges */
|
||||
+ if (partial_begin || partial_end) {
|
||||
+ ret = ext4_alloc_file_blocks(file,
|
||||
+ round_down(offset, 1 << blkbits) >> blkbits,
|
||||
+ (round_up((offset + len), 1 << blkbits) -
|
||||
+ round_down(offset, 1 << blkbits)) >> blkbits,
|
||||
+ new_size, flags, mode);
|
||||
+ if (ret)
|
||||
+ goto out_mutex;
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ /* Zero range excluding the unaligned edges */
|
||||
if (max_blocks > 0) {
|
||||
+ flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN |
|
||||
+ EXT4_EX_NOCACHE);
|
||||
|
||||
/* Now release the pages and zero block aligned part of pages*/
|
||||
truncate_pagecache_range(inode, start, end - 1);
|
40
debian/patches/bugfix/all/ext4-fix-accidental-flag-aliasing-in-ext4_map_blocks.patch
vendored
Normal file
40
debian/patches/bugfix/all/ext4-fix-accidental-flag-aliasing-in-ext4_map_blocks.patch
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
From: Theodore Ts'o <tytso@mit.edu>
|
||||
Date: Mon, 1 Sep 2014 14:33:09 -0400
|
||||
Subject: [2/2] ext4: fix accidental flag aliasing in ext4_map_blocks flags
|
||||
Origin: https://git.kernel.org/linus/bd30d702fc320085f178d22866b32fdc4736c991
|
||||
|
||||
Commit b8a8684502a0f introduced an accidental flag aliasing between
|
||||
EXT4_EX_NOCACHE and EXT4_GET_BLOCKS_CONVERT_UNWRITTEN.
|
||||
|
||||
Fortunately, this didn't introduce any untorward side effects --- we
|
||||
got lucky. Nevertheless, fix this and leave a warning to hopefully
|
||||
avoid this from happening in the future.
|
||||
|
||||
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
||||
---
|
||||
fs/ext4/ext4.h | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
|
||||
index cf3ad75..550b4f9 100644
|
||||
--- a/fs/ext4/ext4.h
|
||||
+++ b/fs/ext4/ext4.h
|
||||
@@ -569,6 +569,7 @@ enum {
|
||||
#define EXT4_GET_BLOCKS_NO_PUT_HOLE 0x0200
|
||||
/* Convert written extents to unwritten */
|
||||
#define EXT4_GET_BLOCKS_CONVERT_UNWRITTEN 0x0400
|
||||
+/* DO NOT ASSIGN ADDITIONAL FLAG VALUES WITHOUT ADJUSTING THE FLAGS BELOW */
|
||||
|
||||
/*
|
||||
* The bit position of these flags must not overlap with any of the
|
||||
@@ -579,8 +580,8 @@ enum {
|
||||
* caching the extents when reading from the extent tree while a
|
||||
* truncate or punch hole operation is in progress.
|
||||
*/
|
||||
-#define EXT4_EX_NOCACHE 0x0400
|
||||
-#define EXT4_EX_FORCE_CACHE 0x0800
|
||||
+#define EXT4_EX_NOCACHE 0x0800
|
||||
+#define EXT4_EX_FORCE_CACHE 0x1000
|
||||
|
||||
/*
|
||||
* Flags used by ext4_free_blocks
|
66
debian/patches/bugfix/all/ext4-fix-zero_range-bug-hidden-by-flag-aliasing.patch
vendored
Normal file
66
debian/patches/bugfix/all/ext4-fix-zero_range-bug-hidden-by-flag-aliasing.patch
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
From: Theodore Ts'o <tytso@mit.edu>
|
||||
Date: Mon, 1 Sep 2014 14:32:09 -0400
|
||||
Subject: [1/2] ext4: fix ZERO_RANGE bug hidden by flag aliasing
|
||||
Origin: https://git.kernel.org/linus/713e8dde3e71e92db2d8cc8459d236ce1fb576ce
|
||||
|
||||
We accidently aliased EXT4_EX_NOCACHE and EXT4_GET_CONVERT_UNWRITTEN
|
||||
falgs, which apparently was hiding a bug that was unmasked when this
|
||||
flag aliasing issue was addressed (see the subsequent commit). The
|
||||
reproduction case was:
|
||||
|
||||
fsx -N 10000 -l 500000 -r 4096 -t 4096 -w 4096 -Z -R -W /vdb/junk
|
||||
|
||||
... which would cause fsx to report corruption in the data file.
|
||||
|
||||
The fix we have is a bit of an overkill, but I'd much rather be
|
||||
conservative for now, and we can optimize ZERO_RANGE_FL handling
|
||||
later. The fact that we need to zap the extent_status cache for the
|
||||
inode is unfortunate, but correctness is far more important than
|
||||
performance.
|
||||
|
||||
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
||||
Cc: Namjae Jeon <namjae.jeon@samsung.com>
|
||||
---
|
||||
fs/ext4/extents.c | 21 ++++++++++++++-------
|
||||
1 file changed, 14 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/fs/ext4/extents.c
|
||||
+++ b/fs/ext4/extents.c
|
||||
@@ -4796,7 +4796,8 @@ static long ext4_zero_range(struct file
|
||||
max_blocks -= lblk;
|
||||
|
||||
flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT |
|
||||
- EXT4_GET_BLOCKS_CONVERT_UNWRITTEN;
|
||||
+ EXT4_GET_BLOCKS_CONVERT_UNWRITTEN |
|
||||
+ EXT4_EX_NOCACHE;
|
||||
if (mode & FALLOC_FL_KEEP_SIZE)
|
||||
flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
|
||||
|
||||
@@ -4834,15 +4835,21 @@ static long ext4_zero_range(struct file
|
||||
ext4_inode_block_unlocked_dio(inode);
|
||||
inode_dio_wait(inode);
|
||||
|
||||
+ ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size,
|
||||
+ flags, mode);
|
||||
+ if (ret)
|
||||
+ goto out_dio;
|
||||
/*
|
||||
* Remove entire range from the extent status tree.
|
||||
+ *
|
||||
+ * ext4_es_remove_extent(inode, lblk, max_blocks) is
|
||||
+ * NOT sufficient. I'm not sure why this is the case,
|
||||
+ * but let's be conservative and remove the extent
|
||||
+ * status tree for the entire inode. There should be
|
||||
+ * no outstanding delalloc extents thanks to the
|
||||
+ * filemap_write_and_wait_range() call above.
|
||||
*/
|
||||
- ret = ext4_es_remove_extent(inode, lblk, max_blocks);
|
||||
- if (ret)
|
||||
- goto out_dio;
|
||||
-
|
||||
- ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size,
|
||||
- flags, mode);
|
||||
+ ret = ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS);
|
||||
if (ret)
|
||||
goto out_dio;
|
||||
}
|
|
@ -557,3 +557,6 @@ debian/usb-avoid-abi-change-in-3.16.7-ckt8.patch
|
|||
|
||||
bugfix/all/ib-core-prevent-integer-overflow-in-ib_umem_get.patch
|
||||
bugfix/all/btrfs-make-xattr-replace-operations-atomic.patch
|
||||
bugfix/all/ext4-fix-zero_range-bug-hidden-by-flag-aliasing.patch
|
||||
bugfix/all/ext4-fix-accidental-flag-aliasing-in-ext4_map_blocks.patch
|
||||
bugfix/all/ext4-allocate-entire-range-in-zero-range.patch
|
||||
|
|
Loading…
Reference in New Issue