Commit 1af97771b397a9ca2ee984c3277bcada3eec95cd
Committed by
Greg Kroah-Hartman
1 parent
4fbdb44239
Exists in
ti-lsk-linux-4.1.y
and in
5 other branches
blk-mq: fix buffer overflow when reading sysfs file of 'pending'
commit 596f5aad2a704b72934e5abec1b1b4114c16f45b upstream. There may be lots of pending requests so that the buffer of PAGE_SIZE can't hold them at all. One typical example is scsi-mq, the queue depth(.can_queue) of scsi_host and blk-mq is quite big but scsi_device's queue_depth is a bit small(.cmd_per_lun), then it is quite easy to have lots of pending requests in hw queue. This patch fixes the following warning and the related memory destruction. [ 359.025101] fill_read_buffer: blk_mq_hw_sysfs_show+0x0/0x7d returned bad count^M [ 359.055595] irq event stamp: 15537^M [ 359.055606] general protection fault: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC ^M [ 359.055614] Dumping ftrace buffer:^M [ 359.055660] (ftrace buffer empty)^M [ 359.055672] Modules linked in: nbd ipv6 kvm_intel kvm serio_raw^M [ 359.055678] CPU: 4 PID: 21631 Comm: stress-ng-sysfs Not tainted 4.2.0-rc5-next-20150805 #434^M [ 359.055679] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011^M [ 359.055682] task: ffff8802161cc000 ti: ffff88021b4a8000 task.ti: ffff88021b4a8000^M [ 359.055693] RIP: 0010:[<ffffffff811541c5>] [<ffffffff811541c5>] __kmalloc+0xe8/0x152^M Signed-off-by: Ming Lei <ming.lei@canonical.com> Signed-off-by: Jens Axboe <axboe@fb.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 1 changed file with 18 additions and 7 deletions Side-by-side Diff
block/blk-mq-sysfs.c
... | ... | @@ -141,15 +141,26 @@ |
141 | 141 | |
142 | 142 | static ssize_t sysfs_list_show(char *page, struct list_head *list, char *msg) |
143 | 143 | { |
144 | - char *start_page = page; | |
145 | 144 | struct request *rq; |
145 | + int len = snprintf(page, PAGE_SIZE - 1, "%s:\n", msg); | |
146 | 146 | |
147 | - page += sprintf(page, "%s:\n", msg); | |
147 | + list_for_each_entry(rq, list, queuelist) { | |
148 | + const int rq_len = 2 * sizeof(rq) + 2; | |
148 | 149 | |
149 | - list_for_each_entry(rq, list, queuelist) | |
150 | - page += sprintf(page, "\t%p\n", rq); | |
150 | + /* if the output will be truncated */ | |
151 | + if (PAGE_SIZE - 1 < len + rq_len) { | |
152 | + /* backspacing if it can't hold '\t...\n' */ | |
153 | + if (PAGE_SIZE - 1 < len + 5) | |
154 | + len -= rq_len; | |
155 | + len += snprintf(page + len, PAGE_SIZE - 1 - len, | |
156 | + "\t...\n"); | |
157 | + break; | |
158 | + } | |
159 | + len += snprintf(page + len, PAGE_SIZE - 1 - len, | |
160 | + "\t%p\n", rq); | |
161 | + } | |
151 | 162 | |
152 | - return page - start_page; | |
163 | + return len; | |
153 | 164 | } |
154 | 165 | |
155 | 166 | static ssize_t blk_mq_sysfs_rq_list_show(struct blk_mq_ctx *ctx, char *page) |