diff options
author | Junho Ryu <jayr@google.com> | 2013-12-03 18:10:28 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-01-09 15:24:21 -0500 |
commit | e696abfcc89a087afef75ebca0848f37fb9877ae (patch) | |
tree | 7e41ed83124af04857e2b9691be82ed6199e80d5 | |
parent | 6b8588219a59ae34f99e20f17bc9756f831a9b2e (diff) |
ext4: fix use-after-free in ext4_mb_new_blocks
commit 4e8d2139802ce4f41936a687f06c560b12115247 upstream.
ext4_mb_put_pa should hold pa->pa_lock before accessing pa->pa_count.
While ext4_mb_use_preallocated checks pa->pa_deleted first and then
increments pa->count later, ext4_mb_put_pa decrements pa->pa_count
before holding pa->pa_lock and then sets pa->pa_deleted.
* Free sequence
ext4_mb_put_pa (1): atomic_dec_and_test pa->pa_count
ext4_mb_put_pa (2): lock pa->pa_lock
ext4_mb_put_pa (3): check pa->pa_deleted
ext4_mb_put_pa (4): set pa->pa_deleted=1
ext4_mb_put_pa (5): unlock pa->pa_lock
ext4_mb_put_pa (6): remove pa from a list
ext4_mb_pa_callback: free pa
* Use sequence
ext4_mb_use_preallocated (1): iterate over preallocation
ext4_mb_use_preallocated (2): lock pa->pa_lock
ext4_mb_use_preallocated (3): check pa->pa_deleted
ext4_mb_use_preallocated (4): increase pa->pa_count
ext4_mb_use_preallocated (5): unlock pa->pa_lock
ext4_mb_release_context: access pa
* Use-after-free sequence
[initial status] <pa->pa_deleted = 0, pa_count = 1>
ext4_mb_use_preallocated (1): iterate over preallocation
ext4_mb_use_preallocated (2): lock pa->pa_lock
ext4_mb_use_preallocated (3): check pa->pa_deleted
ext4_mb_put_pa (1): atomic_dec_and_test pa->pa_count
[pa_count decremented] <pa->pa_deleted = 0, pa_count = 0>
ext4_mb_use_preallocated (4): increase pa->pa_count
[pa_count incremented] <pa->pa_deleted = 0, pa_count = 1>
ext4_mb_use_preallocated (5): unlock pa->pa_lock
ext4_mb_put_pa (2): lock pa->pa_lock
ext4_mb_put_pa (3): check pa->pa_deleted
ext4_mb_put_pa (4): set pa->pa_deleted=1
[race condition!] <pa->pa_deleted = 1, pa_count = 1>
ext4_mb_put_pa (5): unlock pa->pa_lock
ext4_mb_put_pa (6): remove pa from a list
ext4_mb_pa_callback: free pa
ext4_mb_release_context: access pa
AddressSanitizer has detected use-after-free in ext4_mb_new_blocks
Bug report: http://goo.gl/rG1On3
Signed-off-by: Junho Ryu <jayr@google.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | fs/ext4/mballoc.c | 11 |
1 files changed, 8 insertions, 3 deletions
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 59c6750b894f..c1f58e0f26c3 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -3423,6 +3423,9 @@ static void ext4_mb_pa_callback(struct rcu_head *head) | |||
3423 | { | 3423 | { |
3424 | struct ext4_prealloc_space *pa; | 3424 | struct ext4_prealloc_space *pa; |
3425 | pa = container_of(head, struct ext4_prealloc_space, u.pa_rcu); | 3425 | pa = container_of(head, struct ext4_prealloc_space, u.pa_rcu); |
3426 | |||
3427 | BUG_ON(atomic_read(&pa->pa_count)); | ||
3428 | BUG_ON(pa->pa_deleted == 0); | ||
3426 | kmem_cache_free(ext4_pspace_cachep, pa); | 3429 | kmem_cache_free(ext4_pspace_cachep, pa); |
3427 | } | 3430 | } |
3428 | 3431 | ||
@@ -3436,11 +3439,13 @@ static void ext4_mb_put_pa(struct ext4_allocation_context *ac, | |||
3436 | ext4_group_t grp; | 3439 | ext4_group_t grp; |
3437 | ext4_fsblk_t grp_blk; | 3440 | ext4_fsblk_t grp_blk; |
3438 | 3441 | ||
3439 | if (!atomic_dec_and_test(&pa->pa_count) || pa->pa_free != 0) | ||
3440 | return; | ||
3441 | |||
3442 | /* in this short window concurrent discard can set pa_deleted */ | 3442 | /* in this short window concurrent discard can set pa_deleted */ |
3443 | spin_lock(&pa->pa_lock); | 3443 | spin_lock(&pa->pa_lock); |
3444 | if (!atomic_dec_and_test(&pa->pa_count) || pa->pa_free != 0) { | ||
3445 | spin_unlock(&pa->pa_lock); | ||
3446 | return; | ||
3447 | } | ||
3448 | |||
3444 | if (pa->pa_deleted == 1) { | 3449 | if (pa->pa_deleted == 1) { |
3445 | spin_unlock(&pa->pa_lock); | 3450 | spin_unlock(&pa->pa_lock); |
3446 | return; | 3451 | return; |