diff options
author | Ben Hutchings <ben@decadent.org.uk> | 2020-04-21 23:20:17 +0100 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2020-04-21 23:29:34 +0100 |
commit | c53be8ef0c3d3bcf3c92c0e932eb0a7332b07b99 (patch) | |
tree | c161ca27351ad368a60193f69b9862189accf053 | |
parent | 11f7beeb240e9e4e55251d06c11c22730729000c (diff) | |
download | linux-stable-queue-c53be8ef0c3d3bcf3c92c0e932eb0a7332b07b99.tar.gz |
Add various security fixes
20 files changed, 1775 insertions, 0 deletions
diff --git a/queue-3.16/blktrace-fix-dereference-after-null-check.patch b/queue-3.16/blktrace-fix-dereference-after-null-check.patch new file mode 100644 index 00000000..f415e20a --- /dev/null +++ b/queue-3.16/blktrace-fix-dereference-after-null-check.patch @@ -0,0 +1,61 @@ +From: Cengiz Can <cengiz@kernel.wtf> +Date: Wed, 4 Mar 2020 13:58:19 +0300 +Subject: blktrace: fix dereference after null check + +commit 153031a301bb07194e9c37466cfce8eacb977621 upstream. + +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") +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: Ben Hutchings <ben@decadent.org.uk> +--- + kernel/trace/blktrace.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/kernel/trace/blktrace.c ++++ b/kernel/trace/blktrace.c +@@ -1834,8 +1834,11 @@ static ssize_t sysfs_blk_trace_attr_stor + } + + 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) diff --git a/queue-3.16/blktrace-protect-q-blk_trace-with-rcu.patch b/queue-3.16/blktrace-protect-q-blk_trace-with-rcu.patch new file mode 100644 index 00000000..0ee6009c --- /dev/null +++ b/queue-3.16/blktrace-protect-q-blk_trace-with-rcu.patch @@ -0,0 +1,390 @@ +From: Jan Kara <jack@suse.cz> +Date: Thu, 6 Feb 2020 15:28:12 +0100 +Subject: blktrace: Protect q->blk_trace with RCU + +commit c780e86dd48ef6467a1146cf7d0fe1e05a635039 upstream. + +KASAN is reporting that __blk_add_trace() has a use-after-free issue +when accessing q->blk_trace. Indeed the switching of block tracing (and +thus eventual freeing of q->blk_trace) is completely unsynchronized with +the currently running tracing and thus it can happen that the blk_trace +structure is being freed just while __blk_add_trace() works on it. +Protect accesses to q->blk_trace by RCU during tracing and make sure we +wait for the end of RCU grace period when shutting down tracing. Luckily +that is rare enough event that we can afford that. Note that postponing +the freeing of blk_trace to an RCU callback should better be avoided as +it could have unexpected user visible side-effects as debugfs files +would be still existing for a short while block tracing has been shut +down. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=205711 +Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com> +Reviewed-by: Ming Lei <ming.lei@redhat.com> +Tested-by: Ming Lei <ming.lei@redhat.com> +Reviewed-by: Bart Van Assche <bvanassche@acm.org> +Reported-by: Tristan Madani <tristmd@gmail.com> +Signed-off-by: Jan Kara <jack@suse.cz> +Signed-off-by: Jens Axboe <axboe@kernel.dk> +[bwh: Backported to 3.16: + - Drop changes in blk_trace_note_message_enabled(), blk_trace_bio_get_cgid() + - Adjust context] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -447,7 +447,7 @@ struct request_queue { + unsigned int sg_reserved_size; + int node; + #ifdef CONFIG_BLK_DEV_IO_TRACE +- struct blk_trace *blk_trace; ++ struct blk_trace __rcu *blk_trace; + struct mutex blk_trace_mutex; + #endif + /* +--- a/include/linux/blktrace_api.h ++++ b/include/linux/blktrace_api.h +@@ -51,9 +51,13 @@ void __trace_note_message(struct blk_tra + **/ + #define blk_add_trace_msg(q, fmt, ...) \ + do { \ +- struct blk_trace *bt = (q)->blk_trace; \ ++ struct blk_trace *bt; \ ++ \ ++ rcu_read_lock(); \ ++ bt = rcu_dereference((q)->blk_trace); \ + if (unlikely(bt)) \ + __trace_note_message(bt, fmt, ##__VA_ARGS__); \ ++ rcu_read_unlock(); \ + } while (0) + #define BLK_TN_MAX_MSG 128 + +--- a/kernel/trace/blktrace.c ++++ b/kernel/trace/blktrace.c +@@ -302,6 +302,7 @@ static void blk_trace_free(struct blk_tr + + static void blk_trace_cleanup(struct blk_trace *bt) + { ++ synchronize_rcu(); + blk_trace_free(bt); + if (atomic_dec_and_test(&blk_probes_ref)) + blk_unregister_tracepoints(); +@@ -616,8 +617,10 @@ static int compat_blk_trace_setup(struct + static int __blk_trace_startstop(struct request_queue *q, int start) + { + int ret; +- struct blk_trace *bt = q->blk_trace; ++ struct blk_trace *bt; + ++ bt = rcu_dereference_protected(q->blk_trace, ++ lockdep_is_held(&q->blk_trace_mutex)); + if (bt == NULL) + return -EINVAL; + +@@ -726,8 +729,8 @@ int blk_trace_ioctl(struct block_device + void blk_trace_shutdown(struct request_queue *q) + { + mutex_lock(&q->blk_trace_mutex); +- +- if (q->blk_trace) { ++ if (rcu_dereference_protected(q->blk_trace, ++ lockdep_is_held(&q->blk_trace_mutex))) { + __blk_trace_startstop(q, 0); + __blk_trace_remove(q); + } +@@ -753,10 +756,14 @@ void blk_trace_shutdown(struct request_q + static void blk_add_trace_rq(struct request_queue *q, struct request *rq, + unsigned int nr_bytes, u32 what) + { +- struct blk_trace *bt = q->blk_trace; ++ struct blk_trace *bt; + +- if (likely(!bt)) ++ rcu_read_lock(); ++ bt = rcu_dereference(q->blk_trace); ++ if (likely(!bt)) { ++ rcu_read_unlock(); + return; ++ } + + if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { + what |= BLK_TC_ACT(BLK_TC_PC); +@@ -767,6 +774,7 @@ static void blk_add_trace_rq(struct requ + __blk_add_trace(bt, blk_rq_pos(rq), nr_bytes, + rq->cmd_flags, what, rq->errors, 0, NULL); + } ++ rcu_read_unlock(); + } + + static void blk_add_trace_rq_abort(void *ignore, +@@ -816,16 +824,21 @@ static void blk_add_trace_rq_complete(vo + static void blk_add_trace_bio(struct request_queue *q, struct bio *bio, + u32 what, int error) + { +- struct blk_trace *bt = q->blk_trace; ++ struct blk_trace *bt; + +- if (likely(!bt)) ++ rcu_read_lock(); ++ bt = rcu_dereference(q->blk_trace); ++ if (likely(!bt)) { ++ rcu_read_unlock(); + return; ++ } + + if (!error && !bio_flagged(bio, BIO_UPTODATE)) + error = EIO; + + __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size, + bio->bi_rw, what, error, 0, NULL); ++ rcu_read_unlock(); + } + + static void blk_add_trace_bio_bounce(void *ignore, +@@ -870,10 +883,13 @@ static void blk_add_trace_getrq(void *ig + if (bio) + blk_add_trace_bio(q, bio, BLK_TA_GETRQ, 0); + else { +- struct blk_trace *bt = q->blk_trace; ++ struct blk_trace *bt; + ++ rcu_read_lock(); ++ bt = rcu_dereference(q->blk_trace); + if (bt) + __blk_add_trace(bt, 0, 0, rw, BLK_TA_GETRQ, 0, 0, NULL); ++ rcu_read_unlock(); + } + } + +@@ -885,27 +901,35 @@ static void blk_add_trace_sleeprq(void * + if (bio) + blk_add_trace_bio(q, bio, BLK_TA_SLEEPRQ, 0); + else { +- struct blk_trace *bt = q->blk_trace; ++ struct blk_trace *bt; + ++ rcu_read_lock(); ++ bt = rcu_dereference(q->blk_trace); + if (bt) + __blk_add_trace(bt, 0, 0, rw, BLK_TA_SLEEPRQ, + 0, 0, NULL); ++ rcu_read_unlock(); + } + } + + static void blk_add_trace_plug(void *ignore, struct request_queue *q) + { +- struct blk_trace *bt = q->blk_trace; ++ struct blk_trace *bt; + ++ rcu_read_lock(); ++ bt = rcu_dereference(q->blk_trace); + if (bt) + __blk_add_trace(bt, 0, 0, 0, BLK_TA_PLUG, 0, 0, NULL); ++ rcu_read_unlock(); + } + + static void blk_add_trace_unplug(void *ignore, struct request_queue *q, + unsigned int depth, bool explicit) + { +- struct blk_trace *bt = q->blk_trace; ++ struct blk_trace *bt; + ++ rcu_read_lock(); ++ bt = rcu_dereference(q->blk_trace); + if (bt) { + __be64 rpdu = cpu_to_be64(depth); + u32 what; +@@ -917,14 +941,17 @@ static void blk_add_trace_unplug(void *i + + __blk_add_trace(bt, 0, 0, 0, what, 0, sizeof(rpdu), &rpdu); + } ++ rcu_read_unlock(); + } + + static void blk_add_trace_split(void *ignore, + struct request_queue *q, struct bio *bio, + unsigned int pdu) + { +- struct blk_trace *bt = q->blk_trace; ++ struct blk_trace *bt; + ++ rcu_read_lock(); ++ bt = rcu_dereference(q->blk_trace); + if (bt) { + __be64 rpdu = cpu_to_be64(pdu); + +@@ -933,6 +960,7 @@ static void blk_add_trace_split(void *ig + !bio_flagged(bio, BIO_UPTODATE), + sizeof(rpdu), &rpdu); + } ++ rcu_read_unlock(); + } + + /** +@@ -952,11 +980,15 @@ static void blk_add_trace_bio_remap(void + struct request_queue *q, struct bio *bio, + dev_t dev, sector_t from) + { +- struct blk_trace *bt = q->blk_trace; ++ struct blk_trace *bt; + struct blk_io_trace_remap r; + +- if (likely(!bt)) ++ rcu_read_lock(); ++ bt = rcu_dereference(q->blk_trace); ++ if (likely(!bt)) { ++ rcu_read_unlock(); + return; ++ } + + r.device_from = cpu_to_be32(dev); + r.device_to = cpu_to_be32(bio->bi_bdev->bd_dev); +@@ -965,6 +997,7 @@ static void blk_add_trace_bio_remap(void + __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size, + bio->bi_rw, BLK_TA_REMAP, + !bio_flagged(bio, BIO_UPTODATE), sizeof(r), &r); ++ rcu_read_unlock(); + } + + /** +@@ -985,11 +1018,15 @@ static void blk_add_trace_rq_remap(void + struct request *rq, dev_t dev, + sector_t from) + { +- struct blk_trace *bt = q->blk_trace; ++ struct blk_trace *bt; + struct blk_io_trace_remap r; + +- if (likely(!bt)) ++ rcu_read_lock(); ++ bt = rcu_dereference(q->blk_trace); ++ if (likely(!bt)) { ++ rcu_read_unlock(); + return; ++ } + + r.device_from = cpu_to_be32(dev); + r.device_to = cpu_to_be32(disk_devt(rq->rq_disk)); +@@ -998,6 +1035,7 @@ static void blk_add_trace_rq_remap(void + __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq), + rq_data_dir(rq), BLK_TA_REMAP, !!rq->errors, + sizeof(r), &r); ++ rcu_read_unlock(); + } + + /** +@@ -1015,10 +1053,14 @@ void blk_add_driver_data(struct request_ + struct request *rq, + void *data, size_t len) + { +- struct blk_trace *bt = q->blk_trace; ++ struct blk_trace *bt; + +- if (likely(!bt)) ++ rcu_read_lock(); ++ bt = rcu_dereference(q->blk_trace); ++ if (likely(!bt)) { ++ rcu_read_unlock(); + return; ++ } + + if (rq->cmd_type == REQ_TYPE_BLOCK_PC) + __blk_add_trace(bt, 0, blk_rq_bytes(rq), 0, +@@ -1026,6 +1068,7 @@ void blk_add_driver_data(struct request_ + else + __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq), 0, + BLK_TA_DRV_DATA, rq->errors, len, data); ++ rcu_read_unlock(); + } + EXPORT_SYMBOL_GPL(blk_add_driver_data); + +@@ -1537,6 +1580,7 @@ static int blk_trace_remove_queue(struct + spin_lock_irq(&running_trace_lock); + list_del(&bt->running_list); + spin_unlock_irq(&running_trace_lock); ++ synchronize_rcu(); + blk_trace_free(bt); + return 0; + } +@@ -1698,6 +1742,7 @@ static ssize_t sysfs_blk_trace_attr_show + struct hd_struct *p = dev_to_part(dev); + struct request_queue *q; + struct block_device *bdev; ++ struct blk_trace *bt; + ssize_t ret = -ENXIO; + + bdev = bdget(part_devt(p)); +@@ -1710,21 +1755,23 @@ static ssize_t sysfs_blk_trace_attr_show + + mutex_lock(&q->blk_trace_mutex); + ++ bt = rcu_dereference_protected(q->blk_trace, ++ lockdep_is_held(&q->blk_trace_mutex)); + if (attr == &dev_attr_enable) { +- ret = sprintf(buf, "%u\n", !!q->blk_trace); ++ ret = sprintf(buf, "%u\n", !!bt); + goto out_unlock_bdev; + } + +- if (q->blk_trace == NULL) ++ if (bt == NULL) + ret = sprintf(buf, "disabled\n"); + else if (attr == &dev_attr_act_mask) +- ret = blk_trace_mask2str(buf, q->blk_trace->act_mask); ++ ret = blk_trace_mask2str(buf, bt->act_mask); + else if (attr == &dev_attr_pid) +- ret = sprintf(buf, "%u\n", q->blk_trace->pid); ++ ret = sprintf(buf, "%u\n", bt->pid); + else if (attr == &dev_attr_start_lba) +- ret = sprintf(buf, "%llu\n", q->blk_trace->start_lba); ++ ret = sprintf(buf, "%llu\n", bt->start_lba); + else if (attr == &dev_attr_end_lba) +- ret = sprintf(buf, "%llu\n", q->blk_trace->end_lba); ++ ret = sprintf(buf, "%llu\n", bt->end_lba); + + out_unlock_bdev: + mutex_unlock(&q->blk_trace_mutex); +@@ -1741,6 +1788,7 @@ static ssize_t sysfs_blk_trace_attr_stor + struct block_device *bdev; + struct request_queue *q; + struct hd_struct *p; ++ struct blk_trace *bt; + u64 value; + ssize_t ret = -EINVAL; + +@@ -1771,8 +1819,10 @@ static ssize_t sysfs_blk_trace_attr_stor + + mutex_lock(&q->blk_trace_mutex); + ++ bt = rcu_dereference_protected(q->blk_trace, ++ lockdep_is_held(&q->blk_trace_mutex)); + if (attr == &dev_attr_enable) { +- if (!!value == !!q->blk_trace) { ++ if (!!value == !!bt) { + ret = 0; + goto out_unlock_bdev; + } +@@ -1784,18 +1834,18 @@ static ssize_t sysfs_blk_trace_attr_stor + } + + ret = 0; +- if (q->blk_trace == NULL) ++ if (bt == NULL) + ret = blk_trace_setup_queue(q, bdev); + + if (ret == 0) { + if (attr == &dev_attr_act_mask) +- q->blk_trace->act_mask = value; ++ bt->act_mask = value; + else if (attr == &dev_attr_pid) +- q->blk_trace->pid = value; ++ bt->pid = value; + else if (attr == &dev_attr_start_lba) +- q->blk_trace->start_lba = value; ++ bt->start_lba = value; + else if (attr == &dev_attr_end_lba) +- q->blk_trace->end_lba = value; ++ bt->end_lba = value; + } + + out_unlock_bdev: diff --git a/queue-3.16/blktrace-re-write-setting-q-blk_trace.patch b/queue-3.16/blktrace-re-write-setting-q-blk_trace.patch new file mode 100644 index 00000000..dd28d9e5 --- /dev/null +++ b/queue-3.16/blktrace-re-write-setting-q-blk_trace.patch @@ -0,0 +1,82 @@ +From: Davidlohr Bueso <dave@stgolabs.ne> +Date: Fri, 30 Oct 2015 05:25:59 +0900 +Subject: blktrace: re-write setting q->blk_trace + +commit cdea01b2bf98affb7e9c44530108a4a28535eee8 upstream. + +This is really about simplifying the double xchg patterns into +a single cmpxchg, with the same logic. Other than the immediate +cleanup, there are some subtleties this change deals with: + +(i) While the load of the old bt is fully ordered wrt everything, +ie: + + old_bt = xchg(&q->blk_trace, bt); [barrier] + if (old_bt) + (void) xchg(&q->blk_trace, old_bt); [barrier] + +blk_trace could still be changed between the xchg and the old_bt +load. Note that this description is merely theoretical and afaict +very small, but doing everything in a single context with cmpxchg +closes this potential race. + +(ii) Ordering guarantees are obviously kept with cmpxchg. + +(iii) Gets rid of the hacky-by-nature (void)xchg pattern. + +Signed-off-by: Davidlohr Bueso <dbueso@suse.de> +eviewed-by: Jeff Moyer <jmoyer@redhat.com> +Signed-off-by: Jens Axboe <axboe@fb.com> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + kernel/trace/blktrace.c | 16 +++++----------- + 1 file changed, 5 insertions(+), 11 deletions(-) + +--- a/kernel/trace/blktrace.c ++++ b/kernel/trace/blktrace.c +@@ -448,7 +448,7 @@ int do_blk_trace_setup(struct request_qu + struct block_device *bdev, + struct blk_user_trace_setup *buts) + { +- struct blk_trace *old_bt, *bt = NULL; ++ struct blk_trace *bt = NULL; + struct dentry *dir = NULL; + int ret, i; + +@@ -532,11 +532,8 @@ int do_blk_trace_setup(struct request_qu + bt->trace_state = Blktrace_setup; + + ret = -EBUSY; +- old_bt = xchg(&q->blk_trace, bt); +- if (old_bt) { +- (void) xchg(&q->blk_trace, old_bt); ++ if (cmpxchg(&q->blk_trace, NULL, bt)) + goto err; +- } + + if (atomic_inc_return(&blk_probes_ref) == 1) + blk_register_tracepoints(); +@@ -1550,7 +1547,7 @@ static int blk_trace_remove_queue(struct + static int blk_trace_setup_queue(struct request_queue *q, + struct block_device *bdev) + { +- struct blk_trace *old_bt, *bt = NULL; ++ struct blk_trace *bt = NULL; + int ret = -ENOMEM; + + bt = kzalloc(sizeof(*bt), GFP_KERNEL); +@@ -1566,12 +1563,9 @@ static int blk_trace_setup_queue(struct + + blk_trace_setup_lba(bt, bdev); + +- old_bt = xchg(&q->blk_trace, bt); +- if (old_bt != NULL) { +- (void)xchg(&q->blk_trace, old_bt); +- ret = -EBUSY; ++ ret = -EBUSY; ++ if (cmpxchg(&q->blk_trace, NULL, bt)) + goto free_bt; +- } + + if (atomic_inc_return(&blk_probes_ref) == 1) + blk_register_tracepoints(); diff --git a/queue-3.16/floppy-check-fdc-index-for-errors-before-assigning-it.patch b/queue-3.16/floppy-check-fdc-index-for-errors-before-assigning-it.patch new file mode 100644 index 00000000..9285c89b --- /dev/null +++ b/queue-3.16/floppy-check-fdc-index-for-errors-before-assigning-it.patch @@ -0,0 +1,61 @@ +From: Linus Torvalds <torvalds@linux-foundation.org> +Date: Fri, 21 Feb 2020 12:43:35 -0800 +Subject: floppy: check FDC index for errors before assigning it + +commit 2e90ca68b0d2f5548804f22f0dd61145516171e3 upstream. + +Jordy Zomer reported a KASAN out-of-bounds read in the floppy driver in +wait_til_ready(). + +Which on the face of it can't happen, since as Willy Tarreau points out, +the function does no particular memory access. Except through the FDCS +macro, which just indexes a static allocation through teh current fdc, +which is always checked against N_FDC. + +Except the checking happens after we've already assigned the value. + +The floppy driver is a disgrace (a lot of it going back to my original +horrd "design"), and has no real maintainer. Nobody has the hardware, +and nobody really cares. But it still gets used in virtual environment +because it's one of those things that everybody supports. + +The whole thing should be re-written, or at least parts of it should be +seriously cleaned up. The 'current fdc' index, which is used by the +FDCS macro, and which is often shadowed by a local 'fdc' variable, is a +prime example of how not to write code. + +But because nobody has the hardware or the motivation, let's just fix up +the immediate problem with a nasty band-aid: test the fdc index before +actually assigning it to the static 'fdc' variable. + +Reported-by: Jordy Zomer <jordy@simplyhacker.com> +Cc: Willy Tarreau <w@1wt.eu> +Cc: Dan Carpenter <dan.carpenter@oracle.com> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/block/floppy.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/block/floppy.c ++++ b/drivers/block/floppy.c +@@ -847,14 +847,17 @@ static void reset_fdc_info(int mode) + /* selects the fdc and drive, and enables the fdc's input/dma. */ + static void set_fdc(int drive) + { ++ unsigned int new_fdc = fdc; ++ + if (drive >= 0 && drive < N_DRIVE) { +- fdc = FDC(drive); ++ new_fdc = FDC(drive); + current_drive = drive; + } +- if (fdc != 1 && fdc != 0) { ++ if (new_fdc >= N_FDC) { + pr_info("bad fdc value\n"); + return; + } ++ fdc = new_fdc; + set_dor(fdc, ~0, 8); + #if N_FDC > 1 + set_dor(1 - fdc, ~8, 0); diff --git a/queue-3.16/input-add-safety-guards-to-input_set_keycode.patch b/queue-3.16/input-add-safety-guards-to-input_set_keycode.patch new file mode 100644 index 00000000..2ea0fdae --- /dev/null +++ b/queue-3.16/input-add-safety-guards-to-input_set_keycode.patch @@ -0,0 +1,65 @@ +From: Dmitry Torokhov <dmitry.torokhov@gmail.com> +Date: Fri, 13 Dec 2019 14:56:16 -0800 +Subject: Input: add safety guards to input_set_keycode() + +commit cb222aed03d798fc074be55e59d9a112338ee784 upstream. + +If we happen to have a garbage in input device's keycode table with values +too big we'll end up doing clear_bit() with offset way outside of our +bitmaps, damaging other objects within an input device or even outside of +it. Let's add sanity checks to the returned old keycodes. + +Reported-by: syzbot+c769968809f9359b07aa@syzkaller.appspotmail.com +Reported-by: syzbot+76f3a30e88d256644c78@syzkaller.appspotmail.com +Link: https://lore.kernel.org/r/20191207212757.GA245964@dtor-ws +Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/input/input.c | 26 ++++++++++++++++---------- + 1 file changed, 16 insertions(+), 10 deletions(-) + +--- a/drivers/input/input.c ++++ b/drivers/input/input.c +@@ -841,16 +841,18 @@ static int input_default_setkeycode(stru + } + } + +- __clear_bit(*old_keycode, dev->keybit); +- __set_bit(ke->keycode, dev->keybit); +- +- for (i = 0; i < dev->keycodemax; i++) { +- if (input_fetch_keycode(dev, i) == *old_keycode) { +- __set_bit(*old_keycode, dev->keybit); +- break; /* Setting the bit twice is useless, so break */ ++ if (*old_keycode <= KEY_MAX) { ++ __clear_bit(*old_keycode, dev->keybit); ++ for (i = 0; i < dev->keycodemax; i++) { ++ if (input_fetch_keycode(dev, i) == *old_keycode) { ++ __set_bit(*old_keycode, dev->keybit); ++ /* Setting the bit twice is useless, so break */ ++ break; ++ } + } + } + ++ __set_bit(ke->keycode, dev->keybit); + return 0; + } + +@@ -906,9 +908,13 @@ int input_set_keycode(struct input_dev * + * Simulate keyup event if keycode is not present + * in the keymap anymore + */ +- if (test_bit(EV_KEY, dev->evbit) && +- !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && +- __test_and_clear_bit(old_keycode, dev->key)) { ++ if (old_keycode > KEY_MAX) { ++ dev_warn(dev->dev.parent ?: &dev->dev, ++ "%s: got too big old keycode %#x\n", ++ __func__, old_keycode); ++ } else if (test_bit(EV_KEY, dev->evbit) && ++ !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && ++ __test_and_clear_bit(old_keycode, dev->key)) { + struct input_value vals[] = { + { EV_KEY, old_keycode, 0 }, + input_value_sync diff --git a/queue-3.16/kvm-nvmx-don-t-emulate-instructions-in-guest-mode.patch b/queue-3.16/kvm-nvmx-don-t-emulate-instructions-in-guest-mode.patch new file mode 100644 index 00000000..98d774bc --- /dev/null +++ b/queue-3.16/kvm-nvmx-don-t-emulate-instructions-in-guest-mode.patch @@ -0,0 +1,30 @@ +From: Paolo Bonzini <pbonzini@redhat.com> +Date: Tue, 4 Feb 2020 15:26:29 -0800 +Subject: KVM: nVMX: Don't emulate instructions in guest mode + +commit 07721feee46b4b248402133228235318199b05ec upstream. + +vmx_check_intercept is not yet fully implemented. To avoid emulating +instructions disallowed by the L1 hypervisor, refuse to emulate +instructions by default. + +[Made commit, added commit msg - Oliver] +Signed-off-by: Oliver Upton <oupton@google.com> +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> +[bwh: Backported to 3.16: adjust filename, context] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + arch/x86/kvm/vmx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -8938,7 +8938,7 @@ static int vmx_check_intercept(struct kv + struct x86_instruction_info *info, + enum x86_intercept_stage stage) + { +- return X86EMUL_CONTINUE; ++ return X86EMUL_UNHANDLEABLE; + } + + static struct kvm_x86_ops vmx_x86_ops = { diff --git a/queue-3.16/media-ov519-add-missing-endpoint-sanity-checks.patch b/queue-3.16/media-ov519-add-missing-endpoint-sanity-checks.patch new file mode 100644 index 00000000..bc90ab42 --- /dev/null +++ b/queue-3.16/media-ov519-add-missing-endpoint-sanity-checks.patch @@ -0,0 +1,50 @@ +From: Johan Hovold <johan@kernel.org> +Date: Fri, 3 Jan 2020 17:35:09 +0100 +Subject: media: ov519: add missing endpoint sanity checks + +commit 998912346c0da53a6dbb71fab3a138586b596b30 upstream. + +Make sure to check that we have at least one endpoint before accessing +the endpoint array to avoid dereferencing a NULL-pointer on stream +start. + +Note that these sanity checks are not redundant as the driver is mixing +looking up altsettings by index and by number, which need not coincide. + +Fixes: 1876bb923c98 ("V4L/DVB (12079): gspca_ov519: add support for the ov511 bridge") +Fixes: b282d87332f5 ("V4L/DVB (12080): gspca_ov519: Fix ov518+ with OV7620AE (Trust spacecam 320)") +Cc: Hans de Goede <hdegoede@redhat.com> +Signed-off-by: Johan Hovold <johan@kernel.org> +Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> +Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/media/usb/gspca/ov519.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/media/usb/gspca/ov519.c ++++ b/drivers/media/usb/gspca/ov519.c +@@ -3497,6 +3497,11 @@ static void ov511_mode_init_regs(struct + return; + } + ++ if (alt->desc.bNumEndpoints < 1) { ++ sd->gspca_dev.usb_err = -ENODEV; ++ return; ++ } ++ + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + reg_w(sd, R51x_FIFO_PSIZE, packet_size >> 5); + +@@ -3622,6 +3627,11 @@ static void ov518_mode_init_regs(struct + return; + } + ++ if (alt->desc.bNumEndpoints < 1) { ++ sd->gspca_dev.usb_err = -ENODEV; ++ return; ++ } ++ + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + ov518_reg_w32(sd, R51x_FIFO_PSIZE, packet_size & ~7, 2); + diff --git a/queue-3.16/media-stv06xx-add-missing-descriptor-sanity-checks.patch b/queue-3.16/media-stv06xx-add-missing-descriptor-sanity-checks.patch new file mode 100644 index 00000000..331ad4e2 --- /dev/null +++ b/queue-3.16/media-stv06xx-add-missing-descriptor-sanity-checks.patch @@ -0,0 +1,88 @@ +From: Johan Hovold <johan@kernel.org> +Date: Fri, 3 Jan 2020 17:35:10 +0100 +Subject: media: stv06xx: add missing descriptor sanity checks + +commit 485b06aadb933190f4bc44e006076bc27a23f205 upstream. + +Make sure to check that we have two alternate settings and at least one +endpoint before accessing the second altsetting structure and +dereferencing the endpoint arrays. + +This specifically avoids dereferencing NULL-pointers or corrupting +memory when a device does not have the expected descriptors. + +Note that the sanity checks in stv06xx_start() and pb0100_start() are +not redundant as the driver is mixing looking up altsettings by index +and by number, which may not coincide. + +Fixes: 8668d504d72c ("V4L/DVB (12082): gspca_stv06xx: Add support for st6422 bridge and sensor") +Fixes: c0b33bdc5b8d ("[media] gspca-stv06xx: support bandwidth changing") +Cc: Hans de Goede <hdegoede@redhat.com> +Signed-off-by: Johan Hovold <johan@kernel.org> +Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> +Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/media/usb/gspca/stv06xx/stv06xx.c | 19 ++++++++++++++++++- + .../media/usb/gspca/stv06xx/stv06xx_pb0100.c | 4 ++++ + 2 files changed, 22 insertions(+), 1 deletion(-) + +--- a/drivers/media/usb/gspca/stv06xx/stv06xx.c ++++ b/drivers/media/usb/gspca/stv06xx/stv06xx.c +@@ -293,6 +293,9 @@ static int stv06xx_start(struct gspca_de + return -EIO; + } + ++ if (alt->desc.bNumEndpoints < 1) ++ return -ENODEV; ++ + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + err = stv06xx_write_bridge(sd, STV_ISO_SIZE_L, packet_size); + if (err < 0) +@@ -317,11 +320,21 @@ out: + + static int stv06xx_isoc_init(struct gspca_dev *gspca_dev) + { ++ struct usb_interface_cache *intfc; + struct usb_host_interface *alt; + struct sd *sd = (struct sd *) gspca_dev; + ++ intfc = gspca_dev->dev->actconfig->intf_cache[0]; ++ ++ if (intfc->num_altsetting < 2) ++ return -ENODEV; ++ ++ alt = &intfc->altsetting[1]; ++ ++ if (alt->desc.bNumEndpoints < 1) ++ return -ENODEV; ++ + /* Start isoc bandwidth "negotiation" at max isoc bandwidth */ +- alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; + alt->endpoint[0].desc.wMaxPacketSize = + cpu_to_le16(sd->sensor->max_packet_size[gspca_dev->curr_mode]); + +@@ -334,6 +347,10 @@ static int stv06xx_isoc_nego(struct gspc + struct usb_host_interface *alt; + struct sd *sd = (struct sd *) gspca_dev; + ++ /* ++ * Existence of altsetting and endpoint was verified in ++ * stv06xx_isoc_init() ++ */ + alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + min_packet_size = sd->sensor->min_packet_size[gspca_dev->curr_mode]; +--- a/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c ++++ b/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c +@@ -198,6 +198,10 @@ static int pb0100_start(struct sd *sd) + alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); + if (!alt) + return -ENODEV; ++ ++ if (alt->desc.bNumEndpoints < 1) ++ return -ENODEV; ++ + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + + /* If we don't have enough bandwidth use a lower framerate */ diff --git a/queue-3.16/media-xirlink_cit-add-missing-descriptor-sanity-checks.patch b/queue-3.16/media-xirlink_cit-add-missing-descriptor-sanity-checks.patch new file mode 100644 index 00000000..42593a74 --- /dev/null +++ b/queue-3.16/media-xirlink_cit-add-missing-descriptor-sanity-checks.patch @@ -0,0 +1,77 @@ +From: Johan Hovold <johan@kernel.org> +Date: Fri, 3 Jan 2020 17:35:11 +0100 +Subject: media: xirlink_cit: add missing descriptor sanity checks + +commit a246b4d547708f33ff4d4b9a7a5dbac741dc89d8 upstream. + +Make sure to check that we have two alternate settings and at least one +endpoint before accessing the second altsetting structure and +dereferencing the endpoint arrays. + +This specifically avoids dereferencing NULL-pointers or corrupting +memory when a device does not have the expected descriptors. + +Note that the sanity check in cit_get_packet_size() is not redundant as +the driver is mixing looking up altsettings by index and by number, +which may not coincide. + +Fixes: 659fefa0eb17 ("V4L/DVB: gspca_xirlink_cit: Add support for camera with a bcd version of 0.01") +Fixes: 59f8b0bf3c12 ("V4L/DVB: gspca_xirlink_cit: support bandwidth changing for devices with 1 alt setting") +Cc: Hans de Goede <hdegoede@redhat.com> +Signed-off-by: Johan Hovold <johan@kernel.org> +Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> +Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/media/usb/gspca/xirlink_cit.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +--- a/drivers/media/usb/gspca/xirlink_cit.c ++++ b/drivers/media/usb/gspca/xirlink_cit.c +@@ -1455,6 +1455,9 @@ static int cit_get_packet_size(struct gs + return -EIO; + } + ++ if (alt->desc.bNumEndpoints < 1) ++ return -ENODEV; ++ + return le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + } + +@@ -2632,6 +2635,7 @@ static int sd_start(struct gspca_dev *gs + + static int sd_isoc_init(struct gspca_dev *gspca_dev) + { ++ struct usb_interface_cache *intfc; + struct usb_host_interface *alt; + int max_packet_size; + +@@ -2647,8 +2651,17 @@ static int sd_isoc_init(struct gspca_dev + break; + } + ++ intfc = gspca_dev->dev->actconfig->intf_cache[0]; ++ ++ if (intfc->num_altsetting < 2) ++ return -ENODEV; ++ ++ alt = &intfc->altsetting[1]; ++ ++ if (alt->desc.bNumEndpoints < 1) ++ return -ENODEV; ++ + /* Start isoc bandwidth "negotiation" at max isoc bandwidth */ +- alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; + alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(max_packet_size); + + return 0; +@@ -2671,6 +2684,9 @@ static int sd_isoc_nego(struct gspca_dev + break; + } + ++ /* ++ * Existence of altsetting and endpoint was verified in sd_isoc_init() ++ */ + alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + if (packet_size <= min_packet_size) diff --git a/queue-3.16/mm-mempolicy-require-at-least-one-nodeid-for-mpol_preferred.patch b/queue-3.16/mm-mempolicy-require-at-least-one-nodeid-for-mpol_preferred.patch new file mode 100644 index 00000000..121a8f26 --- /dev/null +++ b/queue-3.16/mm-mempolicy-require-at-least-one-nodeid-for-mpol_preferred.patch @@ -0,0 +1,52 @@ +From: Randy Dunlap <rdunlap@infradead.org> +Date: Wed, 1 Apr 2020 21:10:58 -0700 +Subject: mm: mempolicy: require at least one nodeid for MPOL_PREFERRED + +commit aa9f7d5172fac9bf1f09e678c35e287a40a7b7dd upstream. + +Using an empty (malformed) nodelist that is not caught during mount option +parsing leads to a stack-out-of-bounds access. + +The option string that was used was: "mpol=prefer:,". However, +MPOL_PREFERRED requires a single node number, which is not being provided +here. + +Add a check that 'nodes' is not empty after parsing for MPOL_PREFERRED's +nodeid. + +Fixes: 095f1fc4ebf3 ("mempolicy: rework shmem mpol parsing and display") +Reported-by: Entropy Moe <3ntr0py1337@gmail.com> +Reported-by: syzbot+b055b1a6b2b958707a21@syzkaller.appspotmail.com +Signed-off-by: Randy Dunlap <rdunlap@infradead.org> +Signed-off-by: Andrew Morton <akpm@linux-foundation.org> +Tested-by: syzbot+b055b1a6b2b958707a21@syzkaller.appspotmail.com +Cc: Lee Schermerhorn <lee.schermerhorn@hp.com> +Link: http://lkml.kernel.org/r/89526377-7eb6-b662-e1d8-4430928abde9@infradead.org +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + mm/mempolicy.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/mm/mempolicy.c ++++ b/mm/mempolicy.c +@@ -2711,7 +2711,9 @@ int mpol_parse_str(char *str, struct mem + switch (mode) { + case MPOL_PREFERRED: + /* +- * Insist on a nodelist of one node only ++ * Insist on a nodelist of one node only, although later ++ * we use first_node(nodes) to grab a single node, so here ++ * nodelist (or nodes) cannot be empty. + */ + if (nodelist) { + char *rest = nodelist; +@@ -2719,6 +2721,8 @@ int mpol_parse_str(char *str, struct mem + rest++; + if (*rest) + goto out; ++ if (nodes_empty(nodes)) ++ goto out; + } + break; + case MPOL_INTERLEAVE: diff --git a/queue-3.16/net-ipv6_stub-use-ip6_dst_lookup_flow-instead-of-ip6_dst_lookup.patch b/queue-3.16/net-ipv6_stub-use-ip6_dst_lookup_flow-instead-of-ip6_dst_lookup.patch new file mode 100644 index 00000000..00888e58 --- /dev/null +++ b/queue-3.16/net-ipv6_stub-use-ip6_dst_lookup_flow-instead-of-ip6_dst_lookup.patch @@ -0,0 +1,67 @@ +From: Sabrina Dubroca <sd@queasysnail.net> +Date: Wed, 4 Dec 2019 15:35:53 +0100 +Subject: net: ipv6_stub: use ip6_dst_lookup_flow instead of ip6_dst_lookup + +commit 6c8991f41546c3c472503dff1ea9daaddf9331c2 upstream. + +ipv6_stub uses the ip6_dst_lookup function to allow other modules to +perform IPv6 lookups. However, this function skips the XFRM layer +entirely. + +All users of ipv6_stub->ip6_dst_lookup use ip_route_output_flow (via the +ip_route_output_key and ip_route_output helpers) for their IPv4 lookups, +which calls xfrm_lookup_route(). This patch fixes this inconsistent +behavior by switching the stub to ip6_dst_lookup_flow, which also calls +xfrm_lookup_route(). + +This requires some changes in all the callers, as these two functions +take different arguments and have different return types. + +Fixes: 5f81bd2e5d80 ("ipv6: export a stub for IPv6 symbols used by vxlan") +Reported-by: Xiumei Mu <xmu@redhat.com> +Signed-off-by: Sabrina Dubroca <sd@queasysnail.net> +Signed-off-by: David S. Miller <davem@davemloft.net> +[bwh: Backported to 3.16: + - Only vxlan uses this operation + - Neither ip6_dst_lookup() nor ip6_dst_lookup_flow() takes a struct net + pointer argument here + - Adjust filename, context] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- +--- a/drivers/net/vxlan.c ++++ b/drivers/net/vxlan.c +@@ -1929,7 +1929,8 @@ static void vxlan_xmit_one(struct sk_buf + fl6.saddr = vxlan->saddr.sin6.sin6_addr; + fl6.flowi6_proto = IPPROTO_UDP; + +- if (ipv6_stub->ipv6_dst_lookup(sk, &ndst, &fl6)) { ++ ndst = ipv6_stub->ipv6_dst_lookup_flow(sk, &fl6, NULL); ++ if (unlikely(IS_ERR(ndst))) { + netdev_dbg(dev, "no route to %pI6\n", + &dst->sin6.sin6_addr); + dev->stats.tx_carrier_errors++; +--- a/include/net/addrconf.h ++++ b/include/net/addrconf.h +@@ -156,8 +156,9 @@ struct ipv6_stub { + const struct in6_addr *addr); + int (*ipv6_sock_mc_drop)(struct sock *sk, int ifindex, + const struct in6_addr *addr); +- int (*ipv6_dst_lookup)(struct sock *sk, struct dst_entry **dst, +- struct flowi6 *fl6); ++ struct dst_entry *(*ipv6_dst_lookup_flow)(struct sock *sk, ++ struct flowi6 *fl6, ++ const struct in6_addr *final_dst); + void (*udpv6_encap_enable)(void); + void (*ndisc_send_na)(struct net_device *dev, struct neighbour *neigh, + const struct in6_addr *daddr, +--- a/net/ipv6/af_inet6.c ++++ b/net/ipv6/af_inet6.c +@@ -820,7 +820,7 @@ static struct pernet_operations inet6_ne + static const struct ipv6_stub ipv6_stub_impl = { + .ipv6_sock_mc_join = ipv6_sock_mc_join, + .ipv6_sock_mc_drop = ipv6_sock_mc_drop, +- .ipv6_dst_lookup = ip6_dst_lookup, ++ .ipv6_dst_lookup_flow = ip6_dst_lookup_flow, + .udpv6_encap_enable = udpv6_encap_enable, + .ndisc_send_na = ndisc_send_na, + .nd_tbl = &nd_tbl, diff --git a/queue-3.16/series b/queue-3.16/series index 832f93c0..dab52b70 100644 --- a/queue-3.16/series +++ b/queue-3.16/series @@ -208,3 +208,22 @@ net_sched-fix-datalen-for-ematch.patch namei-allow-restricted-o_creat-of-fifos-and-regular-files.patch do_last-fetch-directory-i_mode-and-i_uid-before-it-s-too-late.patch vfs-fix-do_last-regression.patch +blktrace-re-write-setting-q-blk_trace.patch +blktrace-protect-q-blk_trace-with-rcu.patch +blktrace-fix-dereference-after-null-check.patch +input-add-safety-guards-to-input_set_keycode.patch +staging-android-ashmem-disallow-ashmem-memory-from-being-remapped.patch +net-ipv6_stub-use-ip6_dst_lookup_flow-instead-of-ip6_dst_lookup.patch +kvm-nvmx-don-t-emulate-instructions-in-guest-mode.patch +vgacon-fix-a-uaf-in-vgacon_invert_region.patch +tty-vt-fix-task_running-diagnostic-warning-from-paste_selection.patch +vt-selection-handle-pending-signals-in-paste_selection.patch +vt-selection-close-sel_buffer-race.patch +vt-selection-push-console-lock-down.patch +vt-selection-push-sel_lock-up.patch +floppy-check-fdc-index-for-errors-before-assigning-it.patch +vhost-check-docket-sk_family-instead-of-call-getname.patch +mm-mempolicy-require-at-least-one-nodeid-for-mpol_preferred.patch +media-ov519-add-missing-endpoint-sanity-checks.patch +media-stv06xx-add-missing-descriptor-sanity-checks.patch +media-xirlink_cit-add-missing-descriptor-sanity-checks.patch diff --git a/queue-3.16/staging-android-ashmem-disallow-ashmem-memory-from-being-remapped.patch b/queue-3.16/staging-android-ashmem-disallow-ashmem-memory-from-being-remapped.patch new file mode 100644 index 00000000..99f687eb --- /dev/null +++ b/queue-3.16/staging-android-ashmem-disallow-ashmem-memory-from-being-remapped.patch @@ -0,0 +1,69 @@ +From: Suren Baghdasaryan <surenb@google.com> +Date: Mon, 27 Jan 2020 15:56:16 -0800 +Subject: staging: android: ashmem: Disallow ashmem memory from being remapped + +commit 6d67b0290b4b84c477e6a2fc6e005e174d3c7786 upstream. + +When ashmem file is mmapped, the resulting vma->vm_file points to the +backing shmem file with the generic fops that do not check ashmem +permissions like fops of ashmem do. If an mremap is done on the ashmem +region, then the permission checks will be skipped. Fix that by disallowing +mapping operation on the backing shmem file. + +Reported-by: Jann Horn <jannh@google.com> +Signed-off-by: Suren Baghdasaryan <surenb@google.com> +Signed-off-by: Todd Kjos <tkjos@google.com> +Reviewed-by: Joel Fernandes (Google) <joel@joelfernandes.org> +Link: https://lore.kernel.org/r/20200127235616.48920-1-tkjos@google.com +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/staging/android/ashmem.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +--- a/drivers/staging/android/ashmem.c ++++ b/drivers/staging/android/ashmem.c +@@ -351,8 +351,23 @@ static inline vm_flags_t calc_vm_may_fla + _calc_vm_trans(prot, PROT_EXEC, VM_MAYEXEC); + } + ++static int ashmem_vmfile_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ /* do not allow to mmap ashmem backing shmem file directly */ ++ return -EPERM; ++} ++ ++static unsigned long ++ashmem_vmfile_get_unmapped_area(struct file *file, unsigned long addr, ++ unsigned long len, unsigned long pgoff, ++ unsigned long flags) ++{ ++ return current->mm->get_unmapped_area(file, addr, len, pgoff, flags); ++} ++ + static int ashmem_mmap(struct file *file, struct vm_area_struct *vma) + { ++ static struct file_operations vmfile_fops; + struct ashmem_area *asma = file->private_data; + int ret = 0; + +@@ -386,6 +401,19 @@ static int ashmem_mmap(struct file *file + goto out; + } + asma->file = vmfile; ++ /* ++ * override mmap operation of the vmfile so that it can't be ++ * remapped which would lead to creation of a new vma with no ++ * asma permission checks. Have to override get_unmapped_area ++ * as well to prevent VM_BUG_ON check for f_ops modification. ++ */ ++ if (!vmfile_fops.mmap) { ++ vmfile_fops = *vmfile->f_op; ++ vmfile_fops.mmap = ashmem_vmfile_mmap; ++ vmfile_fops.get_unmapped_area = ++ ashmem_vmfile_get_unmapped_area; ++ } ++ vmfile->f_op = &vmfile_fops; + } + get_file(asma->file); + diff --git a/queue-3.16/tty-vt-fix-task_running-diagnostic-warning-from-paste_selection.patch b/queue-3.16/tty-vt-fix-task_running-diagnostic-warning-from-paste_selection.patch new file mode 100644 index 00000000..25c0b98e --- /dev/null +++ b/queue-3.16/tty-vt-fix-task_running-diagnostic-warning-from-paste_selection.patch @@ -0,0 +1,70 @@ +From: Peter Hurley <peter@hurleysoftware.com> +Date: Sun, 12 Jul 2015 20:47:35 -0400 +Subject: tty: vt: Fix !TASK_RUNNING diagnostic warning from paste_selection() + +commit 61e86cc90af49cecef9c54ccea1f572fbcb695ac upstream. + +Pasting text with gpm on a VC produced warning [1]. Reset task state +to TASK_RUNNING in the paste_selection() loop, if the loop did not +sleep. + +[1] +WARNING: CPU: 6 PID: 1960 at /home/peter/src/kernels/mainline/kernel/sched/core.c:7286 __might_sleep+0x7f/0x90() +do not call blocking ops when !TASK_RUNNING; state=1 set at [<ffffffff8151805e>] paste_selection+0x9e/0x1a0 +Modules linked in: btrfs xor raid6_pq ufs qnx4 hfsplus hfs minix ntfs msdos jfs xfs libcrc32c ..... +CPU: 6 PID: 1960 Comm: gpm Not tainted 4.1.0-rc7+tty-xeon+debug #rc7+tty +Hardware name: Dell Inc. Precision WorkStation T5400 /0RW203, BIOS A11 04/30/2012 + ffffffff81c9c0a0 ffff8802b0fd3ac8 ffffffff8185778a 0000000000000001 + ffff8802b0fd3b18 ffff8802b0fd3b08 ffffffff8108039a ffffffff82ae8510 + ffffffff81c9ce00 0000000000000015 0000000000000000 0000000000000000 +Call Trace: + [<ffffffff8185778a>] dump_stack+0x4f/0x7b + [<ffffffff8108039a>] warn_slowpath_common+0x8a/0xc0 + [<ffffffff81080416>] warn_slowpath_fmt+0x46/0x50 + [<ffffffff810ddced>] ? __lock_acquire+0xe2d/0x13a0 + [<ffffffff8151805e>] ? paste_selection+0x9e/0x1a0 + [<ffffffff8151805e>] ? paste_selection+0x9e/0x1a0 + [<ffffffff810ad4ff>] __might_sleep+0x7f/0x90 + [<ffffffff8185f76a>] down_read+0x2a/0xa0 + [<ffffffff810bb1d8>] ? sched_clock_cpu+0xb8/0xe0 + [<ffffffff8150d1dc>] n_tty_receive_buf_common+0x4c/0xba0 + [<ffffffff810dc875>] ? mark_held_locks+0x75/0xa0 + [<ffffffff81861c95>] ? _raw_spin_unlock_irqrestore+0x65/0x80 + [<ffffffff810b49a1>] ? get_parent_ip+0x11/0x50 + [<ffffffff8150dd44>] n_tty_receive_buf2+0x14/0x20 + [<ffffffff81518117>] paste_selection+0x157/0x1a0 + [<ffffffff810b77b0>] ? wake_up_state+0x20/0x20 + [<ffffffff815203f8>] tioclinux+0xb8/0x2c0 + [<ffffffff81515bfe>] vt_ioctl+0xaee/0x11a0 + [<ffffffff810baf75>] ? sched_clock_local+0x25/0x90 + [<ffffffff810bbe11>] ? vtime_account_user+0x91/0xa0 + [<ffffffff8150810c>] tty_ioctl+0x20c/0xe20 + [<ffffffff810bbe11>] ? vtime_account_user+0x91/0xa0 + [<ffffffff810b49a1>] ? get_parent_ip+0x11/0x50 + [<ffffffff810b4a69>] ? preempt_count_sub+0x49/0x50 + [<ffffffff811ab71c>] ? context_tracking_exit+0x5c/0x290 + [<ffffffff811ab71c>] ? context_tracking_exit+0x5c/0x290 + [<ffffffff81248b98>] do_vfs_ioctl+0x318/0x570 + [<ffffffff810dca8d>] ? trace_hardirqs_on+0xd/0x10 + [<ffffffff810dc9b5>] ? trace_hardirqs_on_caller+0x115/0x1e0 + [<ffffffff81254acc>] ? __fget_light+0x6c/0xa0 + [<ffffffff81248e71>] SyS_ioctl+0x81/0xa0 + [<ffffffff81862832>] system_call_fastpath+0x16/0x7a + +Signed-off-by: Peter Hurley <peter@hurleysoftware.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/tty/vt/selection.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/tty/vt/selection.c ++++ b/drivers/tty/vt/selection.c +@@ -356,6 +356,7 @@ int paste_selection(struct tty_struct *t + schedule(); + continue; + } ++ __set_current_state(TASK_RUNNING); + count = sel_buffer_lth - pasted; + count = tty_ldisc_receive_buf(ld, sel_buffer + pasted, NULL, + count); diff --git a/queue-3.16/vgacon-fix-a-uaf-in-vgacon_invert_region.patch b/queue-3.16/vgacon-fix-a-uaf-in-vgacon_invert_region.patch new file mode 100644 index 00000000..931b9411 --- /dev/null +++ b/queue-3.16/vgacon-fix-a-uaf-in-vgacon_invert_region.patch @@ -0,0 +1,125 @@ +From: Zhang Xiaoxu <zhangxiaoxu5@huawei.com> +Date: Wed, 4 Mar 2020 10:24:29 +0800 +Subject: vgacon: Fix a UAF in vgacon_invert_region + +commit 513dc792d6060d5ef572e43852683097a8420f56 upstream. + +When syzkaller tests, there is a UAF: + BUG: KASan: use after free in vgacon_invert_region+0x9d/0x110 at addr + ffff880000100000 + Read of size 2 by task syz-executor.1/16489 + page:ffffea0000004000 count:0 mapcount:-127 mapping: (null) + index:0x0 + page flags: 0xfffff00000000() + page dumped because: kasan: bad access detected + CPU: 1 PID: 16489 Comm: syz-executor.1 Not tainted + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS + rel-1.9.3-0-ge2fc41e-prebuilt.qemu-project.org 04/01/2014 + Call Trace: + [<ffffffffb119f309>] dump_stack+0x1e/0x20 + [<ffffffffb04af957>] kasan_report+0x577/0x950 + [<ffffffffb04ae652>] __asan_load2+0x62/0x80 + [<ffffffffb090f26d>] vgacon_invert_region+0x9d/0x110 + [<ffffffffb0a39d95>] invert_screen+0xe5/0x470 + [<ffffffffb0a21dcb>] set_selection+0x44b/0x12f0 + [<ffffffffb0a3bfae>] tioclinux+0xee/0x490 + [<ffffffffb0a1d114>] vt_ioctl+0xff4/0x2670 + [<ffffffffb0a0089a>] tty_ioctl+0x46a/0x1a10 + [<ffffffffb052db3d>] do_vfs_ioctl+0x5bd/0xc40 + [<ffffffffb052e2f2>] SyS_ioctl+0x132/0x170 + [<ffffffffb11c9b1b>] system_call_fastpath+0x22/0x27 + Memory state around the buggy address: + ffff8800000fff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + ffff8800000fff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 + >ffff880000100000: ff ff ff ff ff ff ff ff ff ff ff ff ff + ff ff ff + +It can be reproduce in the linux mainline by the program: + #include <stdio.h> + #include <stdlib.h> + #include <unistd.h> + #include <fcntl.h> + #include <sys/types.h> + #include <sys/stat.h> + #include <sys/ioctl.h> + #include <linux/vt.h> + + struct tiocl_selection { + unsigned short xs; /* X start */ + unsigned short ys; /* Y start */ + unsigned short xe; /* X end */ + unsigned short ye; /* Y end */ + unsigned short sel_mode; /* selection mode */ + }; + + #define TIOCL_SETSEL 2 + struct tiocl { + unsigned char type; + unsigned char pad; + struct tiocl_selection sel; + }; + + int main() + { + int fd = 0; + const char *dev = "/dev/char/4:1"; + + struct vt_consize v = {0}; + struct tiocl tioc = {0}; + + fd = open(dev, O_RDWR, 0); + + v.v_rows = 3346; + ioctl(fd, VT_RESIZEX, &v); + + tioc.type = TIOCL_SETSEL; + ioctl(fd, TIOCLINUX, &tioc); + + return 0; + } + +When resize the screen, update the 'vc->vc_size_row' to the new_row_size, +but when 'set_origin' in 'vgacon_set_origin', vgacon use 'vga_vram_base' +for 'vc_origin' and 'vc_visible_origin', not 'vc_screenbuf'. It maybe +smaller than 'vc_screenbuf'. When TIOCLINUX, use the new_row_size to calc +the offset, it maybe larger than the vga_vram_size in vgacon driver, then +bad access. +Also, if set an larger screenbuf firstly, then set an more larger +screenbuf, when copy old_origin to new_origin, a bad access may happen. + +So, If the screen size larger than vga_vram, resize screen should be +failed. This alse fix CVE-2020-8649 and CVE-2020-8647. + +Linus pointed out that overflow checking seems absent. We're saved by +the existing bounds checks in vc_do_resize() with rather strict +limits: + + if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW) + return -EINVAL; + +Fixes: 0aec4867dca14 ("[PATCH] SVGATextMode fix") +Reference: CVE-2020-8647 and CVE-2020-8649 +Reported-by: Hulk Robot <hulkci@huawei.com> +Signed-off-by: Zhang Xiaoxu <zhangxiaoxu5@huawei.com> +[danvet: augment commit message to point out overflow safety] +Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> +Link: https://patchwork.freedesktop.org/patch/msgid/20200304022429.37738-1-zhangxiaoxu5@huawei.com +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/video/console/vgacon.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/video/console/vgacon.c ++++ b/drivers/video/console/vgacon.c +@@ -1312,6 +1312,9 @@ static int vgacon_font_get(struct vc_dat + static int vgacon_resize(struct vc_data *c, unsigned int width, + unsigned int height, unsigned int user) + { ++ if ((width << 1) * height > vga_vram_size) ++ return -EINVAL; ++ + if (width % 2 || width > screen_info.orig_video_cols || + height > (screen_info.orig_video_lines * vga_default_font_height)/ + c->vc_font.height) diff --git a/queue-3.16/vhost-check-docket-sk_family-instead-of-call-getname.patch b/queue-3.16/vhost-check-docket-sk_family-instead-of-call-getname.patch new file mode 100644 index 00000000..3b21a915 --- /dev/null +++ b/queue-3.16/vhost-check-docket-sk_family-instead-of-call-getname.patch @@ -0,0 +1,54 @@ +From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= <eperezma@redhat.com> +Date: Fri, 21 Feb 2020 12:06:56 +0100 +Subject: vhost: Check docket sk_family instead of call getname +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 42d84c8490f9f0931786f1623191fcab397c3d64 upstream. + +Doing so, we save one call to get data we already have in the struct. + +Also, since there is no guarantee that getname use sockaddr_ll +parameter beyond its size, we add a little bit of security here. +It should do not do beyond MAX_ADDR_LEN, but syzbot found that +ax25_getname writes more (72 bytes, the size of full_sockaddr_ax25, +versus 20 + 32 bytes of sockaddr_ll + MAX_ADDR_LEN in syzbot repro). + +Fixes: 3a4d5c94e9593 ("vhost_net: a kernel-level virtio server") +Reported-by: syzbot+f2a62d07a5198c819c7b@syzkaller.appspotmail.com +Signed-off-by: Eugenio PĂ©rez <eperezma@redhat.com> +Acked-by: Michael S. Tsirkin <mst@redhat.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +[bwh: Backported to 3.16: Also delete "uaddr_len" variable] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- +--- a/drivers/vhost/net.c ++++ b/drivers/vhost/net.c +@@ -843,11 +843,7 @@ static int vhost_net_release(struct inod + + static struct socket *get_raw_socket(int fd) + { +- struct { +- struct sockaddr_ll sa; +- char buf[MAX_ADDR_LEN]; +- } uaddr; +- int uaddr_len = sizeof uaddr, r; ++ int r; + struct socket *sock = sockfd_lookup(fd, &r); + + if (!sock) +@@ -859,12 +855,7 @@ static struct socket *get_raw_socket(int + goto err; + } + +- r = sock->ops->getname(sock, (struct sockaddr *)&uaddr.sa, +- &uaddr_len, 0); +- if (r) +- goto err; +- +- if (uaddr.sa.sll_family != AF_PACKET) { ++ if (sock->sk->sk_family != AF_PACKET) { + r = -EPFNOSUPPORT; + goto err; + } diff --git a/queue-3.16/vt-selection-close-sel_buffer-race.patch b/queue-3.16/vt-selection-close-sel_buffer-race.patch new file mode 100644 index 00000000..95c5825c --- /dev/null +++ b/queue-3.16/vt-selection-close-sel_buffer-race.patch @@ -0,0 +1,152 @@ +From: Jiri Slaby <jslaby@suse.cz> +Date: Mon, 10 Feb 2020 09:11:31 +0100 +Subject: vt: selection, close sel_buffer race + +commit 07e6124a1a46b4b5a9b3cacc0c306b50da87abf5 upstream. + +syzkaller reported this UAF: +BUG: KASAN: use-after-free in n_tty_receive_buf_common+0x2481/0x2940 drivers/tty/n_tty.c:1741 +Read of size 1 at addr ffff8880089e40e9 by task syz-executor.1/13184 + +CPU: 0 PID: 13184 Comm: syz-executor.1 Not tainted 5.4.7 #1 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014 +Call Trace: +... + kasan_report+0xe/0x20 mm/kasan/common.c:634 + n_tty_receive_buf_common+0x2481/0x2940 drivers/tty/n_tty.c:1741 + tty_ldisc_receive_buf+0xac/0x190 drivers/tty/tty_buffer.c:461 + paste_selection+0x297/0x400 drivers/tty/vt/selection.c:372 + tioclinux+0x20d/0x4e0 drivers/tty/vt/vt.c:3044 + vt_ioctl+0x1bcf/0x28d0 drivers/tty/vt/vt_ioctl.c:364 + tty_ioctl+0x525/0x15a0 drivers/tty/tty_io.c:2657 + vfs_ioctl fs/ioctl.c:47 [inline] + +It is due to a race between parallel paste_selection (TIOCL_PASTESEL) +and set_selection_user (TIOCL_SETSEL) invocations. One uses sel_buffer, +while the other frees it and reallocates a new one for another +selection. Add a mutex to close this race. + +The mutex takes care properly of sel_buffer and sel_buffer_lth only. The +other selection global variables (like sel_start, sel_end, and sel_cons) +are protected only in set_selection_user. The other functions need quite +some more work to close the races of the variables there. This is going +to happen later. + +This likely fixes (I am unsure as there is no reproducer provided) bug +206361 too. It was marked as CVE-2020-8648. + +Signed-off-by: Jiri Slaby <jslaby@suse.cz> +Reported-by: syzbot+59997e8d5cbdc486e6f6@syzkaller.appspotmail.com +References: https://bugzilla.kernel.org/show_bug.cgi?id=206361 +Link: https://lore.kernel.org/r/20200210081131.23572-2-jslaby@suse.cz +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +[bwh: Backported to 3.16: adjust context] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/tty/vt/selection.c | 23 +++++++++++++++++------ + 1 file changed, 17 insertions(+), 6 deletions(-) + +--- a/drivers/tty/vt/selection.c ++++ b/drivers/tty/vt/selection.c +@@ -13,6 +13,7 @@ + #include <linux/tty.h> + #include <linux/sched.h> + #include <linux/mm.h> ++#include <linux/mutex.h> + #include <linux/slab.h> + #include <linux/types.h> + +@@ -40,6 +41,7 @@ static volatile int sel_start = -1; /* + static int sel_end; + static int sel_buffer_lth; + static char *sel_buffer; ++static DEFINE_MUTEX(sel_lock); + + /* clear_selection, highlight and highlight_pointer can be called + from interrupt (via scrollback/front) */ +@@ -163,7 +165,7 @@ int set_selection(const struct tiocl_sel + char *bp, *obp; + int i, ps, pe, multiplier; + u16 c; +- int mode; ++ int mode, ret = 0; + + poke_blanked_console(); + +@@ -203,6 +205,7 @@ int set_selection(const struct tiocl_sel + pe = tmp; + } + ++ mutex_lock(&sel_lock); + if (sel_cons != vc_cons[fg_console].d) { + clear_selection(); + sel_cons = vc_cons[fg_console].d; +@@ -248,9 +251,10 @@ int set_selection(const struct tiocl_sel + break; + case TIOCL_SELPOINTER: + highlight_pointer(pe); +- return 0; ++ goto unlock; + default: +- return -EINVAL; ++ ret = -EINVAL; ++ goto unlock; + } + + /* remove the pointer */ +@@ -272,7 +276,7 @@ int set_selection(const struct tiocl_sel + else if (new_sel_start == sel_start) + { + if (new_sel_end == sel_end) /* no action required */ +- return 0; ++ goto unlock; + else if (new_sel_end > sel_end) /* extend to right */ + highlight(sel_end + 2, new_sel_end); + else /* contract from right */ +@@ -299,7 +303,8 @@ int set_selection(const struct tiocl_sel + if (!bp) { + printk(KERN_WARNING "selection: kmalloc() failed\n"); + clear_selection(); +- return -ENOMEM; ++ ret = -ENOMEM; ++ goto unlock; + } + kfree(sel_buffer); + sel_buffer = bp; +@@ -324,7 +329,9 @@ int set_selection(const struct tiocl_sel + } + } + sel_buffer_lth = bp - sel_buffer; +- return 0; ++unlock: ++ mutex_unlock(&sel_lock); ++ return ret; + } + + /* Insert the contents of the selection buffer into the +@@ -351,6 +358,7 @@ int paste_selection(struct tty_struct *t + tty_buffer_lock_exclusive(&vc->port); + + add_wait_queue(&vc->paste_wait, &wait); ++ mutex_lock(&sel_lock); + while (sel_buffer && sel_buffer_lth > pasted) { + set_current_state(TASK_INTERRUPTIBLE); + if (signal_pending(current)) { +@@ -358,7 +366,9 @@ int paste_selection(struct tty_struct *t + break; + } + if (test_bit(TTY_THROTTLED, &tty->flags)) { ++ mutex_unlock(&sel_lock); + schedule(); ++ mutex_lock(&sel_lock); + continue; + } + __set_current_state(TASK_RUNNING); +@@ -367,6 +377,7 @@ int paste_selection(struct tty_struct *t + count); + pasted += count; + } ++ mutex_unlock(&sel_lock); + remove_wait_queue(&vc->paste_wait, &wait); + __set_current_state(TASK_RUNNING); + diff --git a/queue-3.16/vt-selection-handle-pending-signals-in-paste_selection.patch b/queue-3.16/vt-selection-handle-pending-signals-in-paste_selection.patch new file mode 100644 index 00000000..90949cce --- /dev/null +++ b/queue-3.16/vt-selection-handle-pending-signals-in-paste_selection.patch @@ -0,0 +1,59 @@ +From: Jiri Slaby <jslaby@suse.cz> +Date: Mon, 10 Feb 2020 09:11:30 +0100 +Subject: vt: selection, handle pending signals in paste_selection + +commit 687bff0cd08f790d540cfb7b2349f0d876cdddec upstream. + +When pasting a selection to a vt, the task is set as INTERRUPTIBLE while +waiting for a tty to unthrottle. But signals are not handled at all. +Normally, this is not a problem as tty_ldisc_receive_buf receives all +the goods and a user has no reason to interrupt the task. + +There are two scenarios where this matters: +1) when the tty is throttled and a signal is sent to the process, it + spins on a CPU until the tty is unthrottled. schedule() does not + really echedule, but returns immediately, of course. +2) when the sel_buffer becomes invalid, KASAN prevents any reads from it + and the loop simply does not proceed and spins forever (causing the + tty to throttle, but the code never sleeps, the same as above). This + sometimes happens as there is a race in the sel_buffer handling code. + +So add signal handling to this ioctl (TIOCL_PASTESEL) and return -EINTR +in case a signal is pending. + +Signed-off-by: Jiri Slaby <jslaby@suse.cz> +Link: https://lore.kernel.org/r/20200210081131.23572-1-jslaby@suse.cz +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +[bwh: Backported to 3.16: + - No need to include <linux/sched/signal.h> + - Adjust context] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- +--- a/drivers/tty/vt/selection.c ++++ b/drivers/tty/vt/selection.c +@@ -341,6 +341,7 @@ int paste_selection(struct tty_struct *t + unsigned int count; + struct tty_ldisc *ld; + DECLARE_WAITQUEUE(wait, current); ++ int ret = 0; + + console_lock(); + poke_blanked_console(); +@@ -352,6 +353,10 @@ int paste_selection(struct tty_struct *t + add_wait_queue(&vc->paste_wait, &wait); + while (sel_buffer && sel_buffer_lth > pasted) { + set_current_state(TASK_INTERRUPTIBLE); ++ if (signal_pending(current)) { ++ ret = -EINTR; ++ break; ++ } + if (test_bit(TTY_THROTTLED, &tty->flags)) { + schedule(); + continue; +@@ -367,5 +372,5 @@ int paste_selection(struct tty_struct *t + + tty_buffer_unlock_exclusive(&vc->port); + tty_ldisc_deref(ld); +- return 0; ++ return ret; + } diff --git a/queue-3.16/vt-selection-push-console-lock-down.patch b/queue-3.16/vt-selection-push-console-lock-down.patch new file mode 100644 index 00000000..79eb6551 --- /dev/null +++ b/queue-3.16/vt-selection-push-console-lock-down.patch @@ -0,0 +1,63 @@ +From: Jiri Slaby <jslaby@suse.cz> +Date: Fri, 28 Feb 2020 12:54:05 +0100 +Subject: vt: selection, push console lock down + +commit 4b70dd57a15d2f4685ac6e38056bad93e81e982f upstream. + +We need to nest the console lock in sel_lock, so we have to push it down +a bit. Fortunately, the callers of set_selection_* just lock the console +lock around the function call. So moving it down is easy. + +In the next patch, we switch the order. + +Signed-off-by: Jiri Slaby <jslaby@suse.cz> +Fixes: 07e6124a1a46 ("vt: selection, close sel_buffer race") +Link: https://lore.kernel.org/r/20200228115406.5735-1-jslaby@suse.cz +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/tty/vt/selection.c | 13 ++++++++++++- + drivers/tty/vt/vt.c | 2 -- + 2 files changed, 12 insertions(+), 3 deletions(-) + +--- a/drivers/tty/vt/selection.c ++++ b/drivers/tty/vt/selection.c +@@ -158,7 +158,7 @@ static int store_utf8(u16 c, char *p) + * The entire selection process is managed under the console_lock. It's + * a lot under the lock but its hardly a performance path + */ +-int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) ++static int __set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) + { + struct vc_data *vc = vc_cons[fg_console].d; + int sel_mode, new_sel_start, new_sel_end, spc; +@@ -334,6 +334,17 @@ unlock: + return ret; + } + ++int set_selection(const struct tiocl_selection __user *v, struct tty_struct *tty) ++{ ++ int ret; ++ ++ console_lock(); ++ ret = __set_selection(v, tty); ++ console_unlock(); ++ ++ return ret; ++} ++ + /* Insert the contents of the selection buffer into the + * queue of the tty associated with the current console. + * Invoked by ioctl(). +--- a/drivers/tty/vt/vt.c ++++ b/drivers/tty/vt/vt.c +@@ -2670,9 +2670,7 @@ int tioclinux(struct tty_struct *tty, un + switch (type) + { + case TIOCL_SETSEL: +- console_lock(); + ret = set_selection((struct tiocl_selection __user *)(p+1), tty); +- console_unlock(); + break; + case TIOCL_PASTESEL: + ret = paste_selection(tty); diff --git a/queue-3.16/vt-selection-push-sel_lock-up.patch b/queue-3.16/vt-selection-push-sel_lock-up.patch new file mode 100644 index 00000000..553b257d --- /dev/null +++ b/queue-3.16/vt-selection-push-sel_lock-up.patch @@ -0,0 +1,141 @@ +From: Jiri Slaby <jslaby@suse.cz> +Date: Fri, 28 Feb 2020 12:54:06 +0100 +Subject: vt: selection, push sel_lock up + +commit e8c75a30a23c6ba63f4ef6895cbf41fd42f21aa2 upstream. + +sel_lock cannot nest in the console lock. Thanks to syzkaller, the +kernel states firmly: + +> WARNING: possible circular locking dependency detected +> 5.6.0-rc3-syzkaller #0 Not tainted +> ------------------------------------------------------ +> syz-executor.4/20336 is trying to acquire lock: +> ffff8880a2e952a0 (&tty->termios_rwsem){++++}, at: tty_unthrottle+0x22/0x100 drivers/tty/tty_ioctl.c:136 +> +> but task is already holding lock: +> ffffffff89462e70 (sel_lock){+.+.}, at: paste_selection+0x118/0x470 drivers/tty/vt/selection.c:374 +> +> which lock already depends on the new lock. +> +> the existing dependency chain (in reverse order) is: +> +> -> #2 (sel_lock){+.+.}: +> mutex_lock_nested+0x1b/0x30 kernel/locking/mutex.c:1118 +> set_selection_kernel+0x3b8/0x18a0 drivers/tty/vt/selection.c:217 +> set_selection_user+0x63/0x80 drivers/tty/vt/selection.c:181 +> tioclinux+0x103/0x530 drivers/tty/vt/vt.c:3050 +> vt_ioctl+0x3f1/0x3a30 drivers/tty/vt/vt_ioctl.c:364 + +This is ioctl(TIOCL_SETSEL). +Locks held on the path: console_lock -> sel_lock + +> -> #1 (console_lock){+.+.}: +> console_lock+0x46/0x70 kernel/printk/printk.c:2289 +> con_flush_chars+0x50/0x650 drivers/tty/vt/vt.c:3223 +> n_tty_write+0xeae/0x1200 drivers/tty/n_tty.c:2350 +> do_tty_write drivers/tty/tty_io.c:962 [inline] +> tty_write+0x5a1/0x950 drivers/tty/tty_io.c:1046 + +This is write(). +Locks held on the path: termios_rwsem -> console_lock + +> -> #0 (&tty->termios_rwsem){++++}: +> down_write+0x57/0x140 kernel/locking/rwsem.c:1534 +> tty_unthrottle+0x22/0x100 drivers/tty/tty_ioctl.c:136 +> mkiss_receive_buf+0x12aa/0x1340 drivers/net/hamradio/mkiss.c:902 +> tty_ldisc_receive_buf+0x12f/0x170 drivers/tty/tty_buffer.c:465 +> paste_selection+0x346/0x470 drivers/tty/vt/selection.c:389 +> tioclinux+0x121/0x530 drivers/tty/vt/vt.c:3055 +> vt_ioctl+0x3f1/0x3a30 drivers/tty/vt/vt_ioctl.c:364 + +This is ioctl(TIOCL_PASTESEL). +Locks held on the path: sel_lock -> termios_rwsem + +> other info that might help us debug this: +> +> Chain exists of: +> &tty->termios_rwsem --> console_lock --> sel_lock + +Clearly. From the above, we have: + console_lock -> sel_lock + sel_lock -> termios_rwsem + termios_rwsem -> console_lock + +Fix this by reversing the console_lock -> sel_lock dependency in +ioctl(TIOCL_SETSEL). First, lock sel_lock, then console_lock. + +Signed-off-by: Jiri Slaby <jslaby@suse.cz> +Reported-by: syzbot+26183d9746e62da329b8@syzkaller.appspotmail.com +Fixes: 07e6124a1a46 ("vt: selection, close sel_buffer race") +Link: https://lore.kernel.org/r/20200228115406.5735-2-jslaby@suse.cz +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/tty/vt/selection.c | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +--- a/drivers/tty/vt/selection.c ++++ b/drivers/tty/vt/selection.c +@@ -205,7 +205,6 @@ static int __set_selection(const struct + pe = tmp; + } + +- mutex_lock(&sel_lock); + if (sel_cons != vc_cons[fg_console].d) { + clear_selection(); + sel_cons = vc_cons[fg_console].d; +@@ -251,10 +250,9 @@ static int __set_selection(const struct + break; + case TIOCL_SELPOINTER: + highlight_pointer(pe); +- goto unlock; ++ return 0; + default: +- ret = -EINVAL; +- goto unlock; ++ return -EINVAL; + } + + /* remove the pointer */ +@@ -276,7 +274,7 @@ static int __set_selection(const struct + else if (new_sel_start == sel_start) + { + if (new_sel_end == sel_end) /* no action required */ +- goto unlock; ++ return 0; + else if (new_sel_end > sel_end) /* extend to right */ + highlight(sel_end + 2, new_sel_end); + else /* contract from right */ +@@ -303,8 +301,7 @@ static int __set_selection(const struct + if (!bp) { + printk(KERN_WARNING "selection: kmalloc() failed\n"); + clear_selection(); +- ret = -ENOMEM; +- goto unlock; ++ return -ENOMEM; + } + kfree(sel_buffer); + sel_buffer = bp; +@@ -329,8 +326,7 @@ static int __set_selection(const struct + } + } + sel_buffer_lth = bp - sel_buffer; +-unlock: +- mutex_unlock(&sel_lock); ++ + return ret; + } + +@@ -338,9 +334,11 @@ int set_selection(const struct tiocl_sel + { + int ret; + ++ mutex_lock(&sel_lock); + console_lock(); + ret = __set_selection(v, tty); + console_unlock(); ++ mutex_unlock(&sel_lock); + + return ret; + } |