add jbd2 speedup patches
[ext4-patch-queue.git] / cap-max-length-from-ext
blobb45308d463f7e236af3ea683bff26f3ff172c13a
1 ext4: avoid possible overflow in ext4_map_blocks()
3 The ext4_map_blocks() function returns the number of blocks which
4 satisfying the caller's request.  This number of blocks requested by
5 the caller is specified by an unsigned integer, but the return value
6 of ext4_map_blocks() is a signed integer (to accomodate error codes
7 per the kernel's standard error signalling convention).
9 Historically, overflows could never happen since mballoc() will refuse
10 to allocate more than 2048 blocks at a time (which is something we
11 should fix), and if the blocks were already allocated, the fact that
12 there would be some number of intervening metadata blocks pretty much
13 guaranteed that there could never be a contiguous region of data
14 blocks that was greater than 2**31 blocks.
16 However, this is now possible if there is a file system which is a bit
17 bigger than 8TB, and is created using the new mke2fs hugeblock
18 feature, which can create a perfectly contiguous file.  In that case,
19 if a userspace program attempted to call fallocate() on this already
20 fully allocated file, it's possible that ext4_map_blocks() could
21 return a number large enough that it would overflow a signed integer,
22 resulting in a ext4 thinking that the ext4_map_blocks() call had
23 failed with some strange error code.
25 Since ext4_map_blocks() is always free to return a smaller number of
26 blocks than what was requested by the caller, fix this by capping the
27 number of blocks that ext4_map_blocks() will ever try to map to 2**31
28 - 1.  In practice this should never get hit, except by someone
29 deliberately trying to provke the above-described bug.
31 Thanks to the PaX team for asking whethre this could possibly happen
32 in some off-line discussions about using some static code checking
33 technology they are developing to find bugs in kernel code.
35 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
36 ---
37  fs/ext4/inode.c | 6 ++++++
38  1 file changed, 6 insertions(+)
40 diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
41 index 6e39895..113458c 100644
42 --- a/fs/ext4/inode.c
43 +++ b/fs/ext4/inode.c
44 @@ -514,6 +514,12 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
45                   "logical block %lu\n", inode->i_ino, flags, map->m_len,
46                   (unsigned long) map->m_lblk);
48 +       /*
49 +        * ext4_map_blocks returns an int, and m_len is an unsigned int
50 +        */
51 +       if (unlikely(map->m_len > INT_MAX))
52 +               map->m_len = INT_MAX;
54         /* Lookup extent status tree firstly */
55         if (ext4_es_lookup_extent(inode, map->m_lblk, &es)) {
56                 ext4_es_lru_add(inode);