]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/2.6.32.1/0017-ext4-Fix-double-free-of-blocks-with-EXT4_IOC_MOVE_EX.patch
drop queue-4.14/mips-make-sure-dt-memory-regions-are-valid.patch
[thirdparty/kernel/stable-queue.git] / releases / 2.6.32.1 / 0017-ext4-Fix-double-free-of-blocks-with-EXT4_IOC_MOVE_EX.patch
1 From 164659d7861e1243dc300c27c63e5918762912eb Mon Sep 17 00:00:00 2001
2 From: Akira Fujita <a-fujita@rs.jp.nec.com>
3 Date: Tue, 24 Nov 2009 10:19:57 -0500
4 Subject: [PATCH 17/30] ext4: Fix double-free of blocks with EXT4_IOC_MOVE_EXT
5
6 (cherry picked from commit 94d7c16cbbbd0e03841fcf272bcaf0620ad39618)
7
8 At the beginning of ext4_move_extent(), we call
9 ext4_discard_preallocations() to discard inode PAs of orig and donor
10 inodes. But in the following case, blocks can be double freed, so
11 move ext4_discard_preallocations() to the end of ext4_move_extents().
12
13 1. Discard inode PAs of orig and donor inodes with
14 ext4_discard_preallocations() in ext4_move_extents().
15
16 orig : [ DATA1 ]
17 donor: [ DATA2 ]
18
19 2. While data blocks are exchanging between orig and donor inodes, new
20 inode PAs is created to orig by other process's block allocation.
21 (Since there are semaphore gaps in ext4_move_extents().) And new
22 inode PAs is used partially (2-1).
23
24 2-1 Create new inode PAs to orig inode
25 orig : [ DATA1 | used PA1 | free PA1 ]
26 donor: [ DATA2 ]
27
28 3. Donor inode which has old orig inode's blocks is deleted after
29 EXT4_IOC_MOVE_EXT finished (3-1, 3-2). So the block bitmap
30 corresponds to old orig inode's blocks are freed.
31
32 3-1 After EXT4_IOC_MOVE_EXT finished
33 orig : [ DATA2 | free PA1 ]
34 donor: [ DATA1 | used PA1 ]
35
36 3-2 Delete donor inode
37 orig : [ DATA2 | free PA1 ]
38 donor: [ FREE SPACE(DATA1) | FREE SPACE(used PA1) ]
39
40 4. The double-free of blocks is occurred, when close() is called to
41 orig inode. Because ext4_discard_preallocations() for orig inode
42 frees used PA1 and free PA1, though used PA1 is already freed in 3.
43
44 4-1 Double-free of blocks is occurred
45 orig : [ DATA2 | FREE SPACE(free PA1) ]
46 donor: [ FREE SPACE(DATA1) | DOUBLE FREE(used PA1) ]
47
48 Signed-off-by: Akira Fujita <a-fujita@rs.jp.nec.com>
49 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
50 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
51 ---
52 fs/ext4/move_extent.c | 9 +++++----
53 1 file changed, 5 insertions(+), 4 deletions(-)
54
55 --- a/fs/ext4/move_extent.c
56 +++ b/fs/ext4/move_extent.c
57 @@ -1289,10 +1289,6 @@ ext4_move_extents(struct file *o_filp, s
58 ext4_ext_get_actual_len(ext_cur), block_end + 1) -
59 max(le32_to_cpu(ext_cur->ee_block), block_start);
60
61 - /* Discard preallocations of two inodes */
62 - ext4_discard_preallocations(orig_inode);
63 - ext4_discard_preallocations(donor_inode);
64 -
65 while (!last_extent && le32_to_cpu(ext_cur->ee_block) <= block_end) {
66 seq_blocks += add_blocks;
67
68 @@ -1410,6 +1406,11 @@ ext4_move_extents(struct file *o_filp, s
69
70 }
71 out:
72 + if (*moved_len) {
73 + ext4_discard_preallocations(orig_inode);
74 + ext4_discard_preallocations(donor_inode);
75 + }
76 +
77 if (orig_path) {
78 ext4_ext_drop_refs(orig_path);
79 kfree(orig_path);