| From b8654ec5ab1ba3fc38e8d694985328f1c3ddda40 Mon Sep 17 00:00:00 2001 |
| From: Tejun Heo <tj@kernel.org> |
| Date: Wed, 8 Feb 2017 15:19:07 -0500 |
| Subject: [PATCH] block: fix double-free in the failure path of cgwb_bdi_init() |
| |
| commit 5f478e4ea5c5560b4e40eb136991a09f9389f331 upstream. |
| |
| When !CONFIG_CGROUP_WRITEBACK, bdi has single bdi_writeback_congested |
| at bdi->wb_congested. cgwb_bdi_init() allocates it with kzalloc() and |
| doesn't do further initialization. This usually works fine as the |
| reference count gets bumped to 1 by wb_init() and the put from |
| wb_exit() releases it. |
| |
| However, when wb_init() fails, it puts the wb base ref automatically |
| freeing the wb and the explicit kfree() in cgwb_bdi_init() error path |
| ends up trying to free the same pointer the second time causing a |
| double-free. |
| |
| Fix it by explicitly initilizing the refcnt to 1 and putting the base |
| ref from cgwb_bdi_destroy(). |
| |
| Signed-off-by: Tejun Heo <tj@kernel.org> |
| Reported-by: Dmitry Vyukov <dvyukov@google.com> |
| Fixes: a13f35e87140 ("writeback: don't embed root bdi_writeback_congested in bdi_writeback") |
| Cc: stable@vger.kernel.org # v4.2+ |
| Signed-off-by: Jens Axboe <axboe@fb.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/mm/backing-dev.c b/mm/backing-dev.c |
| index 8fde443f36d7..6ff2d7744223 100644 |
| --- a/mm/backing-dev.c |
| +++ b/mm/backing-dev.c |
| @@ -757,15 +757,20 @@ static int cgwb_bdi_init(struct backing_dev_info *bdi) |
| if (!bdi->wb_congested) |
| return -ENOMEM; |
| |
| + atomic_set(&bdi->wb_congested->refcnt, 1); |
| + |
| err = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL); |
| if (err) { |
| - kfree(bdi->wb_congested); |
| + wb_congested_put(bdi->wb_congested); |
| return err; |
| } |
| return 0; |
| } |
| |
| -static void cgwb_bdi_destroy(struct backing_dev_info *bdi) { } |
| +static void cgwb_bdi_destroy(struct backing_dev_info *bdi) |
| +{ |
| + wb_congested_put(bdi->wb_congested); |
| +} |
| |
| #endif /* CONFIG_CGROUP_WRITEBACK */ |
| |
| -- |
| 2.12.0 |
| |