提交 de1b854e 编写于 作者: Y Yufen Yu 提交者: Yang Yingliang

bdi: get device name under rcu protect

hulk inclusion
category: bugfix
bugzilla: 30109
CVE: NA
---------------------------

bdi->dev may be set as "NULL" or freed by bdi_unregister().
To avoid causing "NULL" pointer reference or use-after-free
in user, we add a common function bdi_get_dev_name(), in which
dev is protected by RCU lock. Then, the caller can get device
name safely.

Fixes: 5ca4579ae59b ("bdi: fix use-after-free for the bdi device")
Signed-off-by: NYufen Yu <yuyufen@huawei.com>
Reviewed-by: NHou Tao <houao1@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 eafb0009
......@@ -132,6 +132,7 @@
#include <linux/ioprio.h>
#include <linux/sbitmap.h>
#include <linux/delay.h>
#include <linux/backing-dev.h>
#include "blk.h"
#include "blk-mq.h"
......@@ -4204,6 +4205,7 @@ bfq_set_next_ioprio_data(struct bfq_queue *bfqq, struct bfq_io_cq *bic)
struct task_struct *tsk = current;
int ioprio_class;
struct bfq_data *bfqd = bfqq->bfqd;
char dname[BDI_DEV_NAME_LEN];
if (!bfqd)
return;
......@@ -4211,8 +4213,9 @@ bfq_set_next_ioprio_data(struct bfq_queue *bfqq, struct bfq_io_cq *bic)
ioprio_class = IOPRIO_PRIO_CLASS(bic->ioprio);
switch (ioprio_class) {
default:
dev_err(bfqq->bfqd->queue->backing_dev_info->dev,
"bfq: bad prio class %d\n", ioprio_class);
bdi_get_dev_name(bfqq->bfqd->queue->backing_dev_info,
dname, BDI_DEV_NAME_LEN);
pr_err("%s bfq: bad prio class %d\n", dname, ioprio_class);
/* fall through */
case IOPRIO_CLASS_NONE:
/*
......
......@@ -1353,6 +1353,7 @@ static struct request *__get_request(struct request_list *rl, unsigned int op,
const bool is_sync = op_is_sync(op);
int may_queue;
req_flags_t rq_flags = RQF_ALLOCED;
char dname[BDI_DEV_NAME_LEN];
lockdep_assert_held(q->queue_lock);
......@@ -1474,8 +1475,9 @@ static struct request *__get_request(struct request_list *rl, unsigned int op,
* shouldn't stall IO. Treat this request as !elvpriv. This will
* disturb iosched and blkcg but weird is bettern than dead.
*/
bdi_get_dev_name(q->backing_dev_info, dname, BDI_DEV_NAME_LEN);
printk_ratelimited(KERN_WARNING "%s: dev %s: request aux data allocation failed, iosched may be disturbed\n",
__func__, dev_name(q->backing_dev_info->dev));
__func__, dname);
rq->rq_flags &= ~RQF_ELVPRIV;
rq->elv.icq = NULL;
......
......@@ -1980,8 +1980,10 @@ void wb_workfn(struct work_struct *work)
struct bdi_writeback *wb = container_of(to_delayed_work(work),
struct bdi_writeback, dwork);
long pages_written;
char dname[BDI_DEV_NAME_LEN];
set_worker_desc("flush-%s", dev_name(wb->bdi->dev));
bdi_get_dev_name(wb->bdi, dname, BDI_DEV_NAME_LEN);
set_worker_desc("flush-%s", dname);
current->flags |= PF_SWAPWRITE;
if (likely(!current_is_workqueue_rescuer() ||
......
......@@ -18,6 +18,8 @@
#include <linux/backing-dev-defs.h>
#include <linux/slab.h>
#define BDI_DEV_NAME_LEN 32
static inline struct backing_dev_info *bdi_get(struct backing_dev_info *bdi)
{
kref_get(&bdi->refcnt);
......@@ -498,4 +500,17 @@ static inline int bdi_rw_congested(struct backing_dev_info *bdi)
(1 << WB_async_congested));
}
static inline void bdi_get_dev_name(struct backing_dev_info *bdi, char *dname,
int len)
{
struct rcu_device *rcu_dev;
rcu_read_lock();
rcu_dev = rcu_dereference(bdi->rcu_dev);
strlcpy(dname, rcu_dev ? dev_name(&rcu_dev->dev) : "(unknown)", len);
rcu_read_unlock();
}
#endif /* _LINUX_BACKING_DEV_H */
......@@ -33,8 +33,7 @@ TRACE_EVENT(wbt_stat,
),
TP_fast_assign(
strlcpy(__entry->name, dev_name(bdi->dev),
ARRAY_SIZE(__entry->name));
bdi_get_dev_name(bdi, __entry->name, ARRAY_SIZE(__entry->name));
__entry->rmean = stat[0].mean;
__entry->rmin = stat[0].min;
__entry->rmax = stat[0].max;
......@@ -68,8 +67,7 @@ TRACE_EVENT(wbt_lat,
),
TP_fast_assign(
strlcpy(__entry->name, dev_name(bdi->dev),
ARRAY_SIZE(__entry->name));
bdi_get_dev_name(bdi, __entry->name, ARRAY_SIZE(__entry->name));
__entry->lat = div_u64(lat, 1000);
),
......@@ -105,8 +103,7 @@ TRACE_EVENT(wbt_step,
),
TP_fast_assign(
strlcpy(__entry->name, dev_name(bdi->dev),
ARRAY_SIZE(__entry->name));
bdi_get_dev_name(bdi, __entry->name, ARRAY_SIZE(__entry->name));
__entry->msg = msg;
__entry->step = step;
__entry->window = div_u64(window, 1000);
......@@ -141,8 +138,7 @@ TRACE_EVENT(wbt_timer,
),
TP_fast_assign(
strlcpy(__entry->name, dev_name(bdi->dev),
ARRAY_SIZE(__entry->name));
bdi_get_dev_name(bdi, __entry->name, ARRAY_SIZE(__entry->name));
__entry->status = status;
__entry->step = step;
__entry->inflight = inflight;
......
......@@ -96,8 +96,7 @@ DECLARE_EVENT_CLASS(writeback_dirty_inode_template,
struct backing_dev_info *bdi = inode_to_bdi(inode);
/* may be called for files on pseudo FSes w/ unregistered bdi */
strncpy(__entry->name,
bdi->dev ? dev_name(bdi->dev) : "(unknown)", 32);
bdi_get_dev_name(bdi, __entry->name, 32);
__entry->ino = inode->i_ino;
__entry->state = inode->i_state;
__entry->flags = flags;
......@@ -220,8 +219,7 @@ DECLARE_EVENT_CLASS(writeback_work_class,
__field(unsigned int, cgroup_ino)
),
TP_fast_assign(
strncpy(__entry->name,
wb->bdi->dev ? dev_name(wb->bdi->dev) : "(unknown)", 32);
bdi_get_dev_name(wb->bdi, __entry->name, 32);
__entry->nr_pages = work->nr_pages;
__entry->sb_dev = work->sb ? work->sb->s_dev : 0;
__entry->sync_mode = work->sync_mode;
......@@ -274,7 +272,7 @@ DECLARE_EVENT_CLASS(writeback_class,
__field(unsigned int, cgroup_ino)
),
TP_fast_assign(
strncpy(__entry->name, dev_name(wb->bdi->dev), 32);
bdi_get_dev_name(wb->bdi, __entry->name, 32);
__entry->cgroup_ino = __trace_wb_assign_cgroup(wb);
),
TP_printk("bdi %s: cgroup_ino=%u",
......@@ -296,7 +294,7 @@ TRACE_EVENT(writeback_bdi_register,
__array(char, name, 32)
),
TP_fast_assign(
strncpy(__entry->name, dev_name(bdi->dev), 32);
bdi_get_dev_name(bdi, __entry->name, 32);
),
TP_printk("bdi %s",
__entry->name
......@@ -321,7 +319,7 @@ DECLARE_EVENT_CLASS(wbc_class,
),
TP_fast_assign(
strncpy(__entry->name, dev_name(bdi->dev), 32);
bdi_get_dev_name(bdi, __entry->name, 32);
__entry->nr_to_write = wbc->nr_to_write;
__entry->pages_skipped = wbc->pages_skipped;
__entry->sync_mode = wbc->sync_mode;
......@@ -372,7 +370,7 @@ TRACE_EVENT(writeback_queue_io,
),
TP_fast_assign(
unsigned long *older_than_this = work->older_than_this;
strncpy(__entry->name, dev_name(wb->bdi->dev), 32);
bdi_get_dev_name(wb->bdi, __entry->name, 32);
__entry->older = older_than_this ? *older_than_this : 0;
__entry->age = older_than_this ?
(jiffies - *older_than_this) * 1000 / HZ : -1;
......@@ -458,7 +456,7 @@ TRACE_EVENT(bdi_dirty_ratelimit,
),
TP_fast_assign(
strlcpy(__entry->bdi, dev_name(wb->bdi->dev), 32);
bdi_get_dev_name(wb->bdi, __entry->bdi, 32);
__entry->write_bw = KBps(wb->write_bandwidth);
__entry->avg_write_bw = KBps(wb->avg_write_bandwidth);
__entry->dirty_rate = KBps(dirty_rate);
......@@ -523,7 +521,7 @@ TRACE_EVENT(balance_dirty_pages,
TP_fast_assign(
unsigned long freerun = (thresh + bg_thresh) / 2;
strlcpy(__entry->bdi, dev_name(wb->bdi->dev), 32);
bdi_get_dev_name(wb->bdi, __entry->bdi, 32);
__entry->limit = global_wb_domain.dirty_limit;
__entry->setpoint = (global_wb_domain.dirty_limit +
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册