aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunho Ryu <jayr@google.com>2013-12-03 18:10:28 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-01-09 15:24:21 -0500
commite696abfcc89a087afef75ebca0848f37fb9877ae (patch)
tree7e41ed83124af04857e2b9691be82ed6199e80d5
parent6b8588219a59ae34f99e20f17bc9756f831a9b2e (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.c11
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;