diff options
author | Nick Piggin <npiggin@suse.de> | 2009-09-15 15:34:51 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2009-09-16 09:18:52 -0400 |
commit | 77b9d059cb3ddb8b1246d5878e81d52926550b23 (patch) | |
tree | 6d6a894d91097aec9e589d22f48d7ec387e062d9 /fs/fs-writeback.c | |
parent | 77fad5e625e56eb31a343ae1d489979fdc61a2aa (diff) |
writeback: Fix bdi use after free in wb_work_complete()
By the time bdi_work_on_stack gets evaluated again in bdi_work_free, it
can already have been deallocated and used for something else in the
!on stack case, giving a false positive in this test and causing
corruption.
Signed-off-by: Nick Piggin <npiggin@suse.de>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'fs/fs-writeback.c')
-rw-r--r-- | fs/fs-writeback.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 6bca6f8176f0..7eba7326b9b9 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -113,6 +113,7 @@ static void bdi_work_free(struct rcu_head *head) | |||
113 | static void wb_work_complete(struct bdi_work *work) | 113 | static void wb_work_complete(struct bdi_work *work) |
114 | { | 114 | { |
115 | const enum writeback_sync_modes sync_mode = work->args.sync_mode; | 115 | const enum writeback_sync_modes sync_mode = work->args.sync_mode; |
116 | int onstack = bdi_work_on_stack(work); | ||
116 | 117 | ||
117 | /* | 118 | /* |
118 | * For allocated work, we can clear the done/seen bit right here. | 119 | * For allocated work, we can clear the done/seen bit right here. |
@@ -120,9 +121,9 @@ static void wb_work_complete(struct bdi_work *work) | |||
120 | * to after the RCU grace period, since the stack could be invalidated | 121 | * to after the RCU grace period, since the stack could be invalidated |
121 | * as soon as bdi_work_clear() has done the wakeup. | 122 | * as soon as bdi_work_clear() has done the wakeup. |
122 | */ | 123 | */ |
123 | if (!bdi_work_on_stack(work)) | 124 | if (!onstack) |
124 | bdi_work_clear(work); | 125 | bdi_work_clear(work); |
125 | if (sync_mode == WB_SYNC_NONE || bdi_work_on_stack(work)) | 126 | if (sync_mode == WB_SYNC_NONE || onstack) |
126 | call_rcu(&work->rcu_head, bdi_work_free); | 127 | call_rcu(&work->rcu_head, bdi_work_free); |
127 | } | 128 | } |
128 | 129 | ||