| From e479308ac228b7482617d31e4253089ea9abbde2 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Wed, 4 Mar 2020 13:58:19 +0300 |
| Subject: blktrace: fix dereference after null check |
| |
| From: Cengiz Can <cengiz@kernel.wtf> |
| |
| [ Upstream commit 153031a301bb07194e9c37466cfce8eacb977621 ] |
| |
| There was a recent change in blktrace.c that added a RCU protection to |
| `q->blk_trace` in order to fix a use-after-free issue during access. |
| |
| However the change missed an edge case that can lead to dereferencing of |
| `bt` pointer even when it's NULL: |
| |
| Coverity static analyzer marked this as a FORWARD_NULL issue with CID |
| 1460458. |
| |
| ``` |
| /kernel/trace/blktrace.c: 1904 in sysfs_blk_trace_attr_store() |
| 1898 ret = 0; |
| 1899 if (bt == NULL) |
| 1900 ret = blk_trace_setup_queue(q, bdev); |
| 1901 |
| 1902 if (ret == 0) { |
| 1903 if (attr == &dev_attr_act_mask) |
| >>> CID 1460458: Null pointer dereferences (FORWARD_NULL) |
| >>> Dereferencing null pointer "bt". |
| 1904 bt->act_mask = value; |
| 1905 else if (attr == &dev_attr_pid) |
| 1906 bt->pid = value; |
| 1907 else if (attr == &dev_attr_start_lba) |
| 1908 bt->start_lba = value; |
| 1909 else if (attr == &dev_attr_end_lba) |
| ``` |
| |
| Added a reassignment with RCU annotation to fix the issue. |
| |
| Fixes: c780e86dd48 ("blktrace: Protect q->blk_trace with RCU") |
| Cc: stable@vger.kernel.org |
| Reviewed-by: Ming Lei <ming.lei@redhat.com> |
| Reviewed-by: Bob Liu <bob.liu@oracle.com> |
| Reviewed-by: Steven Rostedt (VMware) <rostedt@goodmis.org> |
| Signed-off-by: Cengiz Can <cengiz@kernel.wtf> |
| Signed-off-by: Jens Axboe <axboe@kernel.dk> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| kernel/trace/blktrace.c | 5 ++++- |
| 1 file changed, 4 insertions(+), 1 deletion(-) |
| |
| diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c |
| index a6d3016410eba..840ef7af20e04 100644 |
| --- a/kernel/trace/blktrace.c |
| +++ b/kernel/trace/blktrace.c |
| @@ -1896,8 +1896,11 @@ static ssize_t sysfs_blk_trace_attr_store(struct device *dev, |
| } |
| |
| ret = 0; |
| - if (bt == NULL) |
| + if (bt == NULL) { |
| ret = blk_trace_setup_queue(q, bdev); |
| + bt = rcu_dereference_protected(q->blk_trace, |
| + lockdep_is_held(&q->blk_trace_mutex)); |
| + } |
| |
| if (ret == 0) { |
| if (attr == &dev_attr_act_mask) |
| -- |
| 2.20.1 |
| |