Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

block: reject invalid queue attribute values

Instead of using simple_strtoul which "converts" invalid numbers to 0,
use strict_strtoul and perform error checking to ensure that userspace
passes us a valid unsigned long. This addresses problems with functions
such as writev, which might want to write a trailing newline -- the
newline should rightfully be rejected, but the value preceeding it
should be preserved.

Fixes BZ#46981.

Signed-off-by: Dave Reisner <dreisner@archlinux.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Dave Reisner and committed by
Jens Axboe
b1f3b64d bf800ef1

+23 -2
+23 -2
block/blk-sysfs.c
··· 26 26 static ssize_t 27 27 queue_var_store(unsigned long *var, const char *page, size_t count) 28 28 { 29 - char *p = (char *) page; 29 + int err; 30 + unsigned long v; 30 31 31 - *var = simple_strtoul(p, &p, 10); 32 + err = strict_strtoul(page, 10, &v); 33 + if (err || v > UINT_MAX) 34 + return -EINVAL; 35 + 36 + *var = v; 37 + 32 38 return count; 33 39 } 34 40 ··· 54 48 return -EINVAL; 55 49 56 50 ret = queue_var_store(&nr, page, count); 51 + if (ret < 0) 52 + return ret; 53 + 57 54 if (nr < BLKDEV_MIN_RQ) 58 55 nr = BLKDEV_MIN_RQ; 59 56 ··· 110 101 { 111 102 unsigned long ra_kb; 112 103 ssize_t ret = queue_var_store(&ra_kb, page, count); 104 + 105 + if (ret < 0) 106 + return ret; 113 107 114 108 q->backing_dev_info.ra_pages = ra_kb >> (PAGE_CACHE_SHIFT - 10); 115 109 ··· 188 176 page_kb = 1 << (PAGE_CACHE_SHIFT - 10); 189 177 ssize_t ret = queue_var_store(&max_sectors_kb, page, count); 190 178 179 + if (ret < 0) 180 + return ret; 181 + 191 182 if (max_sectors_kb > max_hw_sectors_kb || max_sectors_kb < page_kb) 192 183 return -EINVAL; 193 184 ··· 251 236 unsigned long nm; 252 237 ssize_t ret = queue_var_store(&nm, page, count); 253 238 239 + if (ret < 0) 240 + return ret; 241 + 254 242 spin_lock_irq(q->queue_lock); 255 243 queue_flag_clear(QUEUE_FLAG_NOMERGES, q); 256 244 queue_flag_clear(QUEUE_FLAG_NOXMERGES, q); ··· 282 264 unsigned long val; 283 265 284 266 ret = queue_var_store(&val, page, count); 267 + if (ret < 0) 268 + return ret; 269 + 285 270 spin_lock_irq(q->queue_lock); 286 271 if (val == 2) { 287 272 queue_flag_set(QUEUE_FLAG_SAME_COMP, q);