summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hutchings <ben@decadent.org.uk>2020-06-07 17:40:12 +0100
committerBen Hutchings <ben@decadent.org.uk>2020-06-07 17:40:12 +0100
commit582af5cb2973430c5a6b19f9d346a74977b9b7a5 (patch)
tree6e9be52f6bd7c69e858fcead9a183193c9c71992
parent5ab00918b76039702d3d07f14ad8f2a05989a21d (diff)
downloadlinux-stable-queue-582af5cb2973430c5a6b19f9d346a74977b9b7a5.tar.gz
Add various security fixes
-rw-r--r--queue-3.16/drivers-usb-core-don-t-disable-irqs-in-usb_sg_wait-during-urb-submit.patch76
-rw-r--r--queue-3.16/drivers-usb-core-minimize-irq-disabling-in-usb_sg_cancel.patch68
-rw-r--r--queue-3.16/ext4-add-cond_resched-to-ext4_protect_reserved_inode.patch60
-rw-r--r--queue-3.16/ext4-don-t-perform-block-validity-checks-on-the-journal-inode.patch50
-rw-r--r--queue-3.16/ext4-fix-block-validity-checks-for-journal-inodes-using-indirect-blocks.patch37
-rw-r--r--queue-3.16/ext4-make-checks-for-metadata_csum-feature-safer.patch48
-rw-r--r--queue-3.16/ext4-protect-journal-inode-s-blocks-using-block_validity.patch98
-rw-r--r--queue-3.16/ext4-unsigned-int-compared-against-zero.patch31
-rw-r--r--queue-3.16/mwifiex-fix-possible-buffer-overflows-in-mwifiex_cmd_append_vsie_tlv.patch38
-rw-r--r--queue-3.16/mwifiex-fix-possible-buffer-overflows-in-mwifiex_ret_wmm_get_status.patch33
-rw-r--r--queue-3.16/scsi-mptfusion-add-bounds-check-in-mptctl_hp_targetinfo.patch32
-rw-r--r--queue-3.16/scsi-mptfusion-fix-double-fetch-bug-in-ioctl.patch573
-rw-r--r--queue-3.16/scsi-sg-add-sg_remove_request-in-sg_common_write.patch34
-rw-r--r--queue-3.16/scsi-sg-add-sg_remove_request-in-sg_write.patch36
-rw-r--r--queue-3.16/scsi-sg-change-next_cmd_len-handling-to-mirror-upstream.patch47
-rw-r--r--queue-3.16/scsi-sg-check-for-valid-direction-before-starting-the-request.patch95
-rw-r--r--queue-3.16/scsi-sg-close-race-condition-in-sg_remove_sfp_usercontext.patch91
-rw-r--r--queue-3.16/scsi-sg-disable-set_force_low_dma.patch109
-rw-r--r--queue-3.16/scsi-sg-don-t-return-bogus-sg_requests.patch45
-rw-r--r--queue-3.16/scsi-sg-factor-out-sg_fill_request_table.patch103
-rw-r--r--queue-3.16/scsi-sg-fix-minor-memory-leak-in-error-path.patch30
-rw-r--r--queue-3.16/scsi-sg-fix-sg_dxfer_from_dev-transfers.patch43
-rw-r--r--queue-3.16/scsi-sg-fix-static-checker-warning-in-sg_is_valid_dxfer.patch41
-rw-r--r--queue-3.16/scsi-sg-fixup-infoleak-when-using-sg_get_request_table.patch43
-rw-r--r--queue-3.16/scsi-sg-off-by-one-in-sg_ioctl.patch30
-rw-r--r--queue-3.16/scsi-sg-only-check-for-dxfer_len-greater-than-256m.patch82
-rw-r--r--queue-3.16/scsi-sg-protect-accesses-to-reserved-page-array.patch169
-rw-r--r--queue-3.16/scsi-sg-protect-against-races-between-mmap-and-sg_set_reserved_size.patch58
-rw-r--r--queue-3.16/scsi-sg-re-fix-off-by-one-in-sg_fill_request_table.patch35
-rw-r--r--queue-3.16/scsi-sg-recheck-mmap_io-request-length-with-lock-held.patch45
-rw-r--r--queue-3.16/scsi-sg-remove-save_scat_len.patch37
-rw-r--r--queue-3.16/scsi-sg-reset-res_in_use-after-unlinking-reserved-array.patch35
-rw-r--r--queue-3.16/scsi-sg-use-standard-lists-for-sg_requests.patch287
-rw-r--r--queue-3.16/selinux-cleanup-error-reporting-in-selinux_nlmsg_perm.patch38
-rw-r--r--queue-3.16/selinux-convert-warn_once-to-printk-in-selinux_nlmsg_perm.patch37
-rw-r--r--queue-3.16/selinux-print-sclass-as-string-when-unrecognized-netlink-message-occurs.patch32
-rw-r--r--queue-3.16/selinux-properly-handle-multiple-messages-in-selinux_netlink_send.patch104
-rw-r--r--queue-3.16/selinux-rate-limit-netlink-message-warnings-in-selinux_nlmsg_perm.patch40
-rw-r--r--queue-3.16/series43
-rw-r--r--queue-3.16/sg-o_excl-and-other-lock-handling.patch920
-rw-r--r--queue-3.16/sg-prevent-integer-overflow-when-converting-from-sectors-to-bytes.patch75
-rw-r--r--queue-3.16/signal-extend-exec_id-to-64bits.patch81
-rw-r--r--queue-3.16/usb-core-fix-free-while-in-use-bug-in-the-usb-s-glibrary.patch88
-rw-r--r--queue-3.16/usb-gadget-fix-illegal-array-access-in-binding-with-udc.patch72
44 files changed, 4169 insertions, 0 deletions
diff --git a/queue-3.16/drivers-usb-core-don-t-disable-irqs-in-usb_sg_wait-during-urb-submit.patch b/queue-3.16/drivers-usb-core-don-t-disable-irqs-in-usb_sg_wait-during-urb-submit.patch
new file mode 100644
index 00000000..0e29e9f1
--- /dev/null
+++ b/queue-3.16/drivers-usb-core-don-t-disable-irqs-in-usb_sg_wait-during-urb-submit.patch
@@ -0,0 +1,76 @@
+From: David Mosberger <davidm@egauge.net>
+Date: Tue, 8 Mar 2016 14:42:48 -0700
+Subject: drivers: usb: core: Don't disable irqs in usb_sg_wait() during URB submit.
+
+commit 98b74b0ee57af1bcb6e8b2e76e707a71c5ef8ec9 upstream.
+
+usb_submit_urb() may take quite long to execute. For example, a
+single sg list may have 30 or more entries, possibly leading to that
+many calls to DMA-map pages. This can cause interrupt latency of
+several hundred micro-seconds.
+
+Avoid the problem by releasing the io->lock spinlock and re-enabling
+interrupts before calling usb_submit_urb(). This opens races with
+usb_sg_cancel() and sg_complete(). Handle those races by using
+usb_block_urb() to stop URBs from being submitted after
+usb_sg_cancel() or sg_complete() with error.
+
+Note that usb_unlink_urb() is guaranteed to return -ENODEV if
+!io->urbs[i]->dev and since the -ENODEV case is already handled,
+we don't have to check for !io->urbs[i]->dev explicitly.
+
+Before this change, reading 512MB from an ext3 filesystem on a USB
+memory stick showed a throughput of 12 MB/s with about 500 missed
+deadlines.
+
+With this change, reading the same file gave the same throughput but
+only one or two missed deadlines.
+
+Signed-off-by: David Mosberger <davidm@egauge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/usb/core/message.c | 15 +++++++--------
+ 1 file changed, 7 insertions(+), 8 deletions(-)
+
+--- a/drivers/usb/core/message.c
++++ b/drivers/usb/core/message.c
+@@ -306,9 +306,10 @@ static void sg_complete(struct urb *urb)
+ */
+ spin_unlock(&io->lock);
+ for (i = 0, found = 0; i < io->entries; i++) {
+- if (!io->urbs[i] || !io->urbs[i]->dev)
++ if (!io->urbs[i])
+ continue;
+ if (found) {
++ usb_block_urb(io->urbs[i]);
+ retval = usb_unlink_urb(io->urbs[i]);
+ if (retval != -EINPROGRESS &&
+ retval != -ENODEV &&
+@@ -519,12 +520,10 @@ void usb_sg_wait(struct usb_sg_request *
+ int retval;
+
+ io->urbs[i]->dev = io->dev;
+- retval = usb_submit_urb(io->urbs[i], GFP_ATOMIC);
+-
+- /* after we submit, let completions or cancellations fire;
+- * we handshake using io->status.
+- */
+ spin_unlock_irq(&io->lock);
++
++ retval = usb_submit_urb(io->urbs[i], GFP_NOIO);
++
+ switch (retval) {
+ /* maybe we retrying will recover */
+ case -ENXIO: /* hc didn't queue this one */
+@@ -594,8 +593,8 @@ void usb_sg_cancel(struct usb_sg_request
+ for (i = 0; i < io->entries; i++) {
+ int retval;
+
+- if (!io->urbs[i]->dev)
+- continue;
++ usb_block_urb(io->urbs[i]);
++
+ retval = usb_unlink_urb(io->urbs[i]);
+ if (retval != -EINPROGRESS
+ && retval != -ENODEV
diff --git a/queue-3.16/drivers-usb-core-minimize-irq-disabling-in-usb_sg_cancel.patch b/queue-3.16/drivers-usb-core-minimize-irq-disabling-in-usb_sg_cancel.patch
new file mode 100644
index 00000000..67bf14db
--- /dev/null
+++ b/queue-3.16/drivers-usb-core-minimize-irq-disabling-in-usb_sg_cancel.patch
@@ -0,0 +1,68 @@
+From: David Mosberger <davidm@egauge.net>
+Date: Tue, 8 Mar 2016 14:42:49 -0700
+Subject: drivers: usb: core: Minimize irq disabling in usb_sg_cancel()
+
+commit 5f2e5fb873e269fcb806165715d237f0de4ecf1d upstream.
+
+Restructure usb_sg_cancel() so we don't have to disable interrupts
+while cancelling the URBs.
+
+Suggested-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: David Mosberger <davidm@egauge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/usb/core/message.c | 37 +++++++++++++++++--------------------
+ 1 file changed, 17 insertions(+), 20 deletions(-)
+
+--- a/drivers/usb/core/message.c
++++ b/drivers/usb/core/message.c
+@@ -581,31 +581,28 @@ EXPORT_SYMBOL_GPL(usb_sg_wait);
+ void usb_sg_cancel(struct usb_sg_request *io)
+ {
+ unsigned long flags;
++ int i, retval;
+
+ spin_lock_irqsave(&io->lock, flags);
++ if (io->status) {
++ spin_unlock_irqrestore(&io->lock, flags);
++ return;
++ }
++ /* shut everything down */
++ io->status = -ECONNRESET;
++ spin_unlock_irqrestore(&io->lock, flags);
+
+- /* shut everything down, if it didn't already */
+- if (!io->status) {
+- int i;
+-
+- io->status = -ECONNRESET;
+- spin_unlock(&io->lock);
+- for (i = 0; i < io->entries; i++) {
+- int retval;
+-
+- usb_block_urb(io->urbs[i]);
++ for (i = io->entries - 1; i >= 0; --i) {
++ usb_block_urb(io->urbs[i]);
+
+- retval = usb_unlink_urb(io->urbs[i]);
+- if (retval != -EINPROGRESS
+- && retval != -ENODEV
+- && retval != -EBUSY
+- && retval != -EIDRM)
+- dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
+- __func__, retval);
+- }
+- spin_lock(&io->lock);
++ retval = usb_unlink_urb(io->urbs[i]);
++ if (retval != -EINPROGRESS
++ && retval != -ENODEV
++ && retval != -EBUSY
++ && retval != -EIDRM)
++ dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
++ __func__, retval);
+ }
+- spin_unlock_irqrestore(&io->lock, flags);
+ }
+ EXPORT_SYMBOL_GPL(usb_sg_cancel);
+
diff --git a/queue-3.16/ext4-add-cond_resched-to-ext4_protect_reserved_inode.patch b/queue-3.16/ext4-add-cond_resched-to-ext4_protect_reserved_inode.patch
new file mode 100644
index 00000000..fbdcca3e
--- /dev/null
+++ b/queue-3.16/ext4-add-cond_resched-to-ext4_protect_reserved_inode.patch
@@ -0,0 +1,60 @@
+From: Shijie Luo <luoshijie1@huawei.com>
+Date: Mon, 10 Feb 2020 20:17:52 -0500
+Subject: ext4: add cond_resched() to ext4_protect_reserved_inode
+
+commit af133ade9a40794a37104ecbcc2827c0ea373a3c upstream.
+
+When journal size is set too big by "mkfs.ext4 -J size=", or when
+we mount a crafted image to make journal inode->i_size too big,
+the loop, "while (i < num)", holds cpu too long. This could cause
+soft lockup.
+
+[ 529.357541] Call trace:
+[ 529.357551] dump_backtrace+0x0/0x198
+[ 529.357555] show_stack+0x24/0x30
+[ 529.357562] dump_stack+0xa4/0xcc
+[ 529.357568] watchdog_timer_fn+0x300/0x3e8
+[ 529.357574] __hrtimer_run_queues+0x114/0x358
+[ 529.357576] hrtimer_interrupt+0x104/0x2d8
+[ 529.357580] arch_timer_handler_virt+0x38/0x58
+[ 529.357584] handle_percpu_devid_irq+0x90/0x248
+[ 529.357588] generic_handle_irq+0x34/0x50
+[ 529.357590] __handle_domain_irq+0x68/0xc0
+[ 529.357593] gic_handle_irq+0x6c/0x150
+[ 529.357595] el1_irq+0xb8/0x140
+[ 529.357599] __ll_sc_atomic_add_return_acquire+0x14/0x20
+[ 529.357668] ext4_map_blocks+0x64/0x5c0 [ext4]
+[ 529.357693] ext4_setup_system_zone+0x330/0x458 [ext4]
+[ 529.357717] ext4_fill_super+0x2170/0x2ba8 [ext4]
+[ 529.357722] mount_bdev+0x1a8/0x1e8
+[ 529.357746] ext4_mount+0x44/0x58 [ext4]
+[ 529.357748] mount_fs+0x50/0x170
+[ 529.357752] vfs_kern_mount.part.9+0x54/0x188
+[ 529.357755] do_mount+0x5ac/0xd78
+[ 529.357758] ksys_mount+0x9c/0x118
+[ 529.357760] __arm64_sys_mount+0x28/0x38
+[ 529.357764] el0_svc_common+0x78/0x130
+[ 529.357766] el0_svc_handler+0x38/0x78
+[ 529.357769] el0_svc+0x8/0xc
+[ 541.356516] watchdog: BUG: soft lockup - CPU#0 stuck for 23s! [mount:18674]
+
+Link: https://lore.kernel.org/r/20200211011752.29242-1-luoshijie1@huawei.com
+Reviewed-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Shijie Luo <luoshijie1@huawei.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Cc: stable@kernel.org
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ fs/ext4/block_validity.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/fs/ext4/block_validity.c
++++ b/fs/ext4/block_validity.c
+@@ -153,6 +153,7 @@ static int ext4_protect_reserved_inode(s
+ return PTR_ERR(inode);
+ num = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+ while (i < num) {
++ cond_resched();
+ map.m_lblk = i;
+ map.m_len = num - i;
+ n = ext4_map_blocks(NULL, inode, &map, 0);
diff --git a/queue-3.16/ext4-don-t-perform-block-validity-checks-on-the-journal-inode.patch b/queue-3.16/ext4-don-t-perform-block-validity-checks-on-the-journal-inode.patch
new file mode 100644
index 00000000..f59646eb
--- /dev/null
+++ b/queue-3.16/ext4-don-t-perform-block-validity-checks-on-the-journal-inode.patch
@@ -0,0 +1,50 @@
+From: Theodore Ts'o <tytso@mit.edu>
+Date: Wed, 22 May 2019 10:27:01 -0400
+Subject: ext4: don't perform block validity checks on the journal inode
+
+commit 0a944e8a6c66ca04c7afbaa17e22bf208a8b37f0 upstream.
+
+Since the journal inode is already checked when we added it to the
+block validity's system zone, if we check it again, we'll just trigger
+a failure.
+
+This was causing failures like this:
+
+[ 53.897001] EXT4-fs error (device sda): ext4_find_extent:909: inode
+#8: comm jbd2/sda-8: pblk 121667583 bad header/extent: invalid extent entries - magic f30a, entries 8, max 340(340), depth 0(0)
+[ 53.931430] jbd2_journal_bmap: journal block not found at offset 49 on sda-8
+[ 53.938480] Aborting journal on device sda-8.
+
+... but only if the system was under enough memory pressure that
+logical->physical mapping for the journal inode gets pushed out of the
+extent cache. (This is why it wasn't noticed earlier.)
+
+Fixes: 345c0dbf3a30 ("ext4: protect journal inode's blocks using block_validity")
+Reported-by: Dan Rue <dan.rue@linaro.org>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Tested-by: Naresh Kamboju <naresh.kamboju@linaro.org>
+[bwh: Backported to 3.16: Use EXT4_HAS_COMPAT_FEATURE()]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+--- a/fs/ext4/extents.c
++++ b/fs/ext4/extents.c
+@@ -503,10 +503,15 @@ __read_extent_tree_block(const char *fun
+ }
+ if (buffer_verified(bh) && !(flags & EXT4_EX_FORCE_CACHE))
+ return bh;
+- err = __ext4_ext_check(function, line, inode,
+- ext_block_hdr(bh), depth, pblk);
+- if (err)
+- goto errout;
++ if (!EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
++ EXT4_FEATURE_COMPAT_HAS_JOURNAL) ||
++ (inode->i_ino !=
++ le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum))) {
++ err = __ext4_ext_check(function, line, inode,
++ ext_block_hdr(bh), depth, pblk);
++ if (err)
++ goto errout;
++ }
+ set_buffer_verified(bh);
+ /*
+ * If this is a leaf block, cache all of its entries
diff --git a/queue-3.16/ext4-fix-block-validity-checks-for-journal-inodes-using-indirect-blocks.patch b/queue-3.16/ext4-fix-block-validity-checks-for-journal-inodes-using-indirect-blocks.patch
new file mode 100644
index 00000000..ca1424aa
--- /dev/null
+++ b/queue-3.16/ext4-fix-block-validity-checks-for-journal-inodes-using-indirect-blocks.patch
@@ -0,0 +1,37 @@
+From: Theodore Ts'o <tytso@mit.edu>
+Date: Wed, 15 May 2019 00:51:19 -0400
+Subject: ext4: fix block validity checks for journal inodes using indirect blocks
+
+commit 170417c8c7bb2cbbdd949bf5c443c0c8f24a203b upstream.
+
+Commit 345c0dbf3a30 ("ext4: protect journal inode's blocks using
+block_validity") failed to add an exception for the journal inode in
+ext4_check_blockref(), which is the function used by ext4_get_branch()
+for indirect blocks. This caused attempts to read from the ext3-style
+journals to fail with:
+
+[ 848.968550] EXT4-fs error (device sdb7): ext4_get_branch:171: inode #8: block 30343695: comm jbd2/sdb7-8: invalid block
+
+Fix this by adding the missing exception check.
+
+Fixes: 345c0dbf3a30 ("ext4: protect journal inode's blocks using block_validity")
+Reported-by: Arthur Marsh <arthur.marsh@internode.on.net>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+[bwh: Backported to 3.16: Use EXT4_HAS_COMPAT_FEATURE]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+--- a/fs/ext4/block_validity.c
++++ b/fs/ext4/block_validity.c
+@@ -277,6 +277,12 @@ int ext4_check_blockref(const char *func
+ __le32 *bref = p;
+ unsigned int blk;
+
++ if (EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
++ EXT4_FEATURE_COMPAT_HAS_JOURNAL) &&
++ (inode->i_ino ==
++ le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum)))
++ return 0;
++
+ while (bref < p+max) {
+ blk = le32_to_cpu(*bref++);
+ if (blk &&
diff --git a/queue-3.16/ext4-make-checks-for-metadata_csum-feature-safer.patch b/queue-3.16/ext4-make-checks-for-metadata_csum-feature-safer.patch
new file mode 100644
index 00000000..4e4aa6ee
--- /dev/null
+++ b/queue-3.16/ext4-make-checks-for-metadata_csum-feature-safer.patch
@@ -0,0 +1,48 @@
+From: Tahsin Erdogan <tahsin@google.com>
+Date: Thu, 17 May 2018 18:23:04 +0200
+Subject: ext4: Make checks for metadata_csum feature safer
+
+This is just a small part of commit dec214d00e0d7 "ext4: xattr inode
+deduplication" that makes checks for metadata_csum feature safer and is
+actually needed by following fixes.
+
+Signed-off-by: Tahsin Erdogan <tahsin@google.com>
+Acked-by: Jan Kara <jack@suse.cz>
+[bwh: Ported to 3.16: Use EXT4_HAS_RO_COMPAT_FEATURE()]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -2411,21 +2411,24 @@ extern void ext4_group_desc_csum_set(str
+ extern int ext4_register_li_request(struct super_block *sb,
+ ext4_group_t first_not_zeroed);
+
+-static inline int ext4_has_group_desc_csum(struct super_block *sb)
+-{
+- return EXT4_HAS_RO_COMPAT_FEATURE(sb,
+- EXT4_FEATURE_RO_COMPAT_GDT_CSUM) ||
+- (EXT4_SB(sb)->s_chksum_driver != NULL);
+-}
+-
+ static inline int ext4_has_metadata_csum(struct super_block *sb)
+ {
+ WARN_ON_ONCE(EXT4_HAS_RO_COMPAT_FEATURE(sb,
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+ !EXT4_SB(sb)->s_chksum_driver);
+
+- return (EXT4_SB(sb)->s_chksum_driver != NULL);
++ return EXT4_HAS_RO_COMPAT_FEATURE(sb,
++ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
++ (EXT4_SB(sb)->s_chksum_driver != NULL);
++}
++
++static inline int ext4_has_group_desc_csum(struct super_block *sb)
++{
++ return EXT4_HAS_RO_COMPAT_FEATURE(sb,
++ EXT4_FEATURE_RO_COMPAT_GDT_CSUM) ||
++ ext4_has_metadata_csum(sb);
+ }
++
+ static inline ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es)
+ {
+ return ((ext4_fsblk_t)le32_to_cpu(es->s_blocks_count_hi) << 32) |
diff --git a/queue-3.16/ext4-protect-journal-inode-s-blocks-using-block_validity.patch b/queue-3.16/ext4-protect-journal-inode-s-blocks-using-block_validity.patch
new file mode 100644
index 00000000..ba8b9471
--- /dev/null
+++ b/queue-3.16/ext4-protect-journal-inode-s-blocks-using-block_validity.patch
@@ -0,0 +1,98 @@
+From: Theodore Ts'o <tytso@mit.edu>
+Date: Tue, 9 Apr 2019 23:37:08 -0400
+Subject: ext4: protect journal inode's blocks using block_validity
+
+commit 345c0dbf3a30872d9b204db96b5857cd00808cae upstream.
+
+Add the blocks which belong to the journal inode to block_validity's
+system zone so attempts to deallocate or overwrite the journal due a
+corrupted file system where the journal blocks are also claimed by
+another inode.
+
+Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=202879
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Cc: stable@kernel.org
+[bwh: Backported to 3.16:
+ - Use EXT4_HAS_COMPAT_FEATURE()
+ - Use EIO instead of EFSCORRUPTED]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+--- a/fs/ext4/block_validity.c
++++ b/fs/ext4/block_validity.c
+@@ -137,6 +137,48 @@ static void debug_print_tree(struct ext4
+ printk("\n");
+ }
+
++static int ext4_protect_reserved_inode(struct super_block *sb, u32 ino)
++{
++ struct inode *inode;
++ struct ext4_sb_info *sbi = EXT4_SB(sb);
++ struct ext4_map_blocks map;
++ u32 i = 0, err = 0, num, n;
++
++ if ((ino < EXT4_ROOT_INO) ||
++ (ino > le32_to_cpu(sbi->s_es->s_inodes_count)))
++ return -EINVAL;
++ inode = ext4_iget(sb, ino, EXT4_IGET_SPECIAL);
++ if (IS_ERR(inode))
++ return PTR_ERR(inode);
++ num = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
++ while (i < num) {
++ map.m_lblk = i;
++ map.m_len = num - i;
++ n = ext4_map_blocks(NULL, inode, &map, 0);
++ if (n < 0) {
++ err = n;
++ break;
++ }
++ if (n == 0) {
++ i++;
++ } else {
++ if (!ext4_data_block_valid(sbi, map.m_pblk, n)) {
++ ext4_error(sb, "blocks %llu-%llu from inode %u "
++ "overlap system zone", map.m_pblk,
++ map.m_pblk + map.m_len - 1, ino);
++ err = -EIO;
++ break;
++ }
++ err = add_system_zone(sbi, map.m_pblk, n);
++ if (err < 0)
++ break;
++ i += n;
++ }
++ }
++ iput(inode);
++ return err;
++}
++
+ int ext4_setup_system_zone(struct super_block *sb)
+ {
+ ext4_group_t ngroups = ext4_get_groups_count(sb);
+@@ -171,6 +213,13 @@ int ext4_setup_system_zone(struct super_
+ if (ret)
+ return ret;
+ }
++ if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL) &&
++ sbi->s_es->s_journal_inum) {
++ ret = ext4_protect_reserved_inode(sb,
++ le32_to_cpu(sbi->s_es->s_journal_inum));
++ if (ret)
++ return ret;
++ }
+
+ if (test_opt(sb, DEBUG))
+ debug_print_tree(EXT4_SB(sb));
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -411,6 +411,11 @@ static int __check_block_validity(struct
+ unsigned int line,
+ struct ext4_map_blocks *map)
+ {
++ if (EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
++ EXT4_FEATURE_COMPAT_HAS_JOURNAL) &&
++ (inode->i_ino ==
++ le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum)))
++ return 0;
+ if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), map->m_pblk,
+ map->m_len)) {
+ ext4_error_inode(inode, func, line, map->m_pblk,
diff --git a/queue-3.16/ext4-unsigned-int-compared-against-zero.patch b/queue-3.16/ext4-unsigned-int-compared-against-zero.patch
new file mode 100644
index 00000000..15772dc6
--- /dev/null
+++ b/queue-3.16/ext4-unsigned-int-compared-against-zero.patch
@@ -0,0 +1,31 @@
+From: Colin Ian King <colin.king@canonical.com>
+Date: Fri, 10 May 2019 22:06:38 -0400
+Subject: ext4: unsigned int compared against zero
+
+commit fbbbbd2f28aec991f3fbc248df211550fbdfd58c upstream.
+
+There are two cases where u32 variables n and err are being checked
+for less than zero error values, the checks is always false because
+the variables are not signed. Fix this by making the variables ints.
+
+Addresses-Coverity: ("Unsigned compared against 0")
+Fixes: 345c0dbf3a30 ("ext4: protect journal inode's blocks using block_validity")
+Signed-off-by: Colin Ian King <colin.king@canonical.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ fs/ext4/block_validity.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/fs/ext4/block_validity.c
++++ b/fs/ext4/block_validity.c
+@@ -142,7 +142,8 @@ static int ext4_protect_reserved_inode(s
+ struct inode *inode;
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ struct ext4_map_blocks map;
+- u32 i = 0, err = 0, num, n;
++ u32 i = 0, num;
++ int err = 0, n;
+
+ if ((ino < EXT4_ROOT_INO) ||
+ (ino > le32_to_cpu(sbi->s_es->s_inodes_count)))
diff --git a/queue-3.16/mwifiex-fix-possible-buffer-overflows-in-mwifiex_cmd_append_vsie_tlv.patch b/queue-3.16/mwifiex-fix-possible-buffer-overflows-in-mwifiex_cmd_append_vsie_tlv.patch
new file mode 100644
index 00000000..137f542d
--- /dev/null
+++ b/queue-3.16/mwifiex-fix-possible-buffer-overflows-in-mwifiex_cmd_append_vsie_tlv.patch
@@ -0,0 +1,38 @@
+From: Qing Xu <m1s5p6688@gmail.com>
+Date: Thu, 2 Jan 2020 10:39:27 +0800
+Subject: mwifiex: Fix possible buffer overflows in mwifiex_cmd_append_vsie_tlv()
+
+commit b70261a288ea4d2f4ac7cd04be08a9f0f2de4f4d upstream.
+
+mwifiex_cmd_append_vsie_tlv() calls memcpy() without checking
+the destination size may trigger a buffer overflower,
+which a local user could use to cause denial of service
+or the execution of arbitrary code.
+Fix it by putting the length check before calling memcpy().
+
+Signed-off-by: Qing Xu <m1s5p6688@gmail.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+[bwh: Backported to 3.16:
+ - Use dev_info() instead of mwifiex_dbg()
+ - Adjust filename]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/net/wireless/mwifiex/scan.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/net/wireless/mwifiex/scan.c
++++ b/drivers/net/wireless/mwifiex/scan.c
+@@ -2267,6 +2267,13 @@ mwifiex_cmd_append_vsie_tlv(struct mwifi
+ vs_param_set->header.len =
+ cpu_to_le16((((u16) priv->vs_ie[id].ie[1])
+ & 0x00FF) + 2);
++ if (le16_to_cpu(vs_param_set->header.len) >
++ MWIFIEX_MAX_VSIE_LEN) {
++ dev_info(priv->adapter->dev,
++ "Invalid param length!\n");
++ break;
++ }
++
+ memcpy(vs_param_set->ie, priv->vs_ie[id].ie,
+ le16_to_cpu(vs_param_set->header.len));
+ *buffer += le16_to_cpu(vs_param_set->header.len) +
diff --git a/queue-3.16/mwifiex-fix-possible-buffer-overflows-in-mwifiex_ret_wmm_get_status.patch b/queue-3.16/mwifiex-fix-possible-buffer-overflows-in-mwifiex_ret_wmm_get_status.patch
new file mode 100644
index 00000000..63c8f105
--- /dev/null
+++ b/queue-3.16/mwifiex-fix-possible-buffer-overflows-in-mwifiex_ret_wmm_get_status.patch
@@ -0,0 +1,33 @@
+From: Qing Xu <m1s5p6688@gmail.com>
+Date: Thu, 2 Jan 2020 10:39:26 +0800
+Subject: mwifiex: Fix possible buffer overflows in mwifiex_ret_wmm_get_status()
+
+commit 3a9b153c5591548612c3955c9600a98150c81875 upstream.
+
+mwifiex_ret_wmm_get_status() calls memcpy() without checking the
+destination size.Since the source is given from remote AP which
+contains illegal wmm elements , this may trigger a heap buffer
+overflow.
+Fix it by putting the length check before calling memcpy().
+
+Signed-off-by: Qing Xu <m1s5p6688@gmail.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+[bwh: Backported to 3.16: adjust filename]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/net/wireless/mwifiex/wmm.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/net/wireless/mwifiex/wmm.c
++++ b/drivers/net/wireless/mwifiex/wmm.c
+@@ -791,6 +791,10 @@ int mwifiex_ret_wmm_get_status(struct mw
+ wmm_param_ie->qos_info_bitmap &
+ IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK);
+
++ if (wmm_param_ie->vend_hdr.len + 2 >
++ sizeof(struct ieee_types_wmm_parameter))
++ break;
++
+ memcpy((u8 *) &priv->curr_bss_params.bss_descriptor.
+ wmm_ie, wmm_param_ie,
+ wmm_param_ie->vend_hdr.len + 2);
diff --git a/queue-3.16/scsi-mptfusion-add-bounds-check-in-mptctl_hp_targetinfo.patch b/queue-3.16/scsi-mptfusion-add-bounds-check-in-mptctl_hp_targetinfo.patch
new file mode 100644
index 00000000..2f1bee1d
--- /dev/null
+++ b/queue-3.16/scsi-mptfusion-add-bounds-check-in-mptctl_hp_targetinfo.patch
@@ -0,0 +1,32 @@
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Thu, 25 Jan 2018 17:27:27 +0300
+Subject: scsi: mptfusion: Add bounds check in mptctl_hp_targetinfo()
+
+commit a7043e9529f3c367cc4d82997e00be034cbe57ca upstream.
+
+My static checker complains about an out of bounds read:
+
+ drivers/message/fusion/mptctl.c:2786 mptctl_hp_targetinfo()
+ error: buffer overflow 'hd->sel_timeout' 255 <= u32max.
+
+It's true that we probably should have a bounds check here.
+
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/message/fusion/mptctl.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/message/fusion/mptctl.c
++++ b/drivers/message/fusion/mptctl.c
+@@ -2698,6 +2698,8 @@ mptctl_hp_targetinfo(unsigned long arg)
+ __FILE__, __LINE__, iocnum);
+ return -ENODEV;
+ }
++ if (karg.hdr.id >= MPT_MAX_FC_DEVICES)
++ return -EINVAL;
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n",
+ ioc->name));
+
diff --git a/queue-3.16/scsi-mptfusion-fix-double-fetch-bug-in-ioctl.patch b/queue-3.16/scsi-mptfusion-fix-double-fetch-bug-in-ioctl.patch
new file mode 100644
index 00000000..7a98c275
--- /dev/null
+++ b/queue-3.16/scsi-mptfusion-fix-double-fetch-bug-in-ioctl.patch
@@ -0,0 +1,573 @@
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Tue, 14 Jan 2020 15:34:14 +0300
+Subject: scsi: mptfusion: Fix double fetch bug in ioctl
+
+commit 28d76df18f0ad5bcf5fa48510b225f0ed262a99b upstream.
+
+Tom Hatskevich reported that we look up "iocp" then, in the called
+functions we do a second copy_from_user() and look it up again.
+The problem that could cause is:
+
+drivers/message/fusion/mptctl.c
+ 674 /* All of these commands require an interrupt or
+ 675 * are unknown/illegal.
+ 676 */
+ 677 if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
+ ^^^^
+We take this lock.
+
+ 678 return ret;
+ 679
+ 680 if (cmd == MPTFWDOWNLOAD)
+ 681 ret = mptctl_fw_download(arg);
+ ^^^
+Then the user memory changes and we look up "iocp" again but a different
+one so now we are holding the incorrect lock and have a race condition.
+
+ 682 else if (cmd == MPTCOMMAND)
+ 683 ret = mptctl_mpt_command(arg);
+
+The security impact of this bug is not as bad as it could have been
+because these operations are all privileged and root already has
+enormous destructive power. But it's still worth fixing.
+
+This patch passes the "iocp" pointer to the functions to avoid the
+second lookup. That deletes 100 lines of code from the driver so
+it's a nice clean up as well.
+
+Link: https://lore.kernel.org/r/20200114123414.GA7957@kadam
+Reported-by: Tom Hatskevich <tom2001tom.23@gmail.com>
+Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/message/fusion/mptctl.c | 213 ++++++++------------------------
+ 1 file changed, 50 insertions(+), 163 deletions(-)
+
+--- a/drivers/message/fusion/mptctl.c
++++ b/drivers/message/fusion/mptctl.c
+@@ -100,19 +100,19 @@ struct buflist {
+ * Function prototypes. Called from OS entry point mptctl_ioctl.
+ * arg contents specific to function.
+ */
+-static int mptctl_fw_download(unsigned long arg);
+-static int mptctl_getiocinfo(unsigned long arg, unsigned int cmd);
+-static int mptctl_gettargetinfo(unsigned long arg);
+-static int mptctl_readtest(unsigned long arg);
+-static int mptctl_mpt_command(unsigned long arg);
+-static int mptctl_eventquery(unsigned long arg);
+-static int mptctl_eventenable(unsigned long arg);
+-static int mptctl_eventreport(unsigned long arg);
+-static int mptctl_replace_fw(unsigned long arg);
+-
+-static int mptctl_do_reset(unsigned long arg);
+-static int mptctl_hp_hostinfo(unsigned long arg, unsigned int cmd);
+-static int mptctl_hp_targetinfo(unsigned long arg);
++static int mptctl_fw_download(MPT_ADAPTER *iocp, unsigned long arg);
++static int mptctl_getiocinfo(MPT_ADAPTER *iocp, unsigned long arg, unsigned int cmd);
++static int mptctl_gettargetinfo(MPT_ADAPTER *iocp, unsigned long arg);
++static int mptctl_readtest(MPT_ADAPTER *iocp, unsigned long arg);
++static int mptctl_mpt_command(MPT_ADAPTER *iocp, unsigned long arg);
++static int mptctl_eventquery(MPT_ADAPTER *iocp, unsigned long arg);
++static int mptctl_eventenable(MPT_ADAPTER *iocp, unsigned long arg);
++static int mptctl_eventreport(MPT_ADAPTER *iocp, unsigned long arg);
++static int mptctl_replace_fw(MPT_ADAPTER *iocp, unsigned long arg);
++
++static int mptctl_do_reset(MPT_ADAPTER *iocp, unsigned long arg);
++static int mptctl_hp_hostinfo(MPT_ADAPTER *iocp, unsigned long arg, unsigned int cmd);
++static int mptctl_hp_targetinfo(MPT_ADAPTER *iocp, unsigned long arg);
+
+ static int mptctl_probe(struct pci_dev *, const struct pci_device_id *);
+ static void mptctl_remove(struct pci_dev *);
+@@ -123,8 +123,8 @@ static long compat_mpctl_ioctl(struct fi
+ /*
+ * Private function calls.
+ */
+-static int mptctl_do_mpt_command(struct mpt_ioctl_command karg, void __user *mfPtr);
+-static int mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen);
++static int mptctl_do_mpt_command(MPT_ADAPTER *iocp, struct mpt_ioctl_command karg, void __user *mfPtr);
++static int mptctl_do_fw_download(MPT_ADAPTER *iocp, char __user *ufwbuf, size_t fwlen);
+ static MptSge_t *kbuf_alloc_2_sgl(int bytes, u32 dir, int sge_offset, int *frags,
+ struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
+ static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma,
+@@ -656,19 +656,19 @@ __mptctl_ioctl(struct file *file, unsign
+ * by TM and FW reloads.
+ */
+ if ((cmd & ~IOCSIZE_MASK) == (MPTIOCINFO & ~IOCSIZE_MASK)) {
+- return mptctl_getiocinfo(arg, _IOC_SIZE(cmd));
++ return mptctl_getiocinfo(iocp, arg, _IOC_SIZE(cmd));
+ } else if (cmd == MPTTARGETINFO) {
+- return mptctl_gettargetinfo(arg);
++ return mptctl_gettargetinfo(iocp, arg);
+ } else if (cmd == MPTTEST) {
+- return mptctl_readtest(arg);
++ return mptctl_readtest(iocp, arg);
+ } else if (cmd == MPTEVENTQUERY) {
+- return mptctl_eventquery(arg);
++ return mptctl_eventquery(iocp, arg);
+ } else if (cmd == MPTEVENTENABLE) {
+- return mptctl_eventenable(arg);
++ return mptctl_eventenable(iocp, arg);
+ } else if (cmd == MPTEVENTREPORT) {
+- return mptctl_eventreport(arg);
++ return mptctl_eventreport(iocp, arg);
+ } else if (cmd == MPTFWREPLACE) {
+- return mptctl_replace_fw(arg);
++ return mptctl_replace_fw(iocp, arg);
+ }
+
+ /* All of these commands require an interrupt or
+@@ -678,15 +678,15 @@ __mptctl_ioctl(struct file *file, unsign
+ return ret;
+
+ if (cmd == MPTFWDOWNLOAD)
+- ret = mptctl_fw_download(arg);
++ ret = mptctl_fw_download(iocp, arg);
+ else if (cmd == MPTCOMMAND)
+- ret = mptctl_mpt_command(arg);
++ ret = mptctl_mpt_command(iocp, arg);
+ else if (cmd == MPTHARDRESET)
+- ret = mptctl_do_reset(arg);
++ ret = mptctl_do_reset(iocp, arg);
+ else if ((cmd & ~IOCSIZE_MASK) == (HP_GETHOSTINFO & ~IOCSIZE_MASK))
+- ret = mptctl_hp_hostinfo(arg, _IOC_SIZE(cmd));
++ ret = mptctl_hp_hostinfo(iocp, arg, _IOC_SIZE(cmd));
+ else if (cmd == HP_GETTARGETINFO)
+- ret = mptctl_hp_targetinfo(arg);
++ ret = mptctl_hp_targetinfo(iocp, arg);
+ else
+ ret = -EINVAL;
+
+@@ -705,11 +705,10 @@ mptctl_ioctl(struct file *file, unsigned
+ return ret;
+ }
+
+-static int mptctl_do_reset(unsigned long arg)
++static int mptctl_do_reset(MPT_ADAPTER *iocp, unsigned long arg)
+ {
+ struct mpt_ioctl_diag_reset __user *urinfo = (void __user *) arg;
+ struct mpt_ioctl_diag_reset krinfo;
+- MPT_ADAPTER *iocp;
+
+ if (copy_from_user(&krinfo, urinfo, sizeof(struct mpt_ioctl_diag_reset))) {
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_do_reset - "
+@@ -718,12 +717,6 @@ static int mptctl_do_reset(unsigned long
+ return -EFAULT;
+ }
+
+- if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) {
+- printk(KERN_DEBUG MYNAM "%s@%d::mptctl_do_reset - ioc%d not found!\n",
+- __FILE__, __LINE__, krinfo.hdr.iocnum);
+- return -ENODEV; /* (-6) No such device or address */
+- }
+-
+ dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "mptctl_do_reset called.\n",
+ iocp->name));
+
+@@ -754,7 +747,7 @@ static int mptctl_do_reset(unsigned long
+ * -ENOMSG if FW upload returned bad status
+ */
+ static int
+-mptctl_fw_download(unsigned long arg)
++mptctl_fw_download(MPT_ADAPTER *iocp, unsigned long arg)
+ {
+ struct mpt_fw_xfer __user *ufwdl = (void __user *) arg;
+ struct mpt_fw_xfer kfwdl;
+@@ -766,7 +759,7 @@ mptctl_fw_download(unsigned long arg)
+ return -EFAULT;
+ }
+
+- return mptctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen);
++ return mptctl_do_fw_download(iocp, kfwdl.bufp, kfwdl.fwlen);
+ }
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+@@ -784,11 +777,10 @@ mptctl_fw_download(unsigned long arg)
+ * -ENOMSG if FW upload returned bad status
+ */
+ static int
+-mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
++mptctl_do_fw_download(MPT_ADAPTER *iocp, char __user *ufwbuf, size_t fwlen)
+ {
+ FWDownload_t *dlmsg;
+ MPT_FRAME_HDR *mf;
+- MPT_ADAPTER *iocp;
+ FWDownloadTCSGE_t *ptsge;
+ MptSge_t *sgl, *sgIn;
+ char *sgOut;
+@@ -808,17 +800,10 @@ mptctl_do_fw_download(int ioc, char __us
+ pFWDownloadReply_t ReplyMsg = NULL;
+ unsigned long timeleft;
+
+- if (mpt_verify_adapter(ioc, &iocp) < 0) {
+- printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n",
+- ioc);
+- return -ENODEV; /* (-6) No such device or address */
+- } else {
+-
+- /* Valid device. Get a message frame and construct the FW download message.
+- */
+- if ((mf = mpt_get_msg_frame(mptctl_id, iocp)) == NULL)
+- return -EAGAIN;
+- }
++ /* Valid device. Get a message frame and construct the FW download message.
++ */
++ if ((mf = mpt_get_msg_frame(mptctl_id, iocp)) == NULL)
++ return -EAGAIN;
+
+ dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT
+ "mptctl_do_fwdl called. mptctl_id = %xh.\n", iocp->name, mptctl_id));
+@@ -826,8 +811,6 @@ mptctl_do_fw_download(int ioc, char __us
+ iocp->name, ufwbuf));
+ dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.fwlen = %d\n",
+ iocp->name, (int)fwlen));
+- dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.ioc = %04xh\n",
+- iocp->name, ioc));
+
+ dlmsg = (FWDownload_t*) mf;
+ ptsge = (FWDownloadTCSGE_t *) &dlmsg->SGL;
+@@ -1234,13 +1217,11 @@ kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_
+ * -ENODEV if no such device/adapter
+ */
+ static int
+-mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
++mptctl_getiocinfo (MPT_ADAPTER *ioc, unsigned long arg, unsigned int data_size)
+ {
+ struct mpt_ioctl_iocinfo __user *uarg = (void __user *) arg;
+ struct mpt_ioctl_iocinfo *karg;
+- MPT_ADAPTER *ioc;
+ struct pci_dev *pdev;
+- int iocnum;
+ unsigned int port;
+ int cim_rev;
+ struct scsi_device *sdev;
+@@ -1276,14 +1257,6 @@ mptctl_getiocinfo (unsigned long arg, un
+ return -EFAULT;
+ }
+
+- if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) ||
+- (ioc == NULL)) {
+- printk(KERN_DEBUG MYNAM "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
+- __FILE__, __LINE__, iocnum);
+- kfree(karg);
+- return -ENODEV;
+- }
+-
+ /* Verify the data transfer size is correct. */
+ if (karg->hdr.maxDataSize != data_size) {
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - "
+@@ -1389,15 +1362,13 @@ mptctl_getiocinfo (unsigned long arg, un
+ * -ENODEV if no such device/adapter
+ */
+ static int
+-mptctl_gettargetinfo (unsigned long arg)
++mptctl_gettargetinfo (MPT_ADAPTER *ioc, unsigned long arg)
+ {
+ struct mpt_ioctl_targetinfo __user *uarg = (void __user *) arg;
+ struct mpt_ioctl_targetinfo karg;
+- MPT_ADAPTER *ioc;
+ VirtDevice *vdevice;
+ char *pmem;
+ int *pdata;
+- int iocnum;
+ int numDevices = 0;
+ int lun;
+ int maxWordsLeft;
+@@ -1412,13 +1383,6 @@ mptctl_gettargetinfo (unsigned long arg)
+ return -EFAULT;
+ }
+
+- if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+- (ioc == NULL)) {
+- printk(KERN_DEBUG MYNAM "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
+- __FILE__, __LINE__, iocnum);
+- return -ENODEV;
+- }
+-
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_gettargetinfo called.\n",
+ ioc->name));
+ /* Get the port number and set the maximum number of bytes
+@@ -1514,12 +1478,10 @@ mptctl_gettargetinfo (unsigned long arg)
+ * -ENODEV if no such device/adapter
+ */
+ static int
+-mptctl_readtest (unsigned long arg)
++mptctl_readtest (MPT_ADAPTER *ioc, unsigned long arg)
+ {
+ struct mpt_ioctl_test __user *uarg = (void __user *) arg;
+ struct mpt_ioctl_test karg;
+- MPT_ADAPTER *ioc;
+- int iocnum;
+
+ if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_test))) {
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_readtest - "
+@@ -1528,13 +1490,6 @@ mptctl_readtest (unsigned long arg)
+ return -EFAULT;
+ }
+
+- if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+- (ioc == NULL)) {
+- printk(KERN_DEBUG MYNAM "%s::mptctl_readtest() @%d - ioc%d not found!\n",
+- __FILE__, __LINE__, iocnum);
+- return -ENODEV;
+- }
+-
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_readtest called.\n",
+ ioc->name));
+ /* Fill in the data and return the structure to the calling
+@@ -1575,12 +1530,10 @@ mptctl_readtest (unsigned long arg)
+ * -ENODEV if no such device/adapter
+ */
+ static int
+-mptctl_eventquery (unsigned long arg)
++mptctl_eventquery (MPT_ADAPTER *ioc, unsigned long arg)
+ {
+ struct mpt_ioctl_eventquery __user *uarg = (void __user *) arg;
+ struct mpt_ioctl_eventquery karg;
+- MPT_ADAPTER *ioc;
+- int iocnum;
+
+ if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) {
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_eventquery - "
+@@ -1589,13 +1542,6 @@ mptctl_eventquery (unsigned long arg)
+ return -EFAULT;
+ }
+
+- if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+- (ioc == NULL)) {
+- printk(KERN_DEBUG MYNAM "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
+- __FILE__, __LINE__, iocnum);
+- return -ENODEV;
+- }
+-
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventquery called.\n",
+ ioc->name));
+ karg.eventEntries = MPTCTL_EVENT_LOG_SIZE;
+@@ -1614,12 +1560,10 @@ mptctl_eventquery (unsigned long arg)
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ static int
+-mptctl_eventenable (unsigned long arg)
++mptctl_eventenable (MPT_ADAPTER *ioc, unsigned long arg)
+ {
+ struct mpt_ioctl_eventenable __user *uarg = (void __user *) arg;
+ struct mpt_ioctl_eventenable karg;
+- MPT_ADAPTER *ioc;
+- int iocnum;
+
+ if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) {
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_eventenable - "
+@@ -1628,13 +1572,6 @@ mptctl_eventenable (unsigned long arg)
+ return -EFAULT;
+ }
+
+- if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+- (ioc == NULL)) {
+- printk(KERN_DEBUG MYNAM "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
+- __FILE__, __LINE__, iocnum);
+- return -ENODEV;
+- }
+-
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventenable called.\n",
+ ioc->name));
+ if (ioc->events == NULL) {
+@@ -1662,12 +1599,10 @@ mptctl_eventenable (unsigned long arg)
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ static int
+-mptctl_eventreport (unsigned long arg)
++mptctl_eventreport (MPT_ADAPTER *ioc, unsigned long arg)
+ {
+ struct mpt_ioctl_eventreport __user *uarg = (void __user *) arg;
+ struct mpt_ioctl_eventreport karg;
+- MPT_ADAPTER *ioc;
+- int iocnum;
+ int numBytes, maxEvents, max;
+
+ if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) {
+@@ -1677,12 +1612,6 @@ mptctl_eventreport (unsigned long arg)
+ return -EFAULT;
+ }
+
+- if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+- (ioc == NULL)) {
+- printk(KERN_DEBUG MYNAM "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
+- __FILE__, __LINE__, iocnum);
+- return -ENODEV;
+- }
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventreport called.\n",
+ ioc->name));
+
+@@ -1716,12 +1645,10 @@ mptctl_eventreport (unsigned long arg)
+
+ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ static int
+-mptctl_replace_fw (unsigned long arg)
++mptctl_replace_fw (MPT_ADAPTER *ioc, unsigned long arg)
+ {
+ struct mpt_ioctl_replace_fw __user *uarg = (void __user *) arg;
+ struct mpt_ioctl_replace_fw karg;
+- MPT_ADAPTER *ioc;
+- int iocnum;
+ int newFwSize;
+
+ if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) {
+@@ -1731,13 +1658,6 @@ mptctl_replace_fw (unsigned long arg)
+ return -EFAULT;
+ }
+
+- if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+- (ioc == NULL)) {
+- printk(KERN_DEBUG MYNAM "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
+- __FILE__, __LINE__, iocnum);
+- return -ENODEV;
+- }
+-
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_replace_fw called.\n",
+ ioc->name));
+ /* If caching FW, Free the old FW image
+@@ -1789,12 +1709,10 @@ mptctl_replace_fw (unsigned long arg)
+ * -ENOMEM if memory allocation error
+ */
+ static int
+-mptctl_mpt_command (unsigned long arg)
++mptctl_mpt_command (MPT_ADAPTER *ioc, unsigned long arg)
+ {
+ struct mpt_ioctl_command __user *uarg = (void __user *) arg;
+ struct mpt_ioctl_command karg;
+- MPT_ADAPTER *ioc;
+- int iocnum;
+ int rc;
+
+
+@@ -1805,14 +1723,7 @@ mptctl_mpt_command (unsigned long arg)
+ return -EFAULT;
+ }
+
+- if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+- (ioc == NULL)) {
+- printk(KERN_DEBUG MYNAM "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
+- __FILE__, __LINE__, iocnum);
+- return -ENODEV;
+- }
+-
+- rc = mptctl_do_mpt_command (karg, &uarg->MF);
++ rc = mptctl_do_mpt_command (ioc, karg, &uarg->MF);
+
+ return rc;
+ }
+@@ -1830,9 +1741,8 @@ mptctl_mpt_command (unsigned long arg)
+ * -EPERM if SCSI I/O and target is untagged
+ */
+ static int
+-mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
++mptctl_do_mpt_command (MPT_ADAPTER *ioc, struct mpt_ioctl_command karg, void __user *mfPtr)
+ {
+- MPT_ADAPTER *ioc;
+ MPT_FRAME_HDR *mf = NULL;
+ MPIHeader_t *hdr;
+ char *psge;
+@@ -1841,7 +1751,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+ dma_addr_t dma_addr_in;
+ dma_addr_t dma_addr_out;
+ int sgSize = 0; /* Num SG elements */
+- int iocnum, flagsLength;
++ int flagsLength;
+ int sz, rc = 0;
+ int msgContext;
+ u16 req_idx;
+@@ -1856,13 +1766,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_
+ bufIn.kptr = bufOut.kptr = NULL;
+ bufIn.len = bufOut.len = 0;
+
+- if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+- (ioc == NULL)) {
+- printk(KERN_DEBUG MYNAM "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
+- __FILE__, __LINE__, iocnum);
+- return -ENODEV;
+- }
+-
+ spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+ if (ioc->ioc_reset_in_progress) {
+ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+@@ -2418,17 +2321,15 @@ done_free_mem:
+ * -ENOMEM if memory allocation error
+ */
+ static int
+-mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
++mptctl_hp_hostinfo(MPT_ADAPTER *ioc, unsigned long arg, unsigned int data_size)
+ {
+ hp_host_info_t __user *uarg = (void __user *) arg;
+- MPT_ADAPTER *ioc;
+ struct pci_dev *pdev;
+ char *pbuf=NULL;
+ dma_addr_t buf_dma;
+ hp_host_info_t karg;
+ CONFIGPARMS cfg;
+ ConfigPageHeader_t hdr;
+- int iocnum;
+ int rc, cim_rev;
+ ToolboxIstwiReadWriteRequest_t *IstwiRWRequest;
+ MPT_FRAME_HDR *mf = NULL;
+@@ -2452,12 +2353,6 @@ mptctl_hp_hostinfo(unsigned long arg, un
+ return -EFAULT;
+ }
+
+- if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+- (ioc == NULL)) {
+- printk(KERN_DEBUG MYNAM "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
+- __FILE__, __LINE__, iocnum);
+- return -ENODEV;
+- }
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_hostinfo called.\n",
+ ioc->name));
+
+@@ -2670,15 +2565,13 @@ retry_wait:
+ * -ENOMEM if memory allocation error
+ */
+ static int
+-mptctl_hp_targetinfo(unsigned long arg)
++mptctl_hp_targetinfo(MPT_ADAPTER *ioc, unsigned long arg)
+ {
+ hp_target_info_t __user *uarg = (void __user *) arg;
+ SCSIDevicePage0_t *pg0_alloc;
+ SCSIDevicePage3_t *pg3_alloc;
+- MPT_ADAPTER *ioc;
+ MPT_SCSI_HOST *hd = NULL;
+ hp_target_info_t karg;
+- int iocnum;
+ int data_sz;
+ dma_addr_t page_dma;
+ CONFIGPARMS cfg;
+@@ -2692,12 +2585,6 @@ mptctl_hp_targetinfo(unsigned long arg)
+ return -EFAULT;
+ }
+
+- if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+- (ioc == NULL)) {
+- printk(KERN_DEBUG MYNAM "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
+- __FILE__, __LINE__, iocnum);
+- return -ENODEV;
+- }
+ if (karg.hdr.id >= MPT_MAX_FC_DEVICES)
+ return -EINVAL;
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n",
+@@ -2865,7 +2752,7 @@ compat_mptfwxfer_ioctl(struct file *filp
+ kfw.fwlen = kfw32.fwlen;
+ kfw.bufp = compat_ptr(kfw32.bufp);
+
+- ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen);
++ ret = mptctl_do_fw_download(iocp, kfw.bufp, kfw.fwlen);
+
+ mutex_unlock(&iocp->ioctl_cmds.mutex);
+
+@@ -2919,7 +2806,7 @@ compat_mpt_command(struct file *filp, un
+
+ /* Pass new structure to do_mpt_command
+ */
+- ret = mptctl_do_mpt_command (karg, &uarg->MF);
++ ret = mptctl_do_mpt_command (iocp, karg, &uarg->MF);
+
+ mutex_unlock(&iocp->ioctl_cmds.mutex);
+
diff --git a/queue-3.16/scsi-sg-add-sg_remove_request-in-sg_common_write.patch b/queue-3.16/scsi-sg-add-sg_remove_request-in-sg_common_write.patch
new file mode 100644
index 00000000..c869cda4
--- /dev/null
+++ b/queue-3.16/scsi-sg-add-sg_remove_request-in-sg_common_write.patch
@@ -0,0 +1,34 @@
+From: Li Bin <huawei.libin@huawei.com>
+Date: Mon, 13 Apr 2020 19:29:21 +0800
+Subject: scsi: sg: add sg_remove_request in sg_common_write
+
+commit 849f8583e955dbe3a1806e03ecacd5e71cce0a08 upstream.
+
+If the dxfer_len is greater than 256M then the request is invalid and we
+need to call sg_remove_request in sg_common_write.
+
+Link: https://lore.kernel.org/r/1586777361-17339-1-git-send-email-huawei.libin@huawei.com
+Fixes: f930c7043663 ("scsi: sg: only check for dxfer_len greater than 256M")
+Acked-by: Douglas Gilbert <dgilbert@interlog.com>
+Signed-off-by: Li Bin <huawei.libin@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -808,8 +808,10 @@ sg_common_write(Sg_fd * sfp, Sg_request
+ SCSI_LOG_TIMEOUT(4, printk("sg_common_write: scsi opcode=0x%02x, cmd_size=%d\n",
+ (int) cmnd[0], (int) hp->cmd_len));
+
+- if (hp->dxfer_len >= SZ_256M)
++ if (hp->dxfer_len >= SZ_256M) {
++ sg_remove_request(sfp, srp);
+ return -EINVAL;
++ }
+
+ k = sg_start_req(srp, cmnd);
+ if (k) {
diff --git a/queue-3.16/scsi-sg-add-sg_remove_request-in-sg_write.patch b/queue-3.16/scsi-sg-add-sg_remove_request-in-sg_write.patch
new file mode 100644
index 00000000..4329e8d0
--- /dev/null
+++ b/queue-3.16/scsi-sg-add-sg_remove_request-in-sg_write.patch
@@ -0,0 +1,36 @@
+From: Wu Bo <wubo40@huawei.com>
+Date: Tue, 14 Apr 2020 10:13:28 +0800
+Subject: scsi: sg: add sg_remove_request in sg_write
+
+commit 83c6f2390040f188cc25b270b4befeb5628c1aee upstream.
+
+If the __copy_from_user function failed we need to call sg_remove_request
+in sg_write.
+
+Link: https://lore.kernel.org/r/610618d9-e983-fd56-ed0f-639428343af7@huawei.com
+Acked-by: Douglas Gilbert <dgilbert@interlog.com>
+Signed-off-by: Wu Bo <wubo40@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+[groeck: Backport to v5.4.y and older kernels]
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -696,8 +696,10 @@ sg_write(struct file *filp, const char _
+ hp->flags = input_size; /* structure abuse ... */
+ hp->pack_id = old_hdr.pack_id;
+ hp->usr_ptr = NULL;
+- if (__copy_from_user(cmnd, buf, cmd_size))
++ if (__copy_from_user(cmnd, buf, cmd_size)) {
++ sg_remove_request(sfp, srp);
+ return -EFAULT;
++ }
+ /*
+ * SG_DXFER_TO_FROM_DEV is functionally equivalent to SG_DXFER_FROM_DEV,
+ * but is is possible that the app intended SG_DXFER_TO_DEV, because there
diff --git a/queue-3.16/scsi-sg-change-next_cmd_len-handling-to-mirror-upstream.patch b/queue-3.16/scsi-sg-change-next_cmd_len-handling-to-mirror-upstream.patch
new file mode 100644
index 00000000..a1785d57
--- /dev/null
+++ b/queue-3.16/scsi-sg-change-next_cmd_len-handling-to-mirror-upstream.patch
@@ -0,0 +1,47 @@
+From: Ben Hutchings <ben@decadent.org.uk>
+Date: Thu, 28 May 2020 18:54:25 +0100
+Subject: scsi: sg: Change next_cmd_len handling to mirror upstream
+
+Change the type of next_cmd_len to unsigned char, done in upstream
+commit 65c26a0f3969 "sg: relax 16 byte cdb restriction".
+
+Move the range check from sg_write() to sg_ioctl(), which was done by
+that commit and commit bf33f87dd04c "scsi: sg: check length passed to
+SG_NEXT_CMD_LEN". Continue limiting the command length to
+MAX_COMMAND_SIZE (16).
+
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -160,7 +160,7 @@ typedef struct sg_fd { /* holds the sta
+ char low_dma; /* as in parent but possibly overridden to 1 */
+ char force_packid; /* 1 -> pack_id input to read(), 0 -> ignored */
+ char cmd_q; /* 1 -> allow command queuing, 0 -> don't */
+- char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */
++ unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */
+ char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */
+ char mmap_called; /* 0 -> mmap() never called on this fd */
+ struct kref f_ref;
+@@ -653,12 +653,6 @@ sg_write(struct file *filp, const char _
+ buf += SZ_SG_HEADER;
+ __get_user(opcode, buf);
+ if (sfp->next_cmd_len > 0) {
+- if (sfp->next_cmd_len > MAX_COMMAND_SIZE) {
+- SCSI_LOG_TIMEOUT(1, printk("sg_write: command length too long\n"));
+- sfp->next_cmd_len = 0;
+- sg_remove_request(sfp, srp);
+- return -EIO;
+- }
+ cmd_size = sfp->next_cmd_len;
+ sfp->next_cmd_len = 0; /* reset so only this write() effected */
+ } else {
+@@ -1045,6 +1039,8 @@ sg_ioctl(struct file *filp, unsigned int
+ result = get_user(val, ip);
+ if (result)
+ return result;
++ if (val > MAX_COMMAND_SIZE)
++ return -ENOMEM;
+ sfp->next_cmd_len = (val > 0) ? val : 0;
+ return 0;
+ case SG_GET_VERSION_NUM:
diff --git a/queue-3.16/scsi-sg-check-for-valid-direction-before-starting-the-request.patch b/queue-3.16/scsi-sg-check-for-valid-direction-before-starting-the-request.patch
new file mode 100644
index 00000000..e28fb991
--- /dev/null
+++ b/queue-3.16/scsi-sg-check-for-valid-direction-before-starting-the-request.patch
@@ -0,0 +1,95 @@
+From: Johannes Thumshirn <jthumshirn@suse.de>
+Date: Fri, 7 Apr 2017 09:34:15 +0200
+Subject: scsi: sg: check for valid direction before starting the request
+
+commit 28676d869bbb5257b5f14c0c95ad3af3a7019dd5 upstream.
+
+Check for a valid direction before starting the request, otherwise we
+risk running into an assertion in the scsi midlayer checking for valid
+requests.
+
+[mkp: fixed typo]
+
+Signed-off-by: Johannes Thumshirn <jthumshirn@suse.de>
+Link: http://www.spinics.net/lists/linux-scsi/msg104400.html
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+Tested-by: Johannes Thumshirn <jthumshirn@suse.de>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 46 ++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 34 insertions(+), 12 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -701,18 +701,14 @@ sg_write(struct file *filp, const char _
+ * is a non-zero input_size, so emit a warning.
+ */
+ if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) {
+- static char cmd[TASK_COMM_LEN];
+- if (strcmp(current->comm, cmd)) {
+- printk_ratelimited(KERN_WARNING
+- "sg_write: data in/out %d/%d bytes "
+- "for SCSI command 0x%x-- guessing "
+- "data in;\n program %s not setting "
+- "count and/or reply_len properly\n",
+- old_hdr.reply_len - (int)SZ_SG_HEADER,
+- input_size, (unsigned int) cmnd[0],
+- current->comm);
+- strcpy(cmd, current->comm);
+- }
++ printk_ratelimited(KERN_WARNING
++ "sg_write: data in/out %d/%d bytes "
++ "for SCSI command 0x%x-- guessing "
++ "data in;\n program %s not setting "
++ "count and/or reply_len properly\n",
++ old_hdr.reply_len - (int)SZ_SG_HEADER,
++ input_size, (unsigned int) cmnd[0],
++ current->comm);
+ }
+ k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking);
+ return (k < 0) ? k : count;
+@@ -790,6 +786,29 @@ sg_new_write(Sg_fd *sfp, struct file *fi
+ return count;
+ }
+
++static bool sg_is_valid_dxfer(sg_io_hdr_t *hp)
++{
++ switch (hp->dxfer_direction) {
++ case SG_DXFER_NONE:
++ if (hp->dxferp || hp->dxfer_len > 0)
++ return false;
++ return true;
++ case SG_DXFER_TO_DEV:
++ case SG_DXFER_FROM_DEV:
++ case SG_DXFER_TO_FROM_DEV:
++ if (!hp->dxferp || hp->dxfer_len == 0)
++ return false;
++ return true;
++ case SG_DXFER_UNKNOWN:
++ if ((!hp->dxferp && hp->dxfer_len) ||
++ (hp->dxferp && hp->dxfer_len == 0))
++ return false;
++ return true;
++ default:
++ return false;
++ }
++}
++
+ static int
+ sg_common_write(Sg_fd * sfp, Sg_request * srp,
+ unsigned char *cmnd, int timeout, int blocking)
+@@ -809,6 +828,9 @@ sg_common_write(Sg_fd * sfp, Sg_request
+ SCSI_LOG_TIMEOUT(4, printk("sg_common_write: scsi opcode=0x%02x, cmd_size=%d\n",
+ (int) cmnd[0], (int) hp->cmd_len));
+
++ if (!sg_is_valid_dxfer(hp))
++ return -EINVAL;
++
+ k = sg_start_req(srp, cmnd);
+ if (k) {
+ SCSI_LOG_TIMEOUT(1, printk("sg_common_write: start_req err=%d\n", k));
diff --git a/queue-3.16/scsi-sg-close-race-condition-in-sg_remove_sfp_usercontext.patch b/queue-3.16/scsi-sg-close-race-condition-in-sg_remove_sfp_usercontext.patch
new file mode 100644
index 00000000..762e1049
--- /dev/null
+++ b/queue-3.16/scsi-sg-close-race-condition-in-sg_remove_sfp_usercontext.patch
@@ -0,0 +1,91 @@
+From: Hannes Reinecke <hare@suse.de>
+Date: Fri, 7 Apr 2017 09:34:17 +0200
+Subject: scsi: sg: close race condition in sg_remove_sfp_usercontext()
+
+commit 97d27b0dd015e980ade63fda111fd1353276e28b upstream.
+
+sg_remove_sfp_usercontext() is clearing any sg requests, but needs to
+take 'rq_list_lock' when modifying the list.
+
+Reported-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+Tested-by: Johannes Thumshirn <jthumshirn@suse.de>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -561,6 +561,7 @@ sg_read(struct file *filp, char __user *
+ } else
+ count = (old_hdr->result == 0) ? 0 : -EIO;
+ sg_finish_rem_req(srp);
++ sg_remove_request(sfp, srp);
+ retval = count;
+ free_old_hdr:
+ kfree(old_hdr);
+@@ -601,6 +602,7 @@ sg_new_read(Sg_fd * sfp, char __user *bu
+ }
+ err_out:
+ err2 = sg_finish_rem_req(srp);
++ sg_remove_request(sfp, srp);
+ return err ? : err2 ? : count;
+ }
+
+@@ -835,6 +837,7 @@ sg_common_write(Sg_fd * sfp, Sg_request
+ if (k) {
+ SCSI_LOG_TIMEOUT(1, printk("sg_common_write: start_req err=%d\n", k));
+ sg_finish_rem_req(srp);
++ sg_remove_request(sfp, srp);
+ return k; /* probably out of space --> ENOMEM */
+ }
+ if (atomic_read(&sdp->detaching)) {
+@@ -844,6 +847,7 @@ sg_common_write(Sg_fd * sfp, Sg_request
+ }
+
+ sg_finish_rem_req(srp);
++ sg_remove_request(sfp, srp);
+ return -ENODEV;
+ }
+
+@@ -1367,6 +1371,7 @@ sg_rq_end_io_usercontext(struct work_str
+ struct sg_fd *sfp = srp->parentfp;
+
+ sg_finish_rem_req(srp);
++ sg_remove_request(sfp, srp);
+ kref_put(&sfp->f_ref, sg_remove_sfp);
+ }
+
+@@ -1876,8 +1881,6 @@ sg_finish_rem_req(Sg_request *srp)
+ else
+ sg_remove_scat(req_schp);
+
+- sg_remove_request(sfp, srp);
+-
+ return ret;
+ }
+
+@@ -2211,12 +2214,17 @@ sg_remove_sfp_usercontext(struct work_st
+ struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work);
+ struct sg_device *sdp = sfp->parentdp;
+ Sg_request *srp;
++ unsigned long iflags;
+
+ /* Cleanup any responses which were never read(). */
++ write_lock_irqsave(&sfp->rq_list_lock, iflags);
+ while (!list_empty(&sfp->rq_list)) {
+ srp = list_first_entry(&sfp->rq_list, Sg_request, entry);
+ sg_finish_rem_req(srp);
++ list_del(&srp->entry);
++ srp->parentfp = NULL;
+ }
++ write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+
+ if (sfp->reserve.bufflen > 0) {
+ SCSI_LOG_TIMEOUT(6,
diff --git a/queue-3.16/scsi-sg-disable-set_force_low_dma.patch b/queue-3.16/scsi-sg-disable-set_force_low_dma.patch
new file mode 100644
index 00000000..fb03f518
--- /dev/null
+++ b/queue-3.16/scsi-sg-disable-set_force_low_dma.patch
@@ -0,0 +1,109 @@
+From: Hannes Reinecke <hare@suse.de>
+Date: Fri, 7 Apr 2017 09:34:12 +0200
+Subject: scsi: sg: disable SET_FORCE_LOW_DMA
+
+commit 745dfa0d8ec26b24f3304459ff6e9eacc5c8351b upstream.
+
+The ioctl SET_FORCE_LOW_DMA has never worked since the initial git
+check-in, and the respective setting is nowadays handled correctly. So
+disable it entirely.
+
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+Tested-by: Johannes Thumshirn <jthumshirn@suse.de>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+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/scsi/sg.c | 30 +++++++++---------------------
+ include/scsi/sg.h | 1 -
+ 2 files changed, 9 insertions(+), 22 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -157,7 +157,6 @@ typedef struct sg_fd { /* holds the sta
+ struct list_head rq_list; /* head of request list */
+ struct fasync_struct *async_qp; /* used by asynchronous notification */
+ Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */
+- char low_dma; /* as in parent but possibly overridden to 1 */
+ char force_packid; /* 1 -> pack_id input to read(), 0 -> ignored */
+ char cmd_q; /* 1 -> allow command queuing, 0 -> don't */
+ unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */
+@@ -963,24 +962,14 @@ sg_ioctl(struct file *filp, unsigned int
+ /* strange ..., for backward compatibility */
+ return sfp->timeout_user;
+ case SG_SET_FORCE_LOW_DMA:
+- result = get_user(val, ip);
+- if (result)
+- return result;
+- if (val) {
+- sfp->low_dma = 1;
+- if ((0 == sfp->low_dma) && !sfp->res_in_use) {
+- val = (int) sfp->reserve.bufflen;
+- sg_remove_scat(&sfp->reserve);
+- sg_build_reserve(sfp, val);
+- }
+- } else {
+- if (atomic_read(&sdp->detaching))
+- return -ENODEV;
+- sfp->low_dma = sdp->device->host->unchecked_isa_dma;
+- }
++ /*
++ * N.B. This ioctl never worked properly, but failed to
++ * return an error value. So returning '0' to keep compability
++ * with legacy applications.
++ */
+ return 0;
+ case SG_GET_LOW_DMA:
+- return put_user((int) sfp->low_dma, ip);
++ return put_user((int) sdp->device->host->unchecked_isa_dma, ip);
+ case SG_GET_SCSI_ID:
+ if (!access_ok(VERIFY_WRITE, p, sizeof (sg_scsi_id_t)))
+ return -EFAULT;
+@@ -1890,6 +1879,7 @@ sg_build_indirect(Sg_scatter_hold * schp
+ int sg_tablesize = sfp->parentdp->sg_tablesize;
+ int blk_size = buff_size, order;
+ gfp_t gfp_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN;
++ struct sg_device *sdp = sfp->parentdp;
+
+ if (blk_size < 0)
+ return -EFAULT;
+@@ -1914,7 +1904,7 @@ sg_build_indirect(Sg_scatter_hold * schp
+ scatter_elem_sz_prev = num;
+ }
+
+- if (sfp->low_dma)
++ if (sdp->device->host->unchecked_isa_dma)
+ gfp_mask |= GFP_DMA;
+
+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+@@ -2168,8 +2158,6 @@ sg_add_sfp(Sg_device * sdp, int dev)
+ sfp->timeout = SG_DEFAULT_TIMEOUT;
+ sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER;
+ sfp->force_packid = SG_DEF_FORCE_PACK_ID;
+- sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
+- sdp->device->host->unchecked_isa_dma : 1;
+ sfp->cmd_q = SG_DEF_COMMAND_Q;
+ sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
+ sfp->parentdp = sdp;
+@@ -2627,7 +2615,7 @@ static void sg_proc_debug_helper(struct
+ jiffies_to_msecs(fp->timeout),
+ fp->reserve.bufflen,
+ (int) fp->reserve.k_use_sg,
+- (int) fp->low_dma);
++ (int) sdp->device->host->unchecked_isa_dma);
+ seq_printf(s, " cmd_q=%d f_packid=%d k_orphan=%d closed=0\n",
+ (int) fp->cmd_q, (int) fp->force_packid,
+ (int) fp->keep_orphan);
+--- a/include/scsi/sg.h
++++ b/include/scsi/sg.h
+@@ -234,7 +234,6 @@ typedef struct sg_req_info { /* used by
+ #define SG_DEFAULT_RETRIES 0
+
+ /* Defaults, commented if they differ from original sg driver */
+-#define SG_DEF_FORCE_LOW_DMA 0 /* was 1 -> memory below 16MB on i386 */
+ #define SG_DEF_FORCE_PACK_ID 0
+ #define SG_DEF_KEEP_ORPHAN 0
+ #define SG_DEF_RESERVED_SIZE SG_SCATTER_SZ /* load time option */
diff --git a/queue-3.16/scsi-sg-don-t-return-bogus-sg_requests.patch b/queue-3.16/scsi-sg-don-t-return-bogus-sg_requests.patch
new file mode 100644
index 00000000..af84e81d
--- /dev/null
+++ b/queue-3.16/scsi-sg-don-t-return-bogus-sg_requests.patch
@@ -0,0 +1,45 @@
+From: Johannes Thumshirn <jthumshirn@suse.de>
+Date: Wed, 10 May 2017 09:53:40 +0200
+Subject: scsi: sg: don't return bogus Sg_requests
+
+commit 48ae8484e9fc324b4968d33c585e54bc98e44d61 upstream.
+
+If the list search in sg_get_rq_mark() fails to find a valid request, we
+return a bogus element. This then can later lead to a GPF in
+sg_remove_scat().
+
+So don't return bogus Sg_requests in sg_get_rq_mark() but NULL in case
+the list search doesn't find a valid request.
+
+Signed-off-by: Johannes Thumshirn <jthumshirn@suse.de>
+Reported-by: Andrey Konovalov <andreyknvl@google.com>
+Cc: Hannes Reinecke <hare@suse.de>
+Cc: Christoph Hellwig <hch@lst.de>
+Cc: Doug Gilbert <dgilbert@interlog.com>
+Reviewed-by: Hannes Reinecke <hare@suse.de>
+Acked-by: Doug Gilbert <dgilbert@interlog.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Cc: Tony Battersby <tonyb@cybernetics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -2085,11 +2085,12 @@ sg_get_rq_mark(Sg_fd * sfp, int pack_id)
+ if ((1 == resp->done) && (!resp->sg_io_owned) &&
+ ((-1 == pack_id) || (resp->header.pack_id == pack_id))) {
+ resp->done = 2; /* guard against other readers */
+- break;
++ write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
++ return resp;
+ }
+ }
+ write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+- return resp;
++ return NULL;
+ }
+
+ /* always adds to end of list */
diff --git a/queue-3.16/scsi-sg-factor-out-sg_fill_request_table.patch b/queue-3.16/scsi-sg-factor-out-sg_fill_request_table.patch
new file mode 100644
index 00000000..6d6e86ab
--- /dev/null
+++ b/queue-3.16/scsi-sg-factor-out-sg_fill_request_table.patch
@@ -0,0 +1,103 @@
+From: Hannes Reinecke <hare@suse.de>
+Date: Fri, 15 Sep 2017 14:05:15 +0200
+Subject: scsi: sg: factor out sg_fill_request_table()
+
+commit 4759df905a474d245752c9dc94288e779b8734dd upstream.
+
+Factor out sg_fill_request_table() for better readability.
+
+[mkp: typos, applied by hand]
+
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Bart Van Assche <bart.vanassche@wdc.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 61 +++++++++++++++++++++++++++--------------------
+ 1 file changed, 35 insertions(+), 26 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -870,6 +870,40 @@ static int max_sectors_bytes(struct requ
+ return max_sectors << 9;
+ }
+
++static void
++sg_fill_request_table(Sg_fd *sfp, sg_req_info_t *rinfo)
++{
++ Sg_request *srp;
++ int val;
++ unsigned int ms;
++
++ val = 0;
++ list_for_each_entry(srp, &sfp->rq_list, entry) {
++ if (val > SG_MAX_QUEUE)
++ break;
++ memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
++ rinfo[val].req_state = srp->done + 1;
++ rinfo[val].problem =
++ srp->header.masked_status &
++ srp->header.host_status &
++ srp->header.driver_status;
++ if (srp->done)
++ rinfo[val].duration =
++ srp->header.duration;
++ else {
++ ms = jiffies_to_msecs(jiffies);
++ rinfo[val].duration =
++ (ms > srp->header.duration) ?
++ (ms - srp->header.duration) : 0;
++ }
++ rinfo[val].orphan = srp->orphan;
++ rinfo[val].sg_io_owned = srp->sg_io_owned;
++ rinfo[val].pack_id = srp->header.pack_id;
++ rinfo[val].usr_ptr = srp->header.usr_ptr;
++ val++;
++ }
++}
++
+ static long
+ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
+ {
+@@ -1063,38 +1097,13 @@ sg_ioctl(struct file *filp, unsigned int
+ return -EFAULT;
+ else {
+ sg_req_info_t *rinfo;
+- unsigned int ms;
+
+ rinfo = kmalloc(SZ_SG_REQ_INFO * SG_MAX_QUEUE,
+ GFP_KERNEL);
+ if (!rinfo)
+ return -ENOMEM;
+ read_lock_irqsave(&sfp->rq_list_lock, iflags);
+- val = 0;
+- list_for_each_entry(srp, &sfp->rq_list, entry) {
+- if (val >= SG_MAX_QUEUE)
+- break;
+- memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
+- rinfo[val].req_state = srp->done + 1;
+- rinfo[val].problem =
+- srp->header.masked_status &
+- srp->header.host_status &
+- srp->header.driver_status;
+- if (srp->done)
+- rinfo[val].duration =
+- srp->header.duration;
+- else {
+- ms = jiffies_to_msecs(jiffies);
+- rinfo[val].duration =
+- (ms > srp->header.duration) ?
+- (ms - srp->header.duration) : 0;
+- }
+- rinfo[val].orphan = srp->orphan;
+- rinfo[val].sg_io_owned = srp->sg_io_owned;
+- rinfo[val].pack_id = srp->header.pack_id;
+- rinfo[val].usr_ptr = srp->header.usr_ptr;
+- val++;
+- }
++ sg_fill_request_table(sfp, rinfo);
+ read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+ result = __copy_to_user(p, rinfo,
+ SZ_SG_REQ_INFO * SG_MAX_QUEUE);
diff --git a/queue-3.16/scsi-sg-fix-minor-memory-leak-in-error-path.patch b/queue-3.16/scsi-sg-fix-minor-memory-leak-in-error-path.patch
new file mode 100644
index 00000000..31fba5ed
--- /dev/null
+++ b/queue-3.16/scsi-sg-fix-minor-memory-leak-in-error-path.patch
@@ -0,0 +1,30 @@
+From: Tony Battersby <tonyb@cybernetics.com>
+Date: Thu, 12 Jul 2018 16:30:45 -0400
+Subject: scsi: sg: fix minor memory leak in error path
+
+commit c170e5a8d222537e98aa8d4fddb667ff7a2ee114 upstream.
+
+Fix a minor memory leak when there is an error opening a /dev/sg device.
+
+Fixes: cc833acbee9d ("sg: O_EXCL and other lock handling")
+Cc: <stable@vger.kernel.org>
+Reviewed-by: Ewan D. Milne <emilne@redhat.com>
+Signed-off-by: Tony Battersby <tonyb@cybernetics.com>
+Reviewed-by: Bart Van Assche <bart.vanassche@wdc.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -2168,6 +2168,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
+ write_lock_irqsave(&sdp->sfd_lock, iflags);
+ if (atomic_read(&sdp->detaching)) {
+ write_unlock_irqrestore(&sdp->sfd_lock, iflags);
++ kfree(sfp);
+ return ERR_PTR(-ENODEV);
+ }
+ list_add_tail(&sfp->sfd_siblings, &sdp->sfds);
diff --git a/queue-3.16/scsi-sg-fix-sg_dxfer_from_dev-transfers.patch b/queue-3.16/scsi-sg-fix-sg_dxfer_from_dev-transfers.patch
new file mode 100644
index 00000000..85a60e6e
--- /dev/null
+++ b/queue-3.16/scsi-sg-fix-sg_dxfer_from_dev-transfers.patch
@@ -0,0 +1,43 @@
+From: Johannes Thumshirn <jthumshirn@suse.de>
+Date: Fri, 7 Jul 2017 10:56:38 +0200
+Subject: scsi: sg: fix SG_DXFER_FROM_DEV transfers
+
+commit 68c59fcea1f2c6a54c62aa896cc623c1b5bc9b47 upstream.
+
+SG_DXFER_FROM_DEV transfers do not necessarily have a dxferp as we set
+it to NULL for the old sg_io read/write interface, but must have a
+length bigger than 0. This fixes a regression introduced by commit
+28676d869bbb ("scsi: sg: check for valid direction before starting the
+request")
+
+Signed-off-by: Johannes Thumshirn <jthumshirn@suse.de>
+Fixes: 28676d869bbb ("scsi: sg: check for valid direction before starting the request")
+Reported-by: Chris Clayton <chris2553@googlemail.com>
+Tested-by: Chris Clayton <chris2553@googlemail.com>
+Cc: Douglas Gilbert <dgilbert@interlog.com>
+Reviewed-by: Hannes Reinecke <hare@suse.com>
+Tested-by: Chris Clayton <chris2553@googlemail.com>
+Acked-by: Douglas Gilbert <dgilbert@interlog.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Cc: Cristian Crinteanu <crinteanu.cristian@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -795,8 +795,11 @@ static bool sg_is_valid_dxfer(sg_io_hdr_
+ if (hp->dxferp || hp->dxfer_len > 0)
+ return false;
+ return true;
+- case SG_DXFER_TO_DEV:
+ case SG_DXFER_FROM_DEV:
++ if (hp->dxfer_len < 0)
++ return false;
++ return true;
++ case SG_DXFER_TO_DEV:
+ case SG_DXFER_TO_FROM_DEV:
+ if (!hp->dxferp || hp->dxfer_len == 0)
+ return false;
diff --git a/queue-3.16/scsi-sg-fix-static-checker-warning-in-sg_is_valid_dxfer.patch b/queue-3.16/scsi-sg-fix-static-checker-warning-in-sg_is_valid_dxfer.patch
new file mode 100644
index 00000000..911d97b6
--- /dev/null
+++ b/queue-3.16/scsi-sg-fix-static-checker-warning-in-sg_is_valid_dxfer.patch
@@ -0,0 +1,41 @@
+From: Johannes Thumshirn <jthumshirn@suse.de>
+Date: Mon, 17 Jul 2017 15:11:42 +0200
+Subject: scsi: sg: fix static checker warning in sg_is_valid_dxfer
+
+commit 14074aba4bcda3764c9a702b276308b89901d5b6 upstream.
+
+dxfer_len is an unsigned int and we always assign a value > 0 to it, so
+it doesn't make any sense to check if it is < 0. We can't really check
+dxferp as well as we have both NULL and not NULL cases in the possible
+call paths.
+
+So just return true for SG_DXFER_FROM_DEV transfer in
+sg_is_valid_dxfer().
+
+Signed-off-by: Johannes Thumshirn <jthumshirn@suse.de>
+Reported-by: Colin Ian King <colin.king@canonical.com>
+Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
+Cc: Douglas Gilbert <dgilbert@interlog.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -796,8 +796,11 @@ static bool sg_is_valid_dxfer(sg_io_hdr_
+ return false;
+ return true;
+ case SG_DXFER_FROM_DEV:
+- if (hp->dxfer_len < 0)
+- return false;
++ /*
++ * for SG_DXFER_FROM_DEV we always set dxfer_len to > 0. dxferp
++ * can either be NULL or != NULL so there's no point in checking
++ * it either. So just return true.
++ */
+ return true;
+ case SG_DXFER_TO_DEV:
+ case SG_DXFER_TO_FROM_DEV:
diff --git a/queue-3.16/scsi-sg-fixup-infoleak-when-using-sg_get_request_table.patch b/queue-3.16/scsi-sg-fixup-infoleak-when-using-sg_get_request_table.patch
new file mode 100644
index 00000000..b142bb3b
--- /dev/null
+++ b/queue-3.16/scsi-sg-fixup-infoleak-when-using-sg_get_request_table.patch
@@ -0,0 +1,43 @@
+From: Hannes Reinecke <hare@suse.de>
+Date: Fri, 15 Sep 2017 14:05:16 +0200
+Subject: scsi: sg: fixup infoleak when using SG_GET_REQUEST_TABLE
+
+commit 3e0097499839e0fe3af380410eababe5a47c4cf9 upstream.
+
+When calling SG_GET_REQUEST_TABLE ioctl only a half-filled table is
+returned; the remaining part will then contain stale kernel memory
+information. This patch zeroes out the entire table to avoid this
+issue.
+
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Bart Van Assche <bart.vanassche@wdc.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -881,7 +881,6 @@ sg_fill_request_table(Sg_fd *sfp, sg_req
+ list_for_each_entry(srp, &sfp->rq_list, entry) {
+ if (val > SG_MAX_QUEUE)
+ break;
+- memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
+ rinfo[val].req_state = srp->done + 1;
+ rinfo[val].problem =
+ srp->header.masked_status &
+@@ -1098,8 +1097,8 @@ sg_ioctl(struct file *filp, unsigned int
+ else {
+ sg_req_info_t *rinfo;
+
+- rinfo = kmalloc(SZ_SG_REQ_INFO * SG_MAX_QUEUE,
+- GFP_KERNEL);
++ rinfo = kzalloc(SZ_SG_REQ_INFO * SG_MAX_QUEUE,
++ GFP_KERNEL);
+ if (!rinfo)
+ return -ENOMEM;
+ read_lock_irqsave(&sfp->rq_list_lock, iflags);
diff --git a/queue-3.16/scsi-sg-off-by-one-in-sg_ioctl.patch b/queue-3.16/scsi-sg-off-by-one-in-sg_ioctl.patch
new file mode 100644
index 00000000..e91a87a5
--- /dev/null
+++ b/queue-3.16/scsi-sg-off-by-one-in-sg_ioctl.patch
@@ -0,0 +1,30 @@
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Thu, 17 Aug 2017 10:09:54 +0300
+Subject: scsi: sg: off by one in sg_ioctl()
+
+commit bd46fc406b30d1db1aff8dabaff8d18bb423fdcf upstream.
+
+If "val" is SG_MAX_QUEUE then we are one element beyond the end of the
+"rinfo" array so the > should be >=.
+
+Fixes: 109bade9c625 ("scsi: sg: use standard lists for sg_requests")
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Acked-by: Douglas Gilbert <dgilbert@interlog.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -1072,7 +1072,7 @@ sg_ioctl(struct file *filp, unsigned int
+ read_lock_irqsave(&sfp->rq_list_lock, iflags);
+ val = 0;
+ list_for_each_entry(srp, &sfp->rq_list, entry) {
+- if (val > SG_MAX_QUEUE)
++ if (val >= SG_MAX_QUEUE)
+ break;
+ memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
+ rinfo[val].req_state = srp->done + 1;
diff --git a/queue-3.16/scsi-sg-only-check-for-dxfer_len-greater-than-256m.patch b/queue-3.16/scsi-sg-only-check-for-dxfer_len-greater-than-256m.patch
new file mode 100644
index 00000000..0cd2ce05
--- /dev/null
+++ b/queue-3.16/scsi-sg-only-check-for-dxfer_len-greater-than-256m.patch
@@ -0,0 +1,82 @@
+From: Johannes Thumshirn <jthumshirn@suse.de>
+Date: Thu, 27 Jul 2017 09:11:26 +0200
+Subject: scsi: sg: only check for dxfer_len greater than 256M
+
+commit f930c7043663188429cd9b254e9d761edfc101ce upstream.
+
+Don't make any assumptions on the sg_io_hdr_t::dxfer_direction or the
+sg_io_hdr_t::dxferp in order to determine if it is a valid request. The
+only way we can check for bad requests is by checking if the length
+exceeds 256M.
+
+Signed-off-by: Johannes Thumshirn <jthumshirn@suse.de>
+Fixes: 28676d869bbb (scsi: sg: check for valid direction before starting the request)
+Reported-by: Jason L Tibbitts III <tibbs@math.uh.edu>
+Tested-by: Jason L Tibbitts III <tibbs@math.uh.edu>
+Suggested-by: Doug Gilbert <dgilbert@interlog.com>
+Cc: Doug Gilbert <dgilbert@interlog.com>
+Cc: <stable@vger.kernel.org>
+Reviewed-by: Hannes Reinecke <hare@suse.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+[bwh: Backported to 3.16: Include <linux/sizes.h>]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 31 +------------------------------
+ 1 file changed, 1 insertion(+), 30 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -54,6 +54,7 @@ static int sg_version_num = 30534; /* 2
+ #include <linux/atomic.h>
+ #include <linux/ratelimit.h>
+ #include <linux/cred.h> /* for sg_check_file_access() */
++#include <linux/sizes.h>
+
+ #include "scsi.h"
+ #include <scsi/scsi_dbg.h>
+@@ -788,35 +789,6 @@ sg_new_write(Sg_fd *sfp, struct file *fi
+ return count;
+ }
+
+-static bool sg_is_valid_dxfer(sg_io_hdr_t *hp)
+-{
+- switch (hp->dxfer_direction) {
+- case SG_DXFER_NONE:
+- if (hp->dxferp || hp->dxfer_len > 0)
+- return false;
+- return true;
+- case SG_DXFER_FROM_DEV:
+- /*
+- * for SG_DXFER_FROM_DEV we always set dxfer_len to > 0. dxferp
+- * can either be NULL or != NULL so there's no point in checking
+- * it either. So just return true.
+- */
+- return true;
+- case SG_DXFER_TO_DEV:
+- case SG_DXFER_TO_FROM_DEV:
+- if (!hp->dxferp || hp->dxfer_len == 0)
+- return false;
+- return true;
+- case SG_DXFER_UNKNOWN:
+- if ((!hp->dxferp && hp->dxfer_len) ||
+- (hp->dxferp && hp->dxfer_len == 0))
+- return false;
+- return true;
+- default:
+- return false;
+- }
+-}
+-
+ static int
+ sg_common_write(Sg_fd * sfp, Sg_request * srp,
+ unsigned char *cmnd, int timeout, int blocking)
+@@ -836,7 +808,7 @@ sg_common_write(Sg_fd * sfp, Sg_request
+ SCSI_LOG_TIMEOUT(4, printk("sg_common_write: scsi opcode=0x%02x, cmd_size=%d\n",
+ (int) cmnd[0], (int) hp->cmd_len));
+
+- if (!sg_is_valid_dxfer(hp))
++ if (hp->dxfer_len >= SZ_256M)
+ return -EINVAL;
+
+ k = sg_start_req(srp, cmnd);
diff --git a/queue-3.16/scsi-sg-protect-accesses-to-reserved-page-array.patch b/queue-3.16/scsi-sg-protect-accesses-to-reserved-page-array.patch
new file mode 100644
index 00000000..c8d3628a
--- /dev/null
+++ b/queue-3.16/scsi-sg-protect-accesses-to-reserved-page-array.patch
@@ -0,0 +1,169 @@
+From: Hannes Reinecke <hare@suse.de>
+Date: Fri, 7 Apr 2017 09:34:14 +0200
+Subject: scsi: sg: protect accesses to 'reserved' page array
+
+commit 1bc0eb0446158cc76562176b80623aa119afee5b upstream.
+
+The 'reserved' page array is used as a short-cut for mapping data,
+saving us to allocate pages per request. However, the 'reserved' array
+is only capable of holding one request, so this patch introduces a mutex
+for protect 'sg_fd' against concurrent accesses.
+
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+Tested-by: Johannes Thumshirn <jthumshirn@suse.de>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+[toddpoynor@google.com: backport to 3.18-4.9, fixup for bad ioctl
+SG_SET_FORCE_LOW_DMA code removed in later versions and not modified by
+the original patch.]
+
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+Tested-by: Johannes Thumshirn <jthumshirn@suse.de>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Todd Poynor <toddpoynor@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 47 ++++++++++++++++++++++++++---------------------
+ 1 file changed, 26 insertions(+), 21 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -150,6 +150,7 @@ typedef struct sg_fd { /* holds the sta
+ struct sg_device *parentdp; /* owning device */
+ wait_queue_head_t read_wait; /* queue read until command done */
+ rwlock_t rq_list_lock; /* protect access to list in req_arr */
++ struct mutex f_mutex; /* protect against changes in this fd */
+ int timeout; /* defaults to SG_DEFAULT_TIMEOUT */
+ int timeout_user; /* defaults to SG_DEFAULT_TIMEOUT_USER */
+ Sg_scatter_hold reserve; /* buffer held for this file descriptor */
+@@ -163,6 +164,7 @@ typedef struct sg_fd { /* holds the sta
+ unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */
+ char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */
+ char mmap_called; /* 0 -> mmap() never called on this fd */
++ char res_in_use; /* 1 -> 'reserve' array in use */
+ struct kref f_ref;
+ struct execute_work ew;
+ } Sg_fd;
+@@ -206,7 +208,6 @@ static void sg_remove_sfp(struct kref *)
+ static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id);
+ static Sg_request *sg_add_request(Sg_fd * sfp);
+ static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
+-static int sg_res_in_use(Sg_fd * sfp);
+ static Sg_device *sg_get_dev(int dev);
+ static void sg_device_destroy(struct kref *kref);
+
+@@ -652,6 +653,7 @@ sg_write(struct file *filp, const char _
+ }
+ buf += SZ_SG_HEADER;
+ __get_user(opcode, buf);
++ mutex_lock(&sfp->f_mutex);
+ if (sfp->next_cmd_len > 0) {
+ cmd_size = sfp->next_cmd_len;
+ sfp->next_cmd_len = 0; /* reset so only this write() effected */
+@@ -660,6 +662,7 @@ sg_write(struct file *filp, const char _
+ if ((opcode >= 0xc0) && old_hdr.twelve_byte)
+ cmd_size = 12;
+ }
++ mutex_unlock(&sfp->f_mutex);
+ SCSI_LOG_TIMEOUT(4, printk(
+ "sg_write: scsi opcode=0x%02x, cmd_size=%d\n", (int) opcode, cmd_size));
+ /* Determine buffer size. */
+@@ -758,7 +761,7 @@ sg_new_write(Sg_fd *sfp, struct file *fi
+ sg_remove_request(sfp, srp);
+ return -EINVAL; /* either MMAP_IO or DIRECT_IO (not both) */
+ }
+- if (sg_res_in_use(sfp)) {
++ if (sfp->res_in_use) {
+ sg_remove_request(sfp, srp);
+ return -EBUSY; /* reserve buffer already being used */
+ }
+@@ -933,7 +936,7 @@ sg_ioctl(struct file *filp, unsigned int
+ return result;
+ if (val) {
+ sfp->low_dma = 1;
+- if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) {
++ if ((0 == sfp->low_dma) && !sfp->res_in_use) {
+ val = (int) sfp->reserve.bufflen;
+ sg_remove_scat(&sfp->reserve);
+ sg_build_reserve(sfp, val);
+@@ -1008,12 +1011,18 @@ sg_ioctl(struct file *filp, unsigned int
+ return -EINVAL;
+ val = min_t(int, val,
+ max_sectors_bytes(sdp->device->request_queue));
++ mutex_lock(&sfp->f_mutex);
+ if (val != sfp->reserve.bufflen) {
+- if (sg_res_in_use(sfp) || sfp->mmap_called)
++ if (sfp->mmap_called ||
++ sfp->res_in_use) {
++ mutex_unlock(&sfp->f_mutex);
+ return -EBUSY;
++ }
++
+ sg_remove_scat(&sfp->reserve);
+ sg_build_reserve(sfp, val);
+ }
++ mutex_unlock(&sfp->f_mutex);
+ return 0;
+ case SG_GET_RESERVED_SIZE:
+ val = min_t(int, sfp->reserve.bufflen,
+@@ -1752,13 +1761,22 @@ sg_start_req(Sg_request *srp, unsigned c
+ md = &map_data;
+
+ if (md) {
+- if (!sg_res_in_use(sfp) && dxfer_len <= rsv_schp->bufflen)
++ mutex_lock(&sfp->f_mutex);
++ if (dxfer_len <= rsv_schp->bufflen &&
++ !sfp->res_in_use) {
++ sfp->res_in_use = 1;
+ sg_link_reserve(sfp, srp, dxfer_len);
+- else {
++ } else if ((hp->flags & SG_FLAG_MMAP_IO) && sfp->res_in_use) {
++ mutex_unlock(&sfp->f_mutex);
++ return -EBUSY;
++ } else {
+ res = sg_build_indirect(req_schp, sfp, dxfer_len);
+- if (res)
++ if (res) {
++ mutex_unlock(&sfp->f_mutex);
+ return res;
++ }
+ }
++ mutex_unlock(&sfp->f_mutex);
+
+ md->pages = req_schp->pages;
+ md->page_order = req_schp->page_order;
+@@ -2155,6 +2173,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
+ rwlock_init(&sfp->rq_list_lock);
+
+ kref_init(&sfp->f_ref);
++ mutex_init(&sfp->f_mutex);
+ sfp->timeout = SG_DEFAULT_TIMEOUT;
+ sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER;
+ sfp->force_packid = SG_DEF_FORCE_PACK_ID;
+@@ -2229,20 +2248,6 @@ sg_remove_sfp(struct kref *kref)
+ schedule_work(&sfp->ew.work);
+ }
+
+-static int
+-sg_res_in_use(Sg_fd * sfp)
+-{
+- const Sg_request *srp;
+- unsigned long iflags;
+-
+- read_lock_irqsave(&sfp->rq_list_lock, iflags);
+- for (srp = sfp->headrp; srp; srp = srp->nextrp)
+- if (srp->res_used)
+- break;
+- read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+- return srp ? 1 : 0;
+-}
+-
+ #ifdef CONFIG_SCSI_PROC_FS
+ static int
+ sg_idr_max_id(int id, void *p, void *data)
diff --git a/queue-3.16/scsi-sg-protect-against-races-between-mmap-and-sg_set_reserved_size.patch b/queue-3.16/scsi-sg-protect-against-races-between-mmap-and-sg_set_reserved_size.patch
new file mode 100644
index 00000000..7a4b01fd
--- /dev/null
+++ b/queue-3.16/scsi-sg-protect-against-races-between-mmap-and-sg_set_reserved_size.patch
@@ -0,0 +1,58 @@
+From: Todd Poynor <toddpoynor@google.com>
+Date: Tue, 15 Aug 2017 22:41:08 -0700
+Subject: scsi: sg: protect against races between mmap() and SG_SET_RESERVED_SIZE
+
+commit 6a8dadcca81fceff9976e8828cceb072873b7bd5 upstream.
+
+Take f_mutex around mmap() processing to protect against races with the
+SG_SET_RESERVED_SIZE ioctl. Ensure the reserve buffer length remains
+consistent during the mapping operation, and set the "mmap called" flag
+to prevent further changes to the reserved buffer size as an atomic
+operation with the mapping.
+
+[mkp: fixed whitespace]
+
+Signed-off-by: Todd Poynor <toddpoynor@google.com>
+Acked-by: Douglas Gilbert <dgilbert@interlog.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -1310,6 +1310,7 @@ sg_mmap(struct file *filp, struct vm_are
+ unsigned long req_sz, len, sa;
+ Sg_scatter_hold *rsv_schp;
+ int k, length;
++ int ret = 0;
+
+ if ((!filp) || (!vma) || (!(sfp = (Sg_fd *) filp->private_data)))
+ return -ENXIO;
+@@ -1319,8 +1320,11 @@ sg_mmap(struct file *filp, struct vm_are
+ if (vma->vm_pgoff)
+ return -EINVAL; /* want no offset */
+ rsv_schp = &sfp->reserve;
+- if (req_sz > rsv_schp->bufflen)
+- return -ENOMEM; /* cannot map more than reserved buffer */
++ mutex_lock(&sfp->f_mutex);
++ if (req_sz > rsv_schp->bufflen) {
++ ret = -ENOMEM; /* cannot map more than reserved buffer */
++ goto out;
++ }
+
+ sa = vma->vm_start;
+ length = 1 << (PAGE_SHIFT + rsv_schp->page_order);
+@@ -1334,7 +1338,9 @@ sg_mmap(struct file *filp, struct vm_are
+ vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
+ vma->vm_private_data = sfp;
+ vma->vm_ops = &sg_mmap_vm_ops;
+- return 0;
++out:
++ mutex_unlock(&sfp->f_mutex);
++ return ret;
+ }
+
+ static void
diff --git a/queue-3.16/scsi-sg-re-fix-off-by-one-in-sg_fill_request_table.patch b/queue-3.16/scsi-sg-re-fix-off-by-one-in-sg_fill_request_table.patch
new file mode 100644
index 00000000..c8dd90a2
--- /dev/null
+++ b/queue-3.16/scsi-sg-re-fix-off-by-one-in-sg_fill_request_table.patch
@@ -0,0 +1,35 @@
+From: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Date: Sun, 15 Oct 2017 18:16:33 +0100
+Subject: scsi: sg: Re-fix off by one in sg_fill_request_table()
+
+commit 587c3c9f286cee5c9cac38d28c8ae1875f4ec85b upstream.
+
+Commit 109bade9c625 ("scsi: sg: use standard lists for sg_requests")
+introduced an off-by-one error in sg_ioctl(), which was fixed by commit
+bd46fc406b30 ("scsi: sg: off by one in sg_ioctl()").
+
+Unfortunately commit 4759df905a47 ("scsi: sg: factor out
+sg_fill_request_table()") moved that code, and reintroduced the
+bug (perhaps due to a botched rebase). Fix it again.
+
+Fixes: 4759df905a47 ("scsi: sg: factor out sg_fill_request_table()")
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Acked-by: Douglas Gilbert <dgilbert@interlog.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -879,7 +879,7 @@ sg_fill_request_table(Sg_fd *sfp, sg_req
+
+ val = 0;
+ list_for_each_entry(srp, &sfp->rq_list, entry) {
+- if (val > SG_MAX_QUEUE)
++ if (val >= SG_MAX_QUEUE)
+ break;
+ rinfo[val].req_state = srp->done + 1;
+ rinfo[val].problem =
diff --git a/queue-3.16/scsi-sg-recheck-mmap_io-request-length-with-lock-held.patch b/queue-3.16/scsi-sg-recheck-mmap_io-request-length-with-lock-held.patch
new file mode 100644
index 00000000..d40b3a94
--- /dev/null
+++ b/queue-3.16/scsi-sg-recheck-mmap_io-request-length-with-lock-held.patch
@@ -0,0 +1,45 @@
+From: Todd Poynor <toddpoynor@google.com>
+Date: Tue, 15 Aug 2017 21:48:43 -0700
+Subject: scsi: sg: recheck MMAP_IO request length with lock held
+
+commit 8d26f491116feaa0b16de370b6a7ba40a40fa0b4 upstream.
+
+Commit 1bc0eb044615 ("scsi: sg: protect accesses to 'reserved' page
+array") adds needed concurrency protection for the "reserve" buffer.
+Some checks that are initially made outside the lock are replicated once
+the lock is taken to ensure the checks and resulting decisions are made
+using consistent state.
+
+The check that a request with flag SG_FLAG_MMAP_IO set fits in the
+reserve buffer also needs to be performed again under the lock to ensure
+the reserve buffer length compared against matches the value in effect
+when the request is linked to the reserve buffer. An -ENOMEM should be
+returned in this case, instead of switching over to an indirect buffer
+as for non-MMAP_IO requests.
+
+Signed-off-by: Todd Poynor <toddpoynor@google.com>
+Acked-by: Douglas Gilbert <dgilbert@interlog.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -1772,9 +1772,12 @@ sg_start_req(Sg_request *srp, unsigned c
+ !sfp->res_in_use) {
+ sfp->res_in_use = 1;
+ sg_link_reserve(sfp, srp, dxfer_len);
+- } else if ((hp->flags & SG_FLAG_MMAP_IO) && sfp->res_in_use) {
++ } else if (hp->flags & SG_FLAG_MMAP_IO) {
++ res = -EBUSY; /* sfp->res_in_use == 1 */
++ if (dxfer_len > rsv_schp->bufflen)
++ res = -ENOMEM;
+ mutex_unlock(&sfp->f_mutex);
+- return -EBUSY;
++ return res;
+ } else {
+ res = sg_build_indirect(req_schp, sfp, dxfer_len);
+ if (res) {
diff --git a/queue-3.16/scsi-sg-remove-save_scat_len.patch b/queue-3.16/scsi-sg-remove-save_scat_len.patch
new file mode 100644
index 00000000..892c70ee
--- /dev/null
+++ b/queue-3.16/scsi-sg-remove-save_scat_len.patch
@@ -0,0 +1,37 @@
+From: Hannes Reinecke <hare@suse.de>
+Date: Fri, 7 Apr 2017 09:34:13 +0200
+Subject: scsi: sg: remove 'save_scat_len'
+
+commit 136e57bf43dc4babbfb8783abbf707d483cacbe3 upstream.
+
+Unused.
+
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+Tested-by: Johannes Thumshirn <jthumshirn@suse.de>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -154,7 +154,6 @@ typedef struct sg_fd { /* holds the sta
+ int timeout; /* defaults to SG_DEFAULT_TIMEOUT */
+ int timeout_user; /* defaults to SG_DEFAULT_TIMEOUT_USER */
+ Sg_scatter_hold reserve; /* buffer held for this file descriptor */
+- unsigned save_scat_len; /* original length of trunc. scat. element */
+ Sg_request *headrp; /* head of request slist, NULL->empty */
+ struct fasync_struct *async_qp; /* used by asynchronous notification */
+ Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */
+@@ -2069,7 +2068,6 @@ sg_unlink_reserve(Sg_fd * sfp, Sg_reques
+ req_schp->pages = NULL;
+ req_schp->page_order = 0;
+ req_schp->sglist_len = 0;
+- sfp->save_scat_len = 0;
+ srp->res_used = 0;
+ /* Called without mutex lock to avoid deadlock */
+ sfp->res_in_use = 0;
diff --git a/queue-3.16/scsi-sg-reset-res_in_use-after-unlinking-reserved-array.patch b/queue-3.16/scsi-sg-reset-res_in_use-after-unlinking-reserved-array.patch
new file mode 100644
index 00000000..cecebf50
--- /dev/null
+++ b/queue-3.16/scsi-sg-reset-res_in_use-after-unlinking-reserved-array.patch
@@ -0,0 +1,35 @@
+From: Hannes Reinecke <hare@suse.de>
+Date: Mon, 24 Apr 2017 10:26:36 +0200
+Subject: scsi: sg: reset 'res_in_use' after unlinking reserved array
+
+commit e791ce27c3f6a1d3c746fd6a8f8e36c9540ec6f9 upstream.
+
+Once the reserved page array is unused we can reset the 'res_in_use'
+state; here we can do a lazy update without holding the mutex as we only
+need to check against concurrent access, not concurrent release.
+
+[mkp: checkpatch]
+
+Fixes: 1bc0eb044615 ("scsi: sg: protect accesses to 'reserved' page array")
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Cc: Todd Poynor <toddpoynor@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -2062,6 +2062,8 @@ sg_unlink_reserve(Sg_fd * sfp, Sg_reques
+ req_schp->sglist_len = 0;
+ sfp->save_scat_len = 0;
+ srp->res_used = 0;
++ /* Called without mutex lock to avoid deadlock */
++ sfp->res_in_use = 0;
+ }
+
+ static Sg_request *
diff --git a/queue-3.16/scsi-sg-use-standard-lists-for-sg_requests.patch b/queue-3.16/scsi-sg-use-standard-lists-for-sg_requests.patch
new file mode 100644
index 00000000..cafec049
--- /dev/null
+++ b/queue-3.16/scsi-sg-use-standard-lists-for-sg_requests.patch
@@ -0,0 +1,287 @@
+From: Hannes Reinecke <hare@suse.de>
+Date: Fri, 7 Apr 2017 09:34:16 +0200
+Subject: scsi: sg: use standard lists for sg_requests
+
+commit 109bade9c625c89bb5ea753aaa1a0a97e6fbb548 upstream.
+
+'Sg_request' is using a private list implementation; convert it to
+standard lists.
+
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+Tested-by: Johannes Thumshirn <jthumshirn@suse.de>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 147 +++++++++++++++++++---------------------------
+ 1 file changed, 61 insertions(+), 86 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -130,7 +130,7 @@ struct sg_device; /* forward declaratio
+ struct sg_fd;
+
+ typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */
+- struct sg_request *nextrp; /* NULL -> tail request (slist) */
++ struct list_head entry; /* list entry */
+ struct sg_fd *parentfp; /* NULL -> not in use */
+ Sg_scatter_hold data; /* hold buffer, perhaps scatter list */
+ sg_io_hdr_t header; /* scsi command+info, see <scsi/sg.h> */
+@@ -154,7 +154,7 @@ typedef struct sg_fd { /* holds the sta
+ int timeout; /* defaults to SG_DEFAULT_TIMEOUT */
+ int timeout_user; /* defaults to SG_DEFAULT_TIMEOUT_USER */
+ Sg_scatter_hold reserve; /* buffer held for this file descriptor */
+- Sg_request *headrp; /* head of request slist, NULL->empty */
++ struct list_head rq_list; /* head of request list */
+ struct fasync_struct *async_qp; /* used by asynchronous notification */
+ Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */
+ char low_dma; /* as in parent but possibly overridden to 1 */
+@@ -981,7 +981,7 @@ sg_ioctl(struct file *filp, unsigned int
+ if (!access_ok(VERIFY_WRITE, ip, sizeof (int)))
+ return -EFAULT;
+ read_lock_irqsave(&sfp->rq_list_lock, iflags);
+- for (srp = sfp->headrp; srp; srp = srp->nextrp) {
++ list_for_each_entry(srp, &sfp->rq_list, entry) {
+ if ((1 == srp->done) && (!srp->sg_io_owned)) {
+ read_unlock_irqrestore(&sfp->rq_list_lock,
+ iflags);
+@@ -994,7 +994,8 @@ sg_ioctl(struct file *filp, unsigned int
+ return 0;
+ case SG_GET_NUM_WAITING:
+ read_lock_irqsave(&sfp->rq_list_lock, iflags);
+- for (val = 0, srp = sfp->headrp; srp; srp = srp->nextrp) {
++ val = 0;
++ list_for_each_entry(srp, &sfp->rq_list, entry) {
+ if ((1 == srp->done) && (!srp->sg_io_owned))
+ ++val;
+ }
+@@ -1069,35 +1070,33 @@ sg_ioctl(struct file *filp, unsigned int
+ if (!rinfo)
+ return -ENOMEM;
+ read_lock_irqsave(&sfp->rq_list_lock, iflags);
+- for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE;
+- ++val, srp = srp ? srp->nextrp : srp) {
++ val = 0;
++ list_for_each_entry(srp, &sfp->rq_list, entry) {
++ if (val > SG_MAX_QUEUE)
++ break;
+ memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
+- if (srp) {
+- rinfo[val].req_state = srp->done + 1;
+- rinfo[val].problem =
+- srp->header.masked_status &
+- srp->header.host_status &
+- srp->header.driver_status;
+- if (srp->done)
+- rinfo[val].duration =
+- srp->header.duration;
+- else {
+- ms = jiffies_to_msecs(jiffies);
+- rinfo[val].duration =
+- (ms > srp->header.duration) ?
+- (ms - srp->header.duration) : 0;
+- }
+- rinfo[val].orphan = srp->orphan;
+- rinfo[val].sg_io_owned =
+- srp->sg_io_owned;
+- rinfo[val].pack_id =
+- srp->header.pack_id;
+- rinfo[val].usr_ptr =
+- srp->header.usr_ptr;
++ rinfo[val].req_state = srp->done + 1;
++ rinfo[val].problem =
++ srp->header.masked_status &
++ srp->header.host_status &
++ srp->header.driver_status;
++ if (srp->done)
++ rinfo[val].duration =
++ srp->header.duration;
++ else {
++ ms = jiffies_to_msecs(jiffies);
++ rinfo[val].duration =
++ (ms > srp->header.duration) ?
++ (ms - srp->header.duration) : 0;
+ }
++ rinfo[val].orphan = srp->orphan;
++ rinfo[val].sg_io_owned = srp->sg_io_owned;
++ rinfo[val].pack_id = srp->header.pack_id;
++ rinfo[val].usr_ptr = srp->header.usr_ptr;
++ val++;
+ }
+ read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+- result = __copy_to_user(p, rinfo,
++ result = __copy_to_user(p, rinfo,
+ SZ_SG_REQ_INFO * SG_MAX_QUEUE);
+ result = result ? -EFAULT : 0;
+ kfree(rinfo);
+@@ -1229,7 +1228,7 @@ sg_poll(struct file *filp, poll_table *
+ return POLLERR;
+ poll_wait(filp, &sfp->read_wait, wait);
+ read_lock_irqsave(&sfp->rq_list_lock, iflags);
+- for (srp = sfp->headrp; srp; srp = srp->nextrp) {
++ list_for_each_entry(srp, &sfp->rq_list, entry) {
+ /* if any read waiting, flag it */
+ if ((0 == res) && (1 == srp->done) && (!srp->sg_io_owned))
+ res = POLLIN | POLLRDNORM;
+@@ -2080,7 +2079,7 @@ sg_get_rq_mark(Sg_fd * sfp, int pack_id)
+ unsigned long iflags;
+
+ write_lock_irqsave(&sfp->rq_list_lock, iflags);
+- for (resp = sfp->headrp; resp; resp = resp->nextrp) {
++ list_for_each_entry(resp, &sfp->rq_list, entry) {
+ /* look for requests that are ready + not SG_IO owned */
+ if ((1 == resp->done) && (!resp->sg_io_owned) &&
+ ((-1 == pack_id) || (resp->header.pack_id == pack_id))) {
+@@ -2098,70 +2097,45 @@ sg_add_request(Sg_fd * sfp)
+ {
+ int k;
+ unsigned long iflags;
+- Sg_request *resp;
+ Sg_request *rp = sfp->req_arr;
+
+ write_lock_irqsave(&sfp->rq_list_lock, iflags);
+- resp = sfp->headrp;
+- if (!resp) {
+- memset(rp, 0, sizeof (Sg_request));
+- rp->parentfp = sfp;
+- resp = rp;
+- sfp->headrp = resp;
+- } else {
+- if (0 == sfp->cmd_q)
+- resp = NULL; /* command queuing disallowed */
+- else {
+- for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
+- if (!rp->parentfp)
+- break;
+- }
+- if (k < SG_MAX_QUEUE) {
+- memset(rp, 0, sizeof (Sg_request));
+- rp->parentfp = sfp;
+- while (resp->nextrp)
+- resp = resp->nextrp;
+- resp->nextrp = rp;
+- resp = rp;
+- } else
+- resp = NULL;
++ if (!list_empty(&sfp->rq_list)) {
++ if (!sfp->cmd_q)
++ goto out_unlock;
++
++ for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
++ if (!rp->parentfp)
++ break;
+ }
++ if (k >= SG_MAX_QUEUE)
++ goto out_unlock;
+ }
+- if (resp) {
+- resp->nextrp = NULL;
+- resp->header.duration = jiffies_to_msecs(jiffies);
+- }
++ memset(rp, 0, sizeof (Sg_request));
++ rp->parentfp = sfp;
++ rp->header.duration = jiffies_to_msecs(jiffies);
++ list_add_tail(&rp->entry, &sfp->rq_list);
+ write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+- return resp;
++ return rp;
++out_unlock:
++ write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
++ return NULL;
+ }
+
+ /* Return of 1 for found; 0 for not found */
+ static int
+ sg_remove_request(Sg_fd * sfp, Sg_request * srp)
+ {
+- Sg_request *prev_rp;
+- Sg_request *rp;
+ unsigned long iflags;
+ int res = 0;
+
+- if ((!sfp) || (!srp) || (!sfp->headrp))
++ if (!sfp || !srp || list_empty(&sfp->rq_list))
+ return res;
+ write_lock_irqsave(&sfp->rq_list_lock, iflags);
+- prev_rp = sfp->headrp;
+- if (srp == prev_rp) {
+- sfp->headrp = prev_rp->nextrp;
+- prev_rp->parentfp = NULL;
++ if (!list_empty(&srp->entry)) {
++ list_del(&srp->entry);
++ srp->parentfp = NULL;
+ res = 1;
+- } else {
+- while ((rp = prev_rp->nextrp)) {
+- if (srp == rp) {
+- prev_rp->nextrp = rp->nextrp;
+- rp->parentfp = NULL;
+- res = 1;
+- break;
+- }
+- prev_rp = rp;
+- }
+ }
+ write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+ return res;
+@@ -2180,7 +2154,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
+
+ init_waitqueue_head(&sfp->read_wait);
+ rwlock_init(&sfp->rq_list_lock);
+-
++ INIT_LIST_HEAD(&sfp->rq_list);
+ kref_init(&sfp->f_ref);
+ mutex_init(&sfp->f_mutex);
+ sfp->timeout = SG_DEFAULT_TIMEOUT;
+@@ -2218,10 +2192,13 @@ sg_remove_sfp_usercontext(struct work_st
+ {
+ struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work);
+ struct sg_device *sdp = sfp->parentdp;
++ Sg_request *srp;
+
+ /* Cleanup any responses which were never read(). */
+- while (sfp->headrp)
+- sg_finish_rem_req(sfp->headrp);
++ while (!list_empty(&sfp->rq_list)) {
++ srp = list_first_entry(&sfp->rq_list, Sg_request, entry);
++ sg_finish_rem_req(srp);
++ }
+
+ if (sfp->reserve.bufflen > 0) {
+ SCSI_LOG_TIMEOUT(6,
+@@ -2626,7 +2603,7 @@ static int sg_proc_seq_show_devstrs(stru
+ /* must be called while holding sg_index_lock */
+ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
+ {
+- int k, m, new_interface, blen, usg;
++ int k, new_interface, blen, usg;
+ Sg_request *srp;
+ Sg_fd *fp;
+ const sg_io_hdr_t *hp;
+@@ -2646,13 +2623,11 @@ static void sg_proc_debug_helper(struct
+ seq_printf(s, " cmd_q=%d f_packid=%d k_orphan=%d closed=0\n",
+ (int) fp->cmd_q, (int) fp->force_packid,
+ (int) fp->keep_orphan);
+- for (m = 0, srp = fp->headrp;
+- srp != NULL;
+- ++m, srp = srp->nextrp) {
++ list_for_each_entry(srp, &fp->rq_list, entry) {
+ hp = &srp->header;
+ new_interface = (hp->interface_id == '\0') ? 0 : 1;
+ if (srp->res_used) {
+- if (new_interface &&
++ if (new_interface &&
+ (SG_FLAG_MMAP_IO & hp->flags))
+ cp = " mmap>> ";
+ else
+@@ -2683,7 +2658,7 @@ static void sg_proc_debug_helper(struct
+ seq_printf(s, "ms sgat=%d op=0x%02x\n", usg,
+ (int) srp->data.cmd_opcode);
+ }
+- if (0 == m)
++ if (list_empty(&fp->rq_list))
+ seq_puts(s, " No requests active\n");
+ read_unlock(&fp->rq_list_lock);
+ }
diff --git a/queue-3.16/selinux-cleanup-error-reporting-in-selinux_nlmsg_perm.patch b/queue-3.16/selinux-cleanup-error-reporting-in-selinux_nlmsg_perm.patch
new file mode 100644
index 00000000..16b81928
--- /dev/null
+++ b/queue-3.16/selinux-cleanup-error-reporting-in-selinux_nlmsg_perm.patch
@@ -0,0 +1,38 @@
+From: Richard Guy Briggs <rgb@redhat.com>
+Date: Thu, 18 Sep 2014 20:50:17 -0400
+Subject: selinux: cleanup error reporting in selinux_nlmsg_perm()
+
+commit e173fb2646a832b424c80904c306b816760ce477 upstream.
+
+Convert audit_log() call to WARN_ONCE().
+
+Rename "type=" to nlmsg_type=" to avoid confusion with the audit record
+type.
+
+Added "protocol=" to help track down which protocol (NETLINK_AUDIT?) was used
+within the netlink protocol family.
+
+Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
+[Rewrote the patch subject line]
+Signed-off-by: Paul Moore <pmoore@redhat.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ security/selinux/hooks.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -4683,10 +4683,9 @@ static int selinux_nlmsg_perm(struct soc
+ err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
+ if (err) {
+ if (err == -EINVAL) {
+- audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
+- "SELinux: unrecognized netlink message"
+- " type=%hu for sclass=%hu\n",
+- nlh->nlmsg_type, sksec->sclass);
++ WARN_ONCE(1, "selinux_nlmsg_perm: unrecognized netlink message:"
++ " protocol=%hu nlmsg_type=%hu sclass=%hu\n",
++ sk->sk_protocol, nlh->nlmsg_type, sksec->sclass);
+ if (!selinux_enforcing || security_get_allow_unknown())
+ err = 0;
+ }
diff --git a/queue-3.16/selinux-convert-warn_once-to-printk-in-selinux_nlmsg_perm.patch b/queue-3.16/selinux-convert-warn_once-to-printk-in-selinux_nlmsg_perm.patch
new file mode 100644
index 00000000..93904e49
--- /dev/null
+++ b/queue-3.16/selinux-convert-warn_once-to-printk-in-selinux_nlmsg_perm.patch
@@ -0,0 +1,37 @@
+From: Richard Guy Briggs <rgb@redhat.com>
+Date: Wed, 12 Nov 2014 14:01:34 -0500
+Subject: selinux: convert WARN_ONCE() to printk() in selinux_nlmsg_perm()
+
+commit d950f84c1c6658faec2ecbf5b09f7e7191953394 upstream.
+
+Convert WARN_ONCE() to printk() in selinux_nlmsg_perm().
+
+After conversion from audit_log() in commit e173fb26, WARN_ONCE() was
+deemed too alarmist, so switch it to printk().
+
+Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
+[PM: Changed to printk(WARNING) so we catch all of the different
+ invalid netlink messages. In Richard's defense, he brought this
+ point up earlier, but I didn't understand his point at the time.]
+Signed-off-by: Paul Moore <pmoore@redhat.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ security/selinux/hooks.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -4683,9 +4683,10 @@ static int selinux_nlmsg_perm(struct soc
+ err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
+ if (err) {
+ if (err == -EINVAL) {
+- WARN_ONCE(1, "selinux_nlmsg_perm: unrecognized netlink message:"
+- " protocol=%hu nlmsg_type=%hu sclass=%hu\n",
+- sk->sk_protocol, nlh->nlmsg_type, sksec->sclass);
++ printk(KERN_WARNING
++ "SELinux: unrecognized netlink message:"
++ " protocol=%hu nlmsg_type=%hu sclass=%hu\n",
++ sk->sk_protocol, nlh->nlmsg_type, sksec->sclass);
+ if (!selinux_enforcing || security_get_allow_unknown())
+ err = 0;
+ }
diff --git a/queue-3.16/selinux-print-sclass-as-string-when-unrecognized-netlink-message-occurs.patch b/queue-3.16/selinux-print-sclass-as-string-when-unrecognized-netlink-message-occurs.patch
new file mode 100644
index 00000000..0150bdd9
--- /dev/null
+++ b/queue-3.16/selinux-print-sclass-as-string-when-unrecognized-netlink-message-occurs.patch
@@ -0,0 +1,32 @@
+From: Marek Milkovic <mmilkovi@redhat.com>
+Date: Thu, 4 Jun 2015 16:22:16 -0400
+Subject: selinux: Print 'sclass' as string when unrecognized netlink message occurs
+
+commit cded3fffbeab777e6ad2ec05d4a3b62c5caca0f3 upstream.
+
+This prints the 'sclass' field as string instead of index in unrecognized netlink message.
+The textual representation makes it easier to distinguish the right class.
+
+Signed-off-by: Marek Milkovic <mmilkovi@redhat.com>
+Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
+[PM: 80-char width fixes]
+Signed-off-by: Paul Moore <pmoore@redhat.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ security/selinux/hooks.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -4685,8 +4685,9 @@ static int selinux_nlmsg_perm(struct soc
+ if (err == -EINVAL) {
+ printk(KERN_WARNING
+ "SELinux: unrecognized netlink message:"
+- " protocol=%hu nlmsg_type=%hu sclass=%hu\n",
+- sk->sk_protocol, nlh->nlmsg_type, sksec->sclass);
++ " protocol=%hu nlmsg_type=%hu sclass=%s\n",
++ sk->sk_protocol, nlh->nlmsg_type,
++ secclass_map[sksec->sclass - 1].name);
+ if (!selinux_enforcing || security_get_allow_unknown())
+ err = 0;
+ }
diff --git a/queue-3.16/selinux-properly-handle-multiple-messages-in-selinux_netlink_send.patch b/queue-3.16/selinux-properly-handle-multiple-messages-in-selinux_netlink_send.patch
new file mode 100644
index 00000000..041d4bb7
--- /dev/null
+++ b/queue-3.16/selinux-properly-handle-multiple-messages-in-selinux_netlink_send.patch
@@ -0,0 +1,104 @@
+From: Paul Moore <paul@paul-moore.com>
+Date: Tue, 28 Apr 2020 09:59:02 -0400
+Subject: selinux: properly handle multiple messages in selinux_netlink_send()
+
+commit fb73974172ffaaf57a7c42f35424d9aece1a5af6 upstream.
+
+Fix the SELinux netlink_send hook to properly handle multiple netlink
+messages in a single sk_buff; each message is parsed and subject to
+SELinux access control. Prior to this patch, SELinux only inspected
+the first message in the sk_buff.
+
+Cc: stable@vger.kernel.org
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Reviewed-by: Stephen Smalley <stephen.smalley.work@gmail.com>
+Signed-off-by: Paul Moore <paul@paul-moore.com>
+[bwh: Backported to 3.16: adjust context]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -4669,39 +4669,59 @@ static int selinux_tun_dev_open(void *se
+
+ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
+ {
+- int err = 0;
+- u32 perm;
++ int rc = 0;
++ unsigned int msg_len;
++ unsigned int data_len = skb->len;
++ unsigned char *data = skb->data;
+ struct nlmsghdr *nlh;
+ struct sk_security_struct *sksec = sk->sk_security;
++ u16 sclass = sksec->sclass;
++ u32 perm;
+
+- if (skb->len < NLMSG_HDRLEN) {
+- err = -EINVAL;
+- goto out;
+- }
+- nlh = nlmsg_hdr(skb);
++ while (data_len >= nlmsg_total_size(0)) {
++ nlh = (struct nlmsghdr *)data;
+
+- err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
+- if (err) {
+- if (err == -EINVAL) {
++ /* NOTE: the nlmsg_len field isn't reliably set by some netlink
++ * users which means we can't reject skb's with bogus
++ * length fields; our solution is to follow what
++ * netlink_rcv_skb() does and simply skip processing at
++ * messages with length fields that are clearly junk
++ */
++ if (nlh->nlmsg_len < NLMSG_HDRLEN || nlh->nlmsg_len > data_len)
++ return 0;
++
++ rc = selinux_nlmsg_lookup(sclass, nlh->nlmsg_type, &perm);
++ if (rc == 0) {
++ rc = sock_has_perm(current, sk, perm);
++ if (rc)
++ return rc;
++ } else if (rc == -EINVAL) {
++ /* -EINVAL is a missing msg/perm mapping */
+ pr_warn_ratelimited("SELinux: unrecognized netlink"
+- " message: protocol=%hu nlmsg_type=%hu sclass=%s"
+- " pig=%d comm=%s\n",
+- sk->sk_protocol, nlh->nlmsg_type,
+- secclass_map[sksec->sclass - 1].name,
+- task_pid_nr(current), current->comm);
+- if (!selinux_enforcing || security_get_allow_unknown())
+- err = 0;
++ " message: protocol=%hu nlmsg_type=%hu sclass=%s"
++ " pid=%d comm=%s\n",
++ sk->sk_protocol, nlh->nlmsg_type,
++ secclass_map[sclass - 1].name,
++ task_pid_nr(current), current->comm);
++ if (selinux_enforcing && !security_get_allow_unknown())
++ return rc;
++ rc = 0;
++ } else if (rc == -ENOENT) {
++ /* -ENOENT is a missing socket/class mapping, ignore */
++ rc = 0;
++ } else {
++ return rc;
+ }
+
+- /* Ignore */
+- if (err == -ENOENT)
+- err = 0;
+- goto out;
++ /* move to the next message after applying netlink padding */
++ msg_len = NLMSG_ALIGN(nlh->nlmsg_len);
++ if (msg_len >= data_len)
++ return 0;
++ data_len -= msg_len;
++ data += msg_len;
+ }
+
+- err = sock_has_perm(current, sk, perm);
+-out:
+- return err;
++ return rc;
+ }
+
+ #ifdef CONFIG_NETFILTER
diff --git a/queue-3.16/selinux-rate-limit-netlink-message-warnings-in-selinux_nlmsg_perm.patch b/queue-3.16/selinux-rate-limit-netlink-message-warnings-in-selinux_nlmsg_perm.patch
new file mode 100644
index 00000000..84cc0ed5
--- /dev/null
+++ b/queue-3.16/selinux-rate-limit-netlink-message-warnings-in-selinux_nlmsg_perm.patch
@@ -0,0 +1,40 @@
+From: Vladis Dronov <vdronov@redhat.com>
+Date: Thu, 24 Dec 2015 11:09:41 -0500
+Subject: selinux: rate-limit netlink message warnings in selinux_nlmsg_perm()
+
+commit 76319946f321e30872dd72af7de867cb26e7a373 upstream.
+
+Any process is able to send netlink messages with invalid types.
+Make the warning rate-limited to prevent too much log spam.
+
+The warning is supposed to help to find misbehaving programs, so
+print the triggering command name and pid.
+
+Reported-by: Florian Weimer <fweimer@redhat.com>
+Signed-off-by: Vladis Dronov <vdronov@redhat.com>
+[PM: subject line tweak to make checkpatch.pl happy]
+Signed-off-by: Paul Moore <pmoore@redhat.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ security/selinux/hooks.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -4683,11 +4683,12 @@ static int selinux_nlmsg_perm(struct soc
+ err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
+ if (err) {
+ if (err == -EINVAL) {
+- printk(KERN_WARNING
+- "SELinux: unrecognized netlink message:"
+- " protocol=%hu nlmsg_type=%hu sclass=%s\n",
++ pr_warn_ratelimited("SELinux: unrecognized netlink"
++ " message: protocol=%hu nlmsg_type=%hu sclass=%s"
++ " pig=%d comm=%s\n",
+ sk->sk_protocol, nlh->nlmsg_type,
+- secclass_map[sksec->sclass - 1].name);
++ secclass_map[sksec->sclass - 1].name,
++ task_pid_nr(current), current->comm);
+ if (!selinux_enforcing || security_get_allow_unknown())
+ err = 0;
+ }
diff --git a/queue-3.16/series b/queue-3.16/series
index 4d83b479..445426c6 100644
--- a/queue-3.16/series
+++ b/queue-3.16/series
@@ -8,3 +8,46 @@ net-sysfs-fix-reference-count-leak-in-rx-netdev_queue_add_kobject.patch
net-sysfs-fix-netdev_queue_add_kobject-breakage.patch
net-sysfs-call-dev_hold-always-in-netdev_queue_add_kobject.patch
net-sysfs-call-dev_hold-always-in-rx_queue_add_kobject.patch
+selinux-cleanup-error-reporting-in-selinux_nlmsg_perm.patch
+selinux-convert-warn_once-to-printk-in-selinux_nlmsg_perm.patch
+selinux-print-sclass-as-string-when-unrecognized-netlink-message-occurs.patch
+selinux-rate-limit-netlink-message-warnings-in-selinux_nlmsg_perm.patch
+selinux-properly-handle-multiple-messages-in-selinux_netlink_send.patch
+drivers-usb-core-don-t-disable-irqs-in-usb_sg_wait-during-urb-submit.patch
+drivers-usb-core-minimize-irq-disabling-in-usb_sg_cancel.patch
+usb-core-fix-free-while-in-use-bug-in-the-usb-s-glibrary.patch
+scsi-mptfusion-add-bounds-check-in-mptctl_hp_targetinfo.patch
+scsi-mptfusion-fix-double-fetch-bug-in-ioctl.patch
+mwifiex-fix-possible-buffer-overflows-in-mwifiex_cmd_append_vsie_tlv.patch
+mwifiex-fix-possible-buffer-overflows-in-mwifiex_ret_wmm_get_status.patch
+sg-o_excl-and-other-lock-handling.patch
+sg-prevent-integer-overflow-when-converting-from-sectors-to-bytes.patch
+scsi-sg-change-next_cmd_len-handling-to-mirror-upstream.patch
+scsi-sg-protect-accesses-to-reserved-page-array.patch
+scsi-sg-reset-res_in_use-after-unlinking-reserved-array.patch
+scsi-sg-protect-against-races-between-mmap-and-sg_set_reserved_size.patch
+scsi-sg-recheck-mmap_io-request-length-with-lock-held.patch
+scsi-sg-remove-save_scat_len.patch
+scsi-sg-use-standard-lists-for-sg_requests.patch
+scsi-sg-off-by-one-in-sg_ioctl.patch
+scsi-sg-factor-out-sg_fill_request_table.patch
+scsi-sg-fixup-infoleak-when-using-sg_get_request_table.patch
+scsi-sg-re-fix-off-by-one-in-sg_fill_request_table.patch
+scsi-sg-disable-set_force_low_dma.patch
+scsi-sg-check-for-valid-direction-before-starting-the-request.patch
+scsi-sg-close-race-condition-in-sg_remove_sfp_usercontext.patch
+scsi-sg-fix-sg_dxfer_from_dev-transfers.patch
+scsi-sg-fix-static-checker-warning-in-sg_is_valid_dxfer.patch
+scsi-sg-only-check-for-dxfer_len-greater-than-256m.patch
+scsi-sg-don-t-return-bogus-sg_requests.patch
+scsi-sg-fix-minor-memory-leak-in-error-path.patch
+scsi-sg-add-sg_remove_request-in-sg_common_write.patch
+scsi-sg-add-sg_remove_request-in-sg_write.patch
+signal-extend-exec_id-to-64bits.patch
+usb-gadget-fix-illegal-array-access-in-binding-with-udc.patch
+ext4-make-checks-for-metadata_csum-feature-safer.patch
+ext4-protect-journal-inode-s-blocks-using-block_validity.patch
+ext4-unsigned-int-compared-against-zero.patch
+ext4-fix-block-validity-checks-for-journal-inodes-using-indirect-blocks.patch
+ext4-don-t-perform-block-validity-checks-on-the-journal-inode.patch
+ext4-add-cond_resched-to-ext4_protect_reserved_inode.patch
diff --git a/queue-3.16/sg-o_excl-and-other-lock-handling.patch b/queue-3.16/sg-o_excl-and-other-lock-handling.patch
new file mode 100644
index 00000000..e8442303
--- /dev/null
+++ b/queue-3.16/sg-o_excl-and-other-lock-handling.patch
@@ -0,0 +1,920 @@
+From: Douglas Gilbert <dgilbert@interlog.com>
+Date: Wed, 25 Jun 2014 14:08:03 +0200
+Subject: sg: O_EXCL and other lock handling
+
+commit cc833acbee9db5ca8c6162b015b4c93863c6f821 upstream.
+
+This addresses a problem reported by Vaughan Cao concerning
+the correctness of the O_EXCL logic in the sg driver. POSIX
+doesn't defined O_EXCL semantics on devices but "allow only
+one open file descriptor at a time per sg device" is a rough
+definition. The sg driver's semantics have been to wait
+on an open() when O_NONBLOCK is not given and there are
+O_EXCL headwinds. Nasty things can happen during that wait
+such as the device being detached (removed). So multiple
+locks are reworked in this patch making it large and hard
+to break down into digestible bits.
+
+This patch is against Linus's current git repository which
+doesn't include any sg patches sent in the last few weeks.
+Hence this patch touches as little as possible that it
+doesn't need to and strips out most SCSI_LOG_TIMEOUT()
+changes in v3 because Hannes said he was going to rework all
+that stuff.
+
+The sg3_utils package has several test programs written to
+test this patch. See examples/sg_tst_excl*.cpp .
+
+Not all the locks and flags in sg have been re-worked in
+this patch, notably sg_request::done . That can wait for
+a follow-up patch if this one meets with approval.
+
+Signed-off-by: Douglas Gilbert <dgilbert@interlog.com>
+Reviewed-by: Hannes Reinecke <hare@suse.de>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 424 +++++++++++++++++++++++++---------------------
+ 1 file changed, 230 insertions(+), 194 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -51,6 +51,7 @@ static int sg_version_num = 30534; /* 2
+ #include <linux/delay.h>
+ #include <linux/blktrace_api.h>
+ #include <linux/mutex.h>
++#include <linux/atomic.h>
+ #include <linux/ratelimit.h>
+ #include <linux/cred.h> /* for sg_check_file_access() */
+
+@@ -103,18 +104,16 @@ static int scatter_elem_sz_prev = SG_SCA
+
+ #define SG_SECTOR_SZ 512
+
+-static int sg_add(struct device *, struct class_interface *);
+-static void sg_remove(struct device *, struct class_interface *);
+-
+-static DEFINE_SPINLOCK(sg_open_exclusive_lock);
++static int sg_add_device(struct device *, struct class_interface *);
++static void sg_remove_device(struct device *, struct class_interface *);
+
+ static DEFINE_IDR(sg_index_idr);
+ static DEFINE_RWLOCK(sg_index_lock); /* Also used to lock
+ file descriptor list for device */
+
+ static struct class_interface sg_interface = {
+- .add_dev = sg_add,
+- .remove_dev = sg_remove,
++ .add_dev = sg_add_device,
++ .remove_dev = sg_remove_device,
+ };
+
+ typedef struct sg_scatter_hold { /* holding area for scsi scatter gather info */
+@@ -147,8 +146,7 @@ typedef struct sg_request { /* SG_MAX_QU
+ } Sg_request;
+
+ typedef struct sg_fd { /* holds the state of a file descriptor */
+- /* sfd_siblings is protected by sg_index_lock */
+- struct list_head sfd_siblings;
++ struct list_head sfd_siblings; /* protected by device's sfd_lock */
+ struct sg_device *parentdp; /* owning device */
+ wait_queue_head_t read_wait; /* queue read until command done */
+ rwlock_t rq_list_lock; /* protect access to list in req_arr */
+@@ -171,14 +169,15 @@ typedef struct sg_fd { /* holds the sta
+
+ typedef struct sg_device { /* holds the state of each scsi generic device */
+ struct scsi_device *device;
+- wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */
++ wait_queue_head_t open_wait; /* queue open() when O_EXCL present */
++ struct mutex open_rel_lock; /* held when in open() or release() */
+ int sg_tablesize; /* adapter's max scatter-gather table size */
+ u32 index; /* device index number */
+- /* sfds is protected by sg_index_lock */
+ struct list_head sfds;
+- volatile char detached; /* 0->attached, 1->detached pending removal */
+- /* exclude protected by sg_open_exclusive_lock */
+- char exclude; /* opened for exclusive access */
++ rwlock_t sfd_lock; /* protect access to sfd list */
++ atomic_t detaching; /* 0->device usable, 1->device detaching */
++ bool exclude; /* 1->open(O_EXCL) succeeded and is active */
++ int open_cnt; /* count of opens (perhaps < num(sfds) ) */
+ char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
+ struct gendisk *disk;
+ struct cdev * cdev; /* char_dev [sysfs: /sys/cdev/major/sg<n>] */
+@@ -209,7 +208,7 @@ static Sg_request *sg_add_request(Sg_fd
+ static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
+ static int sg_res_in_use(Sg_fd * sfp);
+ static Sg_device *sg_get_dev(int dev);
+-static void sg_put_dev(Sg_device *sdp);
++static void sg_device_destroy(struct kref *kref);
+
+ #define SZ_SG_HEADER sizeof(struct sg_header)
+ #define SZ_SG_IO_HDR sizeof(sg_io_hdr_t)
+@@ -253,38 +252,43 @@ static int sg_allow_access(struct file *
+ return blk_verify_command(cmd, filp->f_mode & FMODE_WRITE);
+ }
+
+-static int get_exclude(Sg_device *sdp)
+-{
+- unsigned long flags;
+- int ret;
+-
+- spin_lock_irqsave(&sg_open_exclusive_lock, flags);
+- ret = sdp->exclude;
+- spin_unlock_irqrestore(&sg_open_exclusive_lock, flags);
+- return ret;
+-}
+-
+-static int set_exclude(Sg_device *sdp, char val)
++static int
++open_wait(Sg_device *sdp, int flags)
+ {
+- unsigned long flags;
+-
+- spin_lock_irqsave(&sg_open_exclusive_lock, flags);
+- sdp->exclude = val;
+- spin_unlock_irqrestore(&sg_open_exclusive_lock, flags);
+- return val;
+-}
++ int retval = 0;
+
+-static int sfds_list_empty(Sg_device *sdp)
+-{
+- unsigned long flags;
+- int ret;
++ if (flags & O_EXCL) {
++ while (sdp->open_cnt > 0) {
++ mutex_unlock(&sdp->open_rel_lock);
++ retval = wait_event_interruptible(sdp->open_wait,
++ (atomic_read(&sdp->detaching) ||
++ !sdp->open_cnt));
++ mutex_lock(&sdp->open_rel_lock);
++
++ if (retval) /* -ERESTARTSYS */
++ return retval;
++ if (atomic_read(&sdp->detaching))
++ return -ENODEV;
++ }
++ } else {
++ while (sdp->exclude) {
++ mutex_unlock(&sdp->open_rel_lock);
++ retval = wait_event_interruptible(sdp->open_wait,
++ (atomic_read(&sdp->detaching) ||
++ !sdp->exclude));
++ mutex_lock(&sdp->open_rel_lock);
++
++ if (retval) /* -ERESTARTSYS */
++ return retval;
++ if (atomic_read(&sdp->detaching))
++ return -ENODEV;
++ }
++ }
+
+- read_lock_irqsave(&sg_index_lock, flags);
+- ret = list_empty(&sdp->sfds);
+- read_unlock_irqrestore(&sg_index_lock, flags);
+- return ret;
++ return retval;
+ }
+
++/* Returns 0 on success, else a negated errno value */
+ static int
+ sg_open(struct inode *inode, struct file *filp)
+ {
+@@ -293,17 +297,15 @@ sg_open(struct inode *inode, struct file
+ struct request_queue *q;
+ Sg_device *sdp;
+ Sg_fd *sfp;
+- int res;
+ int retval;
+
+ nonseekable_open(inode, filp);
+ SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags));
++ if ((flags & O_EXCL) && (O_RDONLY == (flags & O_ACCMODE)))
++ return -EPERM; /* Can't lock it with read only access */
+ sdp = sg_get_dev(dev);
+- if (IS_ERR(sdp)) {
+- retval = PTR_ERR(sdp);
+- sdp = NULL;
+- goto sg_put;
+- }
++ if (IS_ERR(sdp))
++ return PTR_ERR(sdp);
+
+ /* This driver's module count bumped by fops_get in <linux/fs.h> */
+ /* Prevent the device driver from vanishing while we sleep */
+@@ -315,6 +317,9 @@ sg_open(struct inode *inode, struct file
+ if (retval)
+ goto sdp_put;
+
++ /* scsi_block_when_processing_errors() may block so bypass
++ * check if O_NONBLOCK. Permits SCSI commands to be issued
++ * during error recovery. Tread carefully. */
+ if (!((flags & O_NONBLOCK) ||
+ scsi_block_when_processing_errors(sdp->device))) {
+ retval = -ENXIO;
+@@ -322,65 +327,65 @@ sg_open(struct inode *inode, struct file
+ goto error_out;
+ }
+
+- if (flags & O_EXCL) {
+- if (O_RDONLY == (flags & O_ACCMODE)) {
+- retval = -EPERM; /* Can't lock it with read only access */
+- goto error_out;
+- }
+- if (!sfds_list_empty(sdp) && (flags & O_NONBLOCK)) {
+- retval = -EBUSY;
+- goto error_out;
+- }
+- res = wait_event_interruptible(sdp->o_excl_wait,
+- ((!sfds_list_empty(sdp) || get_exclude(sdp)) ? 0 : set_exclude(sdp, 1)));
+- if (res) {
+- retval = res; /* -ERESTARTSYS because signal hit process */
+- goto error_out;
+- }
+- } else if (get_exclude(sdp)) { /* some other fd has an exclusive lock on dev */
+- if (flags & O_NONBLOCK) {
+- retval = -EBUSY;
+- goto error_out;
+- }
+- res = wait_event_interruptible(sdp->o_excl_wait, !get_exclude(sdp));
+- if (res) {
+- retval = res; /* -ERESTARTSYS because signal hit process */
+- goto error_out;
++ mutex_lock(&sdp->open_rel_lock);
++ if (flags & O_NONBLOCK) {
++ if (flags & O_EXCL) {
++ if (sdp->open_cnt > 0) {
++ retval = -EBUSY;
++ goto error_mutex_locked;
++ }
++ } else {
++ if (sdp->exclude) {
++ retval = -EBUSY;
++ goto error_mutex_locked;
++ }
+ }
++ } else {
++ retval = open_wait(sdp, flags);
++ if (retval) /* -ERESTARTSYS or -ENODEV */
++ goto error_mutex_locked;
+ }
+- if (sdp->detached) {
+- retval = -ENODEV;
+- goto error_out;
+- }
+- if (sfds_list_empty(sdp)) { /* no existing opens on this device */
++
++ /* N.B. at this point we are holding the open_rel_lock */
++ if (flags & O_EXCL)
++ sdp->exclude = true;
++
++ if (sdp->open_cnt < 1) { /* no existing opens */
+ sdp->sgdebug = 0;
+ q = sdp->device->request_queue;
+ sdp->sg_tablesize = queue_max_segments(q);
+ }
+- if ((sfp = sg_add_sfp(sdp, dev)))
+- filp->private_data = sfp;
+- else {
+- if (flags & O_EXCL) {
+- set_exclude(sdp, 0); /* undo if error */
+- wake_up_interruptible(&sdp->o_excl_wait);
+- }
+- retval = -ENOMEM;
+- goto error_out;
++ sfp = sg_add_sfp(sdp, dev);
++ if (IS_ERR(sfp)) {
++ retval = PTR_ERR(sfp);
++ goto out_undo;
+ }
++
++ filp->private_data = sfp;
++ sdp->open_cnt++;
++ mutex_unlock(&sdp->open_rel_lock);
++
+ retval = 0;
+-error_out:
+- if (retval) {
+- scsi_autopm_put_device(sdp->device);
+-sdp_put:
+- scsi_device_put(sdp->device);
+- }
+ sg_put:
+- if (sdp)
+- sg_put_dev(sdp);
++ kref_put(&sdp->d_ref, sg_device_destroy);
+ return retval;
++
++out_undo:
++ if (flags & O_EXCL) {
++ sdp->exclude = false; /* undo if error */
++ wake_up_interruptible(&sdp->open_wait);
++ }
++error_mutex_locked:
++ mutex_unlock(&sdp->open_rel_lock);
++error_out:
++ scsi_autopm_put_device(sdp->device);
++sdp_put:
++ scsi_device_put(sdp->device);
++ goto sg_put;
+ }
+
+-/* Following function was formerly called 'sg_close' */
++/* Release resources associated with a successful sg_open()
++ * Returns 0 on success, else a negated errno value */
+ static int
+ sg_release(struct inode *inode, struct file *filp)
+ {
+@@ -391,11 +396,20 @@ sg_release(struct inode *inode, struct f
+ return -ENXIO;
+ SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name));
+
+- set_exclude(sdp, 0);
+- wake_up_interruptible(&sdp->o_excl_wait);
+-
++ mutex_lock(&sdp->open_rel_lock);
+ scsi_autopm_put_device(sdp->device);
+ kref_put(&sfp->f_ref, sg_remove_sfp);
++ sdp->open_cnt--;
++
++ /* possibly many open()s waiting on exlude clearing, start many;
++ * only open(O_EXCL)s wait on 0==open_cnt so only start one */
++ if (sdp->exclude) {
++ sdp->exclude = false;
++ wake_up_interruptible_all(&sdp->open_wait);
++ } else if (0 == sdp->open_cnt) {
++ wake_up_interruptible(&sdp->open_wait);
++ }
++ mutex_unlock(&sdp->open_rel_lock);
+ return 0;
+ }
+
+@@ -455,7 +469,7 @@ sg_read(struct file *filp, char __user *
+ }
+ srp = sg_get_rq_mark(sfp, req_pack_id);
+ if (!srp) { /* now wait on packet to arrive */
+- if (sdp->detached) {
++ if (atomic_read(&sdp->detaching)) {
+ retval = -ENODEV;
+ goto free_old_hdr;
+ }
+@@ -464,9 +478,9 @@ sg_read(struct file *filp, char __user *
+ goto free_old_hdr;
+ }
+ retval = wait_event_interruptible(sfp->read_wait,
+- (sdp->detached ||
++ (atomic_read(&sdp->detaching) ||
+ (srp = sg_get_rq_mark(sfp, req_pack_id))));
+- if (sdp->detached) {
++ if (atomic_read(&sdp->detaching)) {
+ retval = -ENODEV;
+ goto free_old_hdr;
+ }
+@@ -613,7 +627,7 @@ sg_write(struct file *filp, const char _
+ return -ENXIO;
+ SCSI_LOG_TIMEOUT(3, printk("sg_write: %s, count=%d\n",
+ sdp->disk->disk_name, (int) count));
+- if (sdp->detached)
++ if (atomic_read(&sdp->detaching))
+ return -ENODEV;
+ if (!((filp->f_flags & O_NONBLOCK) ||
+ scsi_block_when_processing_errors(sdp->device)))
+@@ -806,7 +820,7 @@ sg_common_write(Sg_fd * sfp, Sg_request
+ sg_finish_rem_req(srp);
+ return k; /* probably out of space --> ENOMEM */
+ }
+- if (sdp->detached) {
++ if (atomic_read(&sdp->detaching)) {
+ if (srp->bio) {
+ blk_end_request_all(srp->rq, -EIO);
+ srp->rq = NULL;
+@@ -871,7 +885,7 @@ sg_ioctl(struct file *filp, unsigned int
+
+ switch (cmd_in) {
+ case SG_IO:
+- if (sdp->detached)
++ if (atomic_read(&sdp->detaching))
+ return -ENODEV;
+ if (!scsi_block_when_processing_errors(sdp->device))
+ return -ENXIO;
+@@ -882,8 +896,8 @@ sg_ioctl(struct file *filp, unsigned int
+ if (result < 0)
+ return result;
+ result = wait_event_interruptible(sfp->read_wait,
+- (srp_done(sfp, srp) || sdp->detached));
+- if (sdp->detached)
++ (srp_done(sfp, srp) || atomic_read(&sdp->detaching)));
++ if (atomic_read(&sdp->detaching))
+ return -ENODEV;
+ write_lock_irq(&sfp->rq_list_lock);
+ if (srp->done) {
+@@ -922,7 +936,7 @@ sg_ioctl(struct file *filp, unsigned int
+ sg_build_reserve(sfp, val);
+ }
+ } else {
+- if (sdp->detached)
++ if (atomic_read(&sdp->detaching))
+ return -ENODEV;
+ sfp->low_dma = sdp->device->host->unchecked_isa_dma;
+ }
+@@ -935,7 +949,7 @@ sg_ioctl(struct file *filp, unsigned int
+ else {
+ sg_scsi_id_t __user *sg_idp = p;
+
+- if (sdp->detached)
++ if (atomic_read(&sdp->detaching))
+ return -ENODEV;
+ __put_user((int) sdp->device->host->host_no,
+ &sg_idp->host_no);
+@@ -1077,11 +1091,11 @@ sg_ioctl(struct file *filp, unsigned int
+ return result;
+ }
+ case SG_EMULATED_HOST:
+- if (sdp->detached)
++ if (atomic_read(&sdp->detaching))
+ return -ENODEV;
+ return put_user(sdp->device->host->hostt->emulated, ip);
+ case SG_SCSI_RESET:
+- if (sdp->detached)
++ if (atomic_read(&sdp->detaching))
+ return -ENODEV;
+ if (filp->f_flags & O_NONBLOCK) {
+ if (scsi_host_in_recovery(sdp->device->host))
+@@ -1114,7 +1128,7 @@ sg_ioctl(struct file *filp, unsigned int
+ return (scsi_reset_provider(sdp->device, val) ==
+ SUCCESS) ? 0 : -EIO;
+ case SCSI_IOCTL_SEND_COMMAND:
+- if (sdp->detached)
++ if (atomic_read(&sdp->detaching))
+ return -ENODEV;
+ if (read_only) {
+ unsigned char opcode = WRITE_6;
+@@ -1136,7 +1150,7 @@ sg_ioctl(struct file *filp, unsigned int
+ case SCSI_IOCTL_GET_BUS_NUMBER:
+ case SCSI_IOCTL_PROBE_HOST:
+ case SG_GET_TRANSFORM:
+- if (sdp->detached)
++ if (atomic_read(&sdp->detaching))
+ return -ENODEV;
+ return scsi_ioctl(sdp->device, cmd_in, p);
+ case BLKSECTGET:
+@@ -1210,7 +1224,7 @@ sg_poll(struct file *filp, poll_table *
+ }
+ read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+
+- if (sdp->detached)
++ if (atomic_read(&sdp->detaching))
+ res |= POLLHUP;
+ else if (!sfp->cmd_q) {
+ if (0 == count)
+@@ -1309,7 +1323,8 @@ sg_mmap(struct file *filp, struct vm_are
+ return 0;
+ }
+
+-static void sg_rq_end_io_usercontext(struct work_struct *work)
++static void
++sg_rq_end_io_usercontext(struct work_struct *work)
+ {
+ struct sg_request *srp = container_of(work, struct sg_request, ew.work);
+ struct sg_fd *sfp = srp->parentfp;
+@@ -1322,7 +1337,8 @@ static void sg_rq_end_io_usercontext(str
+ * This function is a "bottom half" handler that is called by the mid
+ * level when a command is completed (or has failed).
+ */
+-static void sg_rq_end_io(struct request *rq, int uptodate)
++static void
++sg_rq_end_io(struct request *rq, int uptodate)
+ {
+ struct sg_request *srp = rq->end_io_data;
+ Sg_device *sdp;
+@@ -1340,8 +1356,8 @@ static void sg_rq_end_io(struct request
+ return;
+
+ sdp = sfp->parentdp;
+- if (unlikely(sdp->detached))
+- printk(KERN_INFO "sg_rq_end_io: device detached\n");
++ if (unlikely(atomic_read(&sdp->detaching)))
++ pr_info("%s: device detaching\n", __func__);
+
+ sense = rq->sense;
+ result = rq->errors;
+@@ -1364,7 +1380,7 @@ static void sg_rq_end_io(struct request
+ if ((sdp->sgdebug > 0) &&
+ ((CHECK_CONDITION == srp->header.masked_status) ||
+ (COMMAND_TERMINATED == srp->header.masked_status)))
+- __scsi_print_sense("sg_cmd_done", sense,
++ __scsi_print_sense(__func__, sense,
+ SCSI_SENSE_BUFFERSIZE);
+
+ /* Following if statement is a patch supplied by Eric Youngdale */
+@@ -1423,7 +1439,8 @@ static struct class *sg_sysfs_class;
+
+ static int sg_sysfs_valid = 0;
+
+-static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
++static Sg_device *
++sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
+ {
+ struct request_queue *q = scsidp->request_queue;
+ Sg_device *sdp;
+@@ -1433,7 +1450,8 @@ static Sg_device *sg_alloc(struct gendis
+
+ sdp = kzalloc(sizeof(Sg_device), GFP_KERNEL);
+ if (!sdp) {
+- printk(KERN_WARNING "kmalloc Sg_device failure\n");
++ sdev_printk(KERN_WARNING, scsidp, "%s: kmalloc Sg_device "
++ "failure\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+@@ -1448,8 +1466,9 @@ static Sg_device *sg_alloc(struct gendis
+ scsidp->type, SG_MAX_DEVS - 1);
+ error = -ENODEV;
+ } else {
+- printk(KERN_WARNING
+- "idr allocation Sg_device failure: %d\n", error);
++ sdev_printk(KERN_WARNING, scsidp, "%s: idr "
++ "allocation Sg_device failure: %d\n",
++ __func__, error);
+ }
+ goto out_unlock;
+ }
+@@ -1460,8 +1479,11 @@ static Sg_device *sg_alloc(struct gendis
+ disk->first_minor = k;
+ sdp->disk = disk;
+ sdp->device = scsidp;
++ mutex_init(&sdp->open_rel_lock);
+ INIT_LIST_HEAD(&sdp->sfds);
+- init_waitqueue_head(&sdp->o_excl_wait);
++ init_waitqueue_head(&sdp->open_wait);
++ atomic_set(&sdp->detaching, 0);
++ rwlock_init(&sdp->sfd_lock);
+ sdp->sg_tablesize = queue_max_segments(q);
+ sdp->index = k;
+ kref_init(&sdp->d_ref);
+@@ -1479,7 +1501,7 @@ out_unlock:
+ }
+
+ static int
+-sg_add(struct device *cl_dev, struct class_interface *cl_intf)
++sg_add_device(struct device *cl_dev, struct class_interface *cl_intf)
+ {
+ struct scsi_device *scsidp = to_scsi_device(cl_dev->parent);
+ struct gendisk *disk;
+@@ -1490,7 +1512,7 @@ sg_add(struct device *cl_dev, struct cla
+
+ disk = alloc_disk(1);
+ if (!disk) {
+- printk(KERN_WARNING "alloc_disk failed\n");
++ pr_warn("%s: alloc_disk failed\n", __func__);
+ return -ENOMEM;
+ }
+ disk->major = SCSI_GENERIC_MAJOR;
+@@ -1498,7 +1520,7 @@ sg_add(struct device *cl_dev, struct cla
+ error = -ENOMEM;
+ cdev = cdev_alloc();
+ if (!cdev) {
+- printk(KERN_WARNING "cdev_alloc failed\n");
++ pr_warn("%s: cdev_alloc failed\n", __func__);
+ goto out;
+ }
+ cdev->owner = THIS_MODULE;
+@@ -1506,7 +1528,7 @@ sg_add(struct device *cl_dev, struct cla
+
+ sdp = sg_alloc(disk, scsidp);
+ if (IS_ERR(sdp)) {
+- printk(KERN_WARNING "sg_alloc failed\n");
++ pr_warn("%s: sg_alloc failed\n", __func__);
+ error = PTR_ERR(sdp);
+ goto out;
+ }
+@@ -1524,22 +1546,20 @@ sg_add(struct device *cl_dev, struct cla
+ sdp->index),
+ sdp, "%s", disk->disk_name);
+ if (IS_ERR(sg_class_member)) {
+- printk(KERN_ERR "sg_add: "
+- "device_create failed\n");
++ pr_err("%s: device_create failed\n", __func__);
+ error = PTR_ERR(sg_class_member);
+ goto cdev_add_err;
+ }
+ error = sysfs_create_link(&scsidp->sdev_gendev.kobj,
+ &sg_class_member->kobj, "generic");
+ if (error)
+- printk(KERN_ERR "sg_add: unable to make symlink "
+- "'generic' back to sg%d\n", sdp->index);
++ pr_err("%s: unable to make symlink 'generic' back "
++ "to sg%d\n", __func__, sdp->index);
+ } else
+- printk(KERN_WARNING "sg_add: sg_sys Invalid\n");
++ pr_warn("%s: sg_sys Invalid\n", __func__);
+
+- sdev_printk(KERN_NOTICE, scsidp,
+- "Attached scsi generic sg%d type %d\n", sdp->index,
+- scsidp->type);
++ sdev_printk(KERN_NOTICE, scsidp, "Attached scsi generic sg%d "
++ "type %d\n", sdp->index, scsidp->type);
+
+ dev_set_drvdata(cl_dev, sdp);
+
+@@ -1558,7 +1578,8 @@ out:
+ return error;
+ }
+
+-static void sg_device_destroy(struct kref *kref)
++static void
++sg_device_destroy(struct kref *kref)
+ {
+ struct sg_device *sdp = container_of(kref, struct sg_device, d_ref);
+ unsigned long flags;
+@@ -1580,33 +1601,39 @@ static void sg_device_destroy(struct kre
+ kfree(sdp);
+ }
+
+-static void sg_remove(struct device *cl_dev, struct class_interface *cl_intf)
++static void
++sg_remove_device(struct device *cl_dev, struct class_interface *cl_intf)
+ {
+ struct scsi_device *scsidp = to_scsi_device(cl_dev->parent);
+ Sg_device *sdp = dev_get_drvdata(cl_dev);
+ unsigned long iflags;
+ Sg_fd *sfp;
++ int val;
+
+- if (!sdp || sdp->detached)
++ if (!sdp)
+ return;
++ /* want sdp->detaching non-zero as soon as possible */
++ val = atomic_inc_return(&sdp->detaching);
++ if (val > 1)
++ return; /* only want to do following once per device */
+
+- SCSI_LOG_TIMEOUT(3, printk("sg_remove: %s\n", sdp->disk->disk_name));
++ SCSI_LOG_TIMEOUT(3, printk("%s: %s\n", __func__,
++ sdp->disk->disk_name));
+
+- /* Need a write lock to set sdp->detached. */
+- write_lock_irqsave(&sg_index_lock, iflags);
+- sdp->detached = 1;
++ read_lock_irqsave(&sdp->sfd_lock, iflags);
+ list_for_each_entry(sfp, &sdp->sfds, sfd_siblings) {
+- wake_up_interruptible(&sfp->read_wait);
++ wake_up_interruptible_all(&sfp->read_wait);
+ kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP);
+ }
+- write_unlock_irqrestore(&sg_index_lock, iflags);
++ wake_up_interruptible_all(&sdp->open_wait);
++ read_unlock_irqrestore(&sdp->sfd_lock, iflags);
+
+ sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic");
+ device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, sdp->index));
+ cdev_del(sdp->cdev);
+ sdp->cdev = NULL;
+
+- sg_put_dev(sdp);
++ kref_put(&sdp->d_ref, sg_device_destroy);
+ }
+
+ module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR);
+@@ -1676,7 +1703,8 @@ exit_sg(void)
+ idr_destroy(&sg_index_idr);
+ }
+
+-static int sg_start_req(Sg_request *srp, unsigned char *cmd)
++static int
++sg_start_req(Sg_request *srp, unsigned char *cmd)
+ {
+ int res;
+ struct request *rq;
+@@ -1778,7 +1806,8 @@ static int sg_start_req(Sg_request *srp,
+ return res;
+ }
+
+-static int sg_finish_rem_req(Sg_request * srp)
++static int
++sg_finish_rem_req(Sg_request *srp)
+ {
+ int ret = 0;
+
+@@ -2115,7 +2144,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
+
+ sfp = kzalloc(sizeof(*sfp), GFP_ATOMIC | __GFP_NOWARN);
+ if (!sfp)
+- return NULL;
++ return ERR_PTR(-ENOMEM);
+
+ init_waitqueue_head(&sfp->read_wait);
+ rwlock_init(&sfp->rq_list_lock);
+@@ -2129,9 +2158,13 @@ sg_add_sfp(Sg_device * sdp, int dev)
+ sfp->cmd_q = SG_DEF_COMMAND_Q;
+ sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
+ sfp->parentdp = sdp;
+- write_lock_irqsave(&sg_index_lock, iflags);
++ write_lock_irqsave(&sdp->sfd_lock, iflags);
++ if (atomic_read(&sdp->detaching)) {
++ write_unlock_irqrestore(&sdp->sfd_lock, iflags);
++ return ERR_PTR(-ENODEV);
++ }
+ list_add_tail(&sfp->sfd_siblings, &sdp->sfds);
+- write_unlock_irqrestore(&sg_index_lock, iflags);
++ write_unlock_irqrestore(&sdp->sfd_lock, iflags);
+ SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp));
+ if (unlikely(sg_big_buff != def_reserved_size))
+ sg_big_buff = def_reserved_size;
+@@ -2147,7 +2180,8 @@ sg_add_sfp(Sg_device * sdp, int dev)
+ return sfp;
+ }
+
+-static void sg_remove_sfp_usercontext(struct work_struct *work)
++static void
++sg_remove_sfp_usercontext(struct work_struct *work)
+ {
+ struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work);
+ struct sg_device *sdp = sfp->parentdp;
+@@ -2171,20 +2205,20 @@ static void sg_remove_sfp_usercontext(st
+ kfree(sfp);
+
+ scsi_device_put(sdp->device);
+- sg_put_dev(sdp);
++ kref_put(&sdp->d_ref, sg_device_destroy);
+ module_put(THIS_MODULE);
+ }
+
+-static void sg_remove_sfp(struct kref *kref)
++static void
++sg_remove_sfp(struct kref *kref)
+ {
+ struct sg_fd *sfp = container_of(kref, struct sg_fd, f_ref);
+ struct sg_device *sdp = sfp->parentdp;
+ unsigned long iflags;
+
+- write_lock_irqsave(&sg_index_lock, iflags);
++ write_lock_irqsave(&sdp->sfd_lock, iflags);
+ list_del(&sfp->sfd_siblings);
+- write_unlock_irqrestore(&sg_index_lock, iflags);
+- wake_up_interruptible(&sdp->o_excl_wait);
++ write_unlock_irqrestore(&sdp->sfd_lock, iflags);
+
+ INIT_WORK(&sfp->ew.work, sg_remove_sfp_usercontext);
+ schedule_work(&sfp->ew.work);
+@@ -2235,7 +2269,8 @@ static Sg_device *sg_lookup_dev(int dev)
+ return idr_find(&sg_index_idr, dev);
+ }
+
+-static Sg_device *sg_get_dev(int dev)
++static Sg_device *
++sg_get_dev(int dev)
+ {
+ struct sg_device *sdp;
+ unsigned long flags;
+@@ -2244,8 +2279,8 @@ static Sg_device *sg_get_dev(int dev)
+ sdp = sg_lookup_dev(dev);
+ if (!sdp)
+ sdp = ERR_PTR(-ENXIO);
+- else if (sdp->detached) {
+- /* If sdp->detached, then the refcount may already be 0, in
++ else if (atomic_read(&sdp->detaching)) {
++ /* If sdp->detaching, then the refcount may already be 0, in
+ * which case it would be a bug to do kref_get().
+ */
+ sdp = ERR_PTR(-ENODEV);
+@@ -2256,11 +2291,6 @@ static Sg_device *sg_get_dev(int dev)
+ return sdp;
+ }
+
+-static void sg_put_dev(struct sg_device *sdp)
+-{
+- kref_put(&sdp->d_ref, sg_device_destroy);
+-}
+-
+ #ifdef CONFIG_SCSI_PROC_FS
+
+ static struct proc_dir_entry *sg_proc_sgp = NULL;
+@@ -2477,8 +2507,7 @@ static int sg_proc_single_open_version(s
+
+ static int sg_proc_seq_show_devhdr(struct seq_file *s, void *v)
+ {
+- seq_printf(s, "host\tchan\tid\tlun\ttype\topens\tqdepth\tbusy\t"
+- "online\n");
++ seq_puts(s, "host\tchan\tid\tlun\ttype\topens\tqdepth\tbusy\tonline\n");
+ return 0;
+ }
+
+@@ -2534,7 +2563,11 @@ static int sg_proc_seq_show_dev(struct s
+
+ read_lock_irqsave(&sg_index_lock, iflags);
+ sdp = it ? sg_lookup_dev(it->index) : NULL;
+- if (sdp && (scsidp = sdp->device) && (!sdp->detached))
++ if ((NULL == sdp) || (NULL == sdp->device) ||
++ (atomic_read(&sdp->detaching)))
++ seq_puts(s, "-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n");
++ else {
++ scsidp = sdp->device;
+ seq_printf(s, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
+ scsidp->host->host_no, scsidp->channel,
+ scsidp->id, scsidp->lun, (int) scsidp->type,
+@@ -2542,8 +2575,7 @@ static int sg_proc_seq_show_dev(struct s
+ (int) scsidp->queue_depth,
+ (int) scsidp->device_busy,
+ (int) scsi_device_online(scsidp));
+- else
+- seq_printf(s, "-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n");
++ }
+ read_unlock_irqrestore(&sg_index_lock, iflags);
+ return 0;
+ }
+@@ -2562,11 +2594,12 @@ static int sg_proc_seq_show_devstrs(stru
+
+ read_lock_irqsave(&sg_index_lock, iflags);
+ sdp = it ? sg_lookup_dev(it->index) : NULL;
+- if (sdp && (scsidp = sdp->device) && (!sdp->detached))
++ scsidp = sdp ? sdp->device : NULL;
++ if (sdp && scsidp && (!atomic_read(&sdp->detaching)))
+ seq_printf(s, "%8.8s\t%16.16s\t%4.4s\n",
+ scsidp->vendor, scsidp->model, scsidp->rev);
+ else
+- seq_printf(s, "<no active device>\n");
++ seq_puts(s, "<no active device>\n");
+ read_unlock_irqrestore(&sg_index_lock, iflags);
+ return 0;
+ }
+@@ -2611,12 +2644,12 @@ static void sg_proc_debug_helper(struct
+ else
+ cp = " ";
+ }
+- seq_printf(s, cp);
++ seq_puts(s, cp);
+ blen = srp->data.bufflen;
+ usg = srp->data.k_use_sg;
+- seq_printf(s, srp->done ?
+- ((1 == srp->done) ? "rcv:" : "fin:")
+- : "act:");
++ seq_puts(s, srp->done ?
++ ((1 == srp->done) ? "rcv:" : "fin:")
++ : "act:");
+ seq_printf(s, " id=%d blen=%d",
+ srp->header.pack_id, blen);
+ if (srp->done)
+@@ -2632,7 +2665,7 @@ static void sg_proc_debug_helper(struct
+ (int) srp->data.cmd_opcode);
+ }
+ if (0 == m)
+- seq_printf(s, " No requests active\n");
++ seq_puts(s, " No requests active\n");
+ read_unlock(&fp->rq_list_lock);
+ }
+ }
+@@ -2648,31 +2681,34 @@ static int sg_proc_seq_show_debug(struct
+ Sg_device *sdp;
+ unsigned long iflags;
+
+- if (it && (0 == it->index)) {
+- seq_printf(s, "max_active_device=%d(origin 1)\n",
+- (int)it->max);
+- seq_printf(s, " def_reserved_size=%d\n", sg_big_buff);
+- }
++ if (it && (0 == it->index))
++ seq_printf(s, "max_active_device=%d def_reserved_size=%d\n",
++ (int)it->max, sg_big_buff);
+
+ read_lock_irqsave(&sg_index_lock, iflags);
+ sdp = it ? sg_lookup_dev(it->index) : NULL;
+- if (sdp && !list_empty(&sdp->sfds)) {
+- struct scsi_device *scsidp = sdp->device;
+-
++ if (NULL == sdp)
++ goto skip;
++ read_lock(&sdp->sfd_lock);
++ if (!list_empty(&sdp->sfds)) {
+ seq_printf(s, " >>> device=%s ", sdp->disk->disk_name);
+- if (sdp->detached)
+- seq_printf(s, "detached pending close ");
+- else
+- seq_printf
+- (s, "scsi%d chan=%d id=%d lun=%d em=%d",
+- scsidp->host->host_no,
+- scsidp->channel, scsidp->id,
+- scsidp->lun,
+- scsidp->host->hostt->emulated);
+- seq_printf(s, " sg_tablesize=%d excl=%d\n",
+- sdp->sg_tablesize, get_exclude(sdp));
++ if (atomic_read(&sdp->detaching))
++ seq_puts(s, "detaching pending close ");
++ else if (sdp->device) {
++ struct scsi_device *scsidp = sdp->device;
++
++ seq_printf(s, "%d:%d:%d:%d em=%d",
++ scsidp->host->host_no,
++ scsidp->channel, scsidp->id,
++ scsidp->lun,
++ scsidp->host->hostt->emulated);
++ }
++ seq_printf(s, " sg_tablesize=%d excl=%d open_cnt=%d\n",
++ sdp->sg_tablesize, sdp->exclude, sdp->open_cnt);
+ sg_proc_debug_helper(s, sdp);
+ }
++ read_unlock(&sdp->sfd_lock);
++skip:
+ read_unlock_irqrestore(&sg_index_lock, iflags);
+ return 0;
+ }
diff --git a/queue-3.16/sg-prevent-integer-overflow-when-converting-from-sectors-to-bytes.patch b/queue-3.16/sg-prevent-integer-overflow-when-converting-from-sectors-to-bytes.patch
new file mode 100644
index 00000000..c109e224
--- /dev/null
+++ b/queue-3.16/sg-prevent-integer-overflow-when-converting-from-sectors-to-bytes.patch
@@ -0,0 +1,75 @@
+From: Akinobu Mita <akinobu.mita@gmail.com>
+Date: Mon, 2 Jun 2014 22:56:46 +0900
+Subject: sg: prevent integer overflow when converting from sectors to bytes
+
+commit 46f69e6a6bbbf3858617c8729e31895846c15a79 upstream.
+
+This prevents integer overflow when converting the request queue's
+max_sectors from sectors to bytes. However, this is a preparation for
+extending the data type of max_sectors in struct Scsi_Host and
+scsi_host_template. So, it is impossible to happen this integer
+overflow for now, because SCSI low-level drivers can not specify
+max_sectors greater than 0xffff due to the data type limitation.
+
+Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
+Acked by: Douglas Gilbert <dgilbert@interlog.com>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 17 +++++++++++++----
+ 1 file changed, 13 insertions(+), 4 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -865,6 +865,15 @@ static int srp_done(Sg_fd *sfp, Sg_reque
+ return ret;
+ }
+
++static int max_sectors_bytes(struct request_queue *q)
++{
++ unsigned int max_sectors = queue_max_sectors(q);
++
++ max_sectors = min_t(unsigned int, max_sectors, INT_MAX >> 9);
++
++ return max_sectors << 9;
++}
++
+ static long
+ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
+ {
+@@ -1004,7 +1013,7 @@ sg_ioctl(struct file *filp, unsigned int
+ if (val < 0)
+ return -EINVAL;
+ val = min_t(int, val,
+- queue_max_sectors(sdp->device->request_queue) * 512);
++ max_sectors_bytes(sdp->device->request_queue));
+ if (val != sfp->reserve.bufflen) {
+ if (sg_res_in_use(sfp) || sfp->mmap_called)
+ return -EBUSY;
+@@ -1014,7 +1023,7 @@ sg_ioctl(struct file *filp, unsigned int
+ return 0;
+ case SG_GET_RESERVED_SIZE:
+ val = min_t(int, sfp->reserve.bufflen,
+- queue_max_sectors(sdp->device->request_queue) * 512);
++ max_sectors_bytes(sdp->device->request_queue));
+ return put_user(val, ip);
+ case SG_SET_COMMAND_Q:
+ result = get_user(val, ip);
+@@ -1154,7 +1163,7 @@ sg_ioctl(struct file *filp, unsigned int
+ return -ENODEV;
+ return scsi_ioctl(sdp->device, cmd_in, p);
+ case BLKSECTGET:
+- return put_user(queue_max_sectors(sdp->device->request_queue) * 512,
++ return put_user(max_sectors_bytes(sdp->device->request_queue),
+ ip);
+ case BLKTRACESETUP:
+ return blk_trace_setup(sdp->device->request_queue,
+@@ -2170,7 +2179,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
+ sg_big_buff = def_reserved_size;
+
+ bufflen = min_t(int, sg_big_buff,
+- queue_max_sectors(sdp->device->request_queue) * 512);
++ max_sectors_bytes(sdp->device->request_queue));
+ sg_build_reserve(sfp, bufflen);
+ SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, k_use_sg=%d\n",
+ sfp->reserve.bufflen, sfp->reserve.k_use_sg));
diff --git a/queue-3.16/signal-extend-exec_id-to-64bits.patch b/queue-3.16/signal-extend-exec_id-to-64bits.patch
new file mode 100644
index 00000000..43577249
--- /dev/null
+++ b/queue-3.16/signal-extend-exec_id-to-64bits.patch
@@ -0,0 +1,81 @@
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Mon, 30 Mar 2020 19:01:04 -0500
+Subject: signal: Extend exec_id to 64bits
+
+commit d1e7fd6462ca9fc76650fbe6ca800e35b24267da upstream.
+
+Replace the 32bit exec_id with a 64bit exec_id to make it impossible
+to wrap the exec_id counter. With care an attacker can cause exec_id
+wrap and send arbitrary signals to a newly exec'd parent. This
+bypasses the signal sending checks if the parent changes their
+credentials during exec.
+
+The severity of this problem can been seen that in my limited testing
+of a 32bit exec_id it can take as little as 19s to exec 65536 times.
+Which means that it can take as little as 14 days to wrap a 32bit
+exec_id. Adam Zabrocki has succeeded wrapping the self_exe_id in 7
+days. Even my slower timing is in the uptime of a typical server.
+Which means self_exec_id is simply a speed bump today, and if exec
+gets noticably faster self_exec_id won't even be a speed bump.
+
+Extending self_exec_id to 64bits introduces a problem on 32bit
+architectures where reading self_exec_id is no longer atomic and can
+take two read instructions. Which means that is is possible to hit
+a window where the read value of exec_id does not match the written
+value. So with very lucky timing after this change this still
+remains expoiltable.
+
+I have updated the update of exec_id on exec to use WRITE_ONCE
+and the read of exec_id in do_notify_parent to use READ_ONCE
+to make it clear that there is no locking between these two
+locations.
+
+Link: https://lore.kernel.org/kernel-hardening/20200324215049.GA3710@pi3.com.pl
+Fixes: 2.3.23pre2
+Cc: stable@vger.kernel.org
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+[bwh: Backported to 3.16:
+ - Use ACCESS_ONCE()
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ fs/exec.c | 2 +-
+ include/linux/sched.h | 4 ++--
+ kernel/signal.c | 2 +-
+ 3 files changed, 4 insertions(+), 4 deletions(-)
+
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -1182,7 +1182,7 @@ void setup_new_exec(struct linux_binprm
+
+ /* An exec changes our domain. We are no longer part of the thread
+ group */
+- current->self_exec_id++;
++ ACCESS_ONCE(current->self_exec_id) = current->self_exec_id + 1;
+ flush_signal_handlers(current, 0);
+ }
+ EXPORT_SYMBOL(setup_new_exec);
+--- a/include/linux/sched.h
++++ b/include/linux/sched.h
+@@ -1427,8 +1427,8 @@ struct task_struct {
+ struct seccomp seccomp;
+
+ /* Thread group tracking */
+- u32 parent_exec_id;
+- u32 self_exec_id;
++ u64 parent_exec_id;
++ u64 self_exec_id;
+ /* Protection of (de-)allocation: mm, files, fs, tty, keyrings, mems_allowed,
+ * mempolicy */
+ spinlock_t alloc_lock;
+--- a/kernel/signal.c
++++ b/kernel/signal.c
+@@ -1679,7 +1679,7 @@ bool do_notify_parent(struct task_struct
+ * This is only possible if parent == real_parent.
+ * Check if it has changed security domain.
+ */
+- if (tsk->parent_exec_id != tsk->parent->self_exec_id)
++ if (tsk->parent_exec_id != ACCESS_ONCE(tsk->parent->self_exec_id))
+ sig = SIGCHLD;
+ }
+
diff --git a/queue-3.16/usb-core-fix-free-while-in-use-bug-in-the-usb-s-glibrary.patch b/queue-3.16/usb-core-fix-free-while-in-use-bug-in-the-usb-s-glibrary.patch
new file mode 100644
index 00000000..e1f081b2
--- /dev/null
+++ b/queue-3.16/usb-core-fix-free-while-in-use-bug-in-the-usb-s-glibrary.patch
@@ -0,0 +1,88 @@
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Sat, 28 Mar 2020 16:18:11 -0400
+Subject: USB: core: Fix free-while-in-use bug in the USB S-Glibrary
+
+commit 056ad39ee9253873522f6469c3364964a322912b upstream.
+
+FuzzUSB (a variant of syzkaller) found a free-while-still-in-use bug
+in the USB scatter-gather library:
+
+BUG: KASAN: use-after-free in atomic_read
+include/asm-generic/atomic-instrumented.h:26 [inline]
+BUG: KASAN: use-after-free in usb_hcd_unlink_urb+0x5f/0x170
+drivers/usb/core/hcd.c:1607
+Read of size 4 at addr ffff888065379610 by task kworker/u4:1/27
+
+CPU: 1 PID: 27 Comm: kworker/u4:1 Not tainted 5.5.11 #2
+Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
+1.10.2-1ubuntu1 04/01/2014
+Workqueue: scsi_tmf_2 scmd_eh_abort_handler
+Call Trace:
+ __dump_stack lib/dump_stack.c:77 [inline]
+ dump_stack+0xce/0x128 lib/dump_stack.c:118
+ print_address_description.constprop.4+0x21/0x3c0 mm/kasan/report.c:374
+ __kasan_report+0x153/0x1cb mm/kasan/report.c:506
+ kasan_report+0x12/0x20 mm/kasan/common.c:639
+ check_memory_region_inline mm/kasan/generic.c:185 [inline]
+ check_memory_region+0x152/0x1b0 mm/kasan/generic.c:192
+ __kasan_check_read+0x11/0x20 mm/kasan/common.c:95
+ atomic_read include/asm-generic/atomic-instrumented.h:26 [inline]
+ usb_hcd_unlink_urb+0x5f/0x170 drivers/usb/core/hcd.c:1607
+ usb_unlink_urb+0x72/0xb0 drivers/usb/core/urb.c:657
+ usb_sg_cancel+0x14e/0x290 drivers/usb/core/message.c:602
+ usb_stor_stop_transport+0x5e/0xa0 drivers/usb/storage/transport.c:937
+
+This bug occurs when cancellation of the S-G transfer races with
+transfer completion. When that happens, usb_sg_cancel() may continue
+to access the transfer's URBs after usb_sg_wait() has freed them.
+
+The bug is caused by the fact that usb_sg_cancel() does not take any
+sort of reference to the transfer, and so there is nothing to prevent
+the URBs from being deallocated while the routine is trying to use
+them. The fix is to take such a reference by incrementing the
+transfer's io->count field while the cancellation is in progres and
+decrementing it afterward. The transfer's URBs are not deallocated
+until io->complete is triggered, which happens when io->count reaches
+zero.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Reported-and-tested-by: Kyungtae Kim <kt0755@gmail.com>
+CC: <stable@vger.kernel.org>
+
+Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.2003281615140.14837-100000@netrider.rowland.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/usb/core/message.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/core/message.c
++++ b/drivers/usb/core/message.c
+@@ -584,12 +584,13 @@ void usb_sg_cancel(struct usb_sg_request
+ int i, retval;
+
+ spin_lock_irqsave(&io->lock, flags);
+- if (io->status) {
++ if (io->status || io->count == 0) {
+ spin_unlock_irqrestore(&io->lock, flags);
+ return;
+ }
+ /* shut everything down */
+ io->status = -ECONNRESET;
++ io->count++; /* Keep the request alive until we're done */
+ spin_unlock_irqrestore(&io->lock, flags);
+
+ for (i = io->entries - 1; i >= 0; --i) {
+@@ -603,6 +604,12 @@ void usb_sg_cancel(struct usb_sg_request
+ dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
+ __func__, retval);
+ }
++
++ spin_lock_irqsave(&io->lock, flags);
++ io->count--;
++ if (!io->count)
++ complete(&io->complete);
++ spin_unlock_irqrestore(&io->lock, flags);
+ }
+ EXPORT_SYMBOL_GPL(usb_sg_cancel);
+
diff --git a/queue-3.16/usb-gadget-fix-illegal-array-access-in-binding-with-udc.patch b/queue-3.16/usb-gadget-fix-illegal-array-access-in-binding-with-udc.patch
new file mode 100644
index 00000000..4d36b48a
--- /dev/null
+++ b/queue-3.16/usb-gadget-fix-illegal-array-access-in-binding-with-udc.patch
@@ -0,0 +1,72 @@
+From: Kyungtae Kim <kt0755@gmail.com>
+Date: Sun, 10 May 2020 05:43:34 +0000
+Subject: USB: gadget: fix illegal array access in binding with UDC
+
+commit 15753588bcd4bbffae1cca33c8ced5722477fe1f upstream.
+
+FuzzUSB (a variant of syzkaller) found an illegal array access
+using an incorrect index while binding a gadget with UDC.
+
+Reference: https://www.spinics.net/lists/linux-usb/msg194331.html
+
+This bug occurs when a size variable used for a buffer
+is misused to access its strcpy-ed buffer.
+Given a buffer along with its size variable (taken from user input),
+from which, a new buffer is created using kstrdup().
+Due to the original buffer containing 0 value in the middle,
+the size of the kstrdup-ed buffer becomes smaller than that of the original.
+So accessing the kstrdup-ed buffer with the same size variable
+triggers memory access violation.
+
+The fix makes sure no zero value in the buffer,
+by comparing the strlen() of the orignal buffer with the size variable,
+so that the access to the kstrdup-ed buffer is safe.
+
+BUG: KASAN: slab-out-of-bounds in gadget_dev_desc_UDC_store+0x1ba/0x200
+drivers/usb/gadget/configfs.c:266
+Read of size 1 at addr ffff88806a55dd7e by task syz-executor.0/17208
+
+CPU: 2 PID: 17208 Comm: syz-executor.0 Not tainted 5.6.8 #1
+Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
+Call Trace:
+ __dump_stack lib/dump_stack.c:77 [inline]
+ dump_stack+0xce/0x128 lib/dump_stack.c:118
+ print_address_description.constprop.4+0x21/0x3c0 mm/kasan/report.c:374
+ __kasan_report+0x131/0x1b0 mm/kasan/report.c:506
+ kasan_report+0x12/0x20 mm/kasan/common.c:641
+ __asan_report_load1_noabort+0x14/0x20 mm/kasan/generic_report.c:132
+ gadget_dev_desc_UDC_store+0x1ba/0x200 drivers/usb/gadget/configfs.c:266
+ flush_write_buffer fs/configfs/file.c:251 [inline]
+ configfs_write_file+0x2f1/0x4c0 fs/configfs/file.c:283
+ __vfs_write+0x85/0x110 fs/read_write.c:494
+ vfs_write+0x1cd/0x510 fs/read_write.c:558
+ ksys_write+0x18a/0x220 fs/read_write.c:611
+ __do_sys_write fs/read_write.c:623 [inline]
+ __se_sys_write fs/read_write.c:620 [inline]
+ __x64_sys_write+0x73/0xb0 fs/read_write.c:620
+ do_syscall_64+0x9e/0x510 arch/x86/entry/common.c:294
+ entry_SYSCALL_64_after_hwframe+0x49/0xbe
+
+Signed-off-by: Kyungtae Kim <kt0755@gmail.com>
+Reported-and-tested-by: Kyungtae Kim <kt0755@gmail.com>
+Cc: Felipe Balbi <balbi@kernel.org>
+Cc: stable <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/20200510054326.GA19198@pizza01
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/usb/gadget/configfs.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/usb/gadget/configfs.c
++++ b/drivers/usb/gadget/configfs.c
+@@ -254,6 +254,9 @@ static ssize_t gadget_dev_desc_UDC_store
+ char *name;
+ int ret;
+
++ if (strlen(page) < len)
++ return -EOVERFLOW;
++
+ name = kstrdup(page, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;