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
|
* IB/core: Prevent integer overflow in ib_umem_get address arithmetic
|
||||||
(CVE-2014-8159)
|
(CVE-2014-8159)
|
||||||
* Btrfs: make xattr replace operations atomic (CVE-2014-9710)
|
* 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
|
-- 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/ib-core-prevent-integer-overflow-in-ib_umem_get.patch
|
||||||
bugfix/all/btrfs-make-xattr-replace-operations-atomic.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