]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 15 Feb 2018 08:35:19 +0000 (09:35 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 15 Feb 2018 08:35:19 +0000 (09:35 +0100)
added patches:
alpha-fix-crash-if-pthread_create-races-with-signal-delivery.patch
alpha-fix-reboot-on-avanti-platform.patch
arm-kvm-fix-smccc-handling-of-unimplemented-smc-hvc-calls.patch
blk-mq-quiesce-queue-before-freeing-queue.patch
bluetooth-btsdio-do-not-bind-to-non-removable-bcm43341.patch
bluetooth-btusb-restore-qca-rome-suspend-resume-fix-with-a-rewritten-version.patch
crypto-caam-fix-endless-loop-when-deco-acquire-fails.patch
edac-octeon-fix-an-uninitialized-variable-warning.patch
hid-quirks-fix-keyboard-touchpad-on-toshiba-click-mini-not-working.patch
kernel-async.c-revert-async-simplify-lowest_in_progress.patch
kvm-nvmx-fix-races-when-sending-nested-pi-while-dest-enters-leaves-l2.patch
media-cxusb-dib0700-ignore-xc2028_i2c_flush.patch
media-ts2020-avoid-integer-overflows-on-32-bit-machines.patch
media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch
media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch
media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch
media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch
media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch
media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch
media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch
media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch
media-v4l2-compat-ioctl32.c-fix-the-indentation.patch
media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch
media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch
media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch
media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch
pktcdvd-fix-pkt_setup_dev-error-path.patch
revert-bluetooth-btusb-fix-qca-rome-suspend-resume.patch
signal-openrisc-fix-do_unaligned_access-to-send-the-proper-signal.patch
signal-sh-ensure-si_signo-is-initialized-in-do_divide_error.patch
vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch
watchdog-imx2_wdt-restore-previous-timeout-after-suspend-resume.patch
xtensa-fix-futex_atomic_cmpxchg_inatomic.patch

34 files changed:
queue-4.4/alpha-fix-crash-if-pthread_create-races-with-signal-delivery.patch [new file with mode: 0644]
queue-4.4/alpha-fix-reboot-on-avanti-platform.patch [new file with mode: 0644]
queue-4.4/arm-kvm-fix-smccc-handling-of-unimplemented-smc-hvc-calls.patch [new file with mode: 0644]
queue-4.4/blk-mq-quiesce-queue-before-freeing-queue.patch [new file with mode: 0644]
queue-4.4/bluetooth-btsdio-do-not-bind-to-non-removable-bcm43341.patch [new file with mode: 0644]
queue-4.4/bluetooth-btusb-restore-qca-rome-suspend-resume-fix-with-a-rewritten-version.patch [new file with mode: 0644]
queue-4.4/crypto-caam-fix-endless-loop-when-deco-acquire-fails.patch [new file with mode: 0644]
queue-4.4/edac-octeon-fix-an-uninitialized-variable-warning.patch [new file with mode: 0644]
queue-4.4/hid-quirks-fix-keyboard-touchpad-on-toshiba-click-mini-not-working.patch [new file with mode: 0644]
queue-4.4/kernel-async.c-revert-async-simplify-lowest_in_progress.patch [new file with mode: 0644]
queue-4.4/kvm-nvmx-fix-races-when-sending-nested-pi-while-dest-enters-leaves-l2.patch [new file with mode: 0644]
queue-4.4/media-cxusb-dib0700-ignore-xc2028_i2c_flush.patch [new file with mode: 0644]
queue-4.4/media-ts2020-avoid-integer-overflows-on-32-bit-machines.patch [new file with mode: 0644]
queue-4.4/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch [new file with mode: 0644]
queue-4.4/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch [new file with mode: 0644]
queue-4.4/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch [new file with mode: 0644]
queue-4.4/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch [new file with mode: 0644]
queue-4.4/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch [new file with mode: 0644]
queue-4.4/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch [new file with mode: 0644]
queue-4.4/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch [new file with mode: 0644]
queue-4.4/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch [new file with mode: 0644]
queue-4.4/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch [new file with mode: 0644]
queue-4.4/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch [new file with mode: 0644]
queue-4.4/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch [new file with mode: 0644]
queue-4.4/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch [new file with mode: 0644]
queue-4.4/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch [new file with mode: 0644]
queue-4.4/pktcdvd-fix-pkt_setup_dev-error-path.patch [new file with mode: 0644]
queue-4.4/revert-bluetooth-btusb-fix-qca-rome-suspend-resume.patch [new file with mode: 0644]
queue-4.4/series
queue-4.4/signal-openrisc-fix-do_unaligned_access-to-send-the-proper-signal.patch [new file with mode: 0644]
queue-4.4/signal-sh-ensure-si_signo-is-initialized-in-do_divide_error.patch [new file with mode: 0644]
queue-4.4/vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch [new file with mode: 0644]
queue-4.4/watchdog-imx2_wdt-restore-previous-timeout-after-suspend-resume.patch [new file with mode: 0644]
queue-4.4/xtensa-fix-futex_atomic_cmpxchg_inatomic.patch [new file with mode: 0644]

diff --git a/queue-4.4/alpha-fix-crash-if-pthread_create-races-with-signal-delivery.patch b/queue-4.4/alpha-fix-crash-if-pthread_create-races-with-signal-delivery.patch
new file mode 100644 (file)
index 0000000..72dd431
--- /dev/null
@@ -0,0 +1,56 @@
+From 21ffceda1c8b3807615c40d440d7815e0c85d366 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Tue, 2 Jan 2018 14:01:34 -0500
+Subject: alpha: fix crash if pthread_create races with signal delivery
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit 21ffceda1c8b3807615c40d440d7815e0c85d366 upstream.
+
+On alpha, a process will crash if it attempts to start a thread and a
+signal is delivered at the same time. The crash can be reproduced with
+this program: https://cygwin.com/ml/cygwin/2014-11/msg00473.html
+
+The reason for the crash is this:
+* we call the clone syscall
+* we go to the function copy_process
+* copy process calls copy_thread_tls, it is a wrapper around copy_thread
+* copy_thread sets the tls pointer: childti->pcb.unique = regs->r20
+* copy_thread sets regs->r20 to zero
+* we go back to copy_process
+* copy process checks "if (signal_pending(current))" and returns
+  -ERESTARTNOINTR
+* the clone syscall is restarted, but this time, regs->r20 is zero, so
+  the new thread is created with zero tls pointer
+* the new thread crashes in start_thread when attempting to access tls
+
+The comment in the code says that setting the register r20 is some
+compatibility with OSF/1. But OSF/1 doesn't use the CLONE_SETTLS flag, so
+we don't have to zero r20 if CLONE_SETTLS is set. This patch fixes the bug
+by zeroing regs->r20 only if CLONE_SETTLS is not set.
+
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Matt Turner <mattst88@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/alpha/kernel/process.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/arch/alpha/kernel/process.c
++++ b/arch/alpha/kernel/process.c
+@@ -273,12 +273,13 @@ copy_thread(unsigned long clone_flags, u
+          application calling fork.  */
+       if (clone_flags & CLONE_SETTLS)
+               childti->pcb.unique = regs->r20;
++      else
++              regs->r20 = 0;  /* OSF/1 has some strange fork() semantics.  */
+       childti->pcb.usp = usp ?: rdusp();
+       *childregs = *regs;
+       childregs->r0 = 0;
+       childregs->r19 = 0;
+       childregs->r20 = 1;     /* OSF/1 has some strange fork() semantics.  */
+-      regs->r20 = 0;
+       stack = ((struct switch_stack *) regs) - 1;
+       *childstack = *stack;
+       childstack->r26 = (unsigned long) ret_from_fork;
diff --git a/queue-4.4/alpha-fix-reboot-on-avanti-platform.patch b/queue-4.4/alpha-fix-reboot-on-avanti-platform.patch
new file mode 100644 (file)
index 0000000..100748e
--- /dev/null
@@ -0,0 +1,32 @@
+From 55fc633c41a08ce9244ff5f528f420b16b1e04d6 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Tue, 2 Jan 2018 13:59:54 -0500
+Subject: alpha: fix reboot on Avanti platform
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit 55fc633c41a08ce9244ff5f528f420b16b1e04d6 upstream.
+
+We need to define NEED_SRM_SAVE_RESTORE on the Avanti, otherwise we get
+machine check exception when attempting to reboot the machine.
+
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Matt Turner <mattst88@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/alpha/kernel/pci_impl.h |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/arch/alpha/kernel/pci_impl.h
++++ b/arch/alpha/kernel/pci_impl.h
+@@ -143,7 +143,8 @@ struct pci_iommu_arena
+ };
+ #if defined(CONFIG_ALPHA_SRM) && \
+-    (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA))
++    (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA) || \
++     defined(CONFIG_ALPHA_AVANTI))
+ # define NEED_SRM_SAVE_RESTORE
+ #else
+ # undef NEED_SRM_SAVE_RESTORE
diff --git a/queue-4.4/arm-kvm-fix-smccc-handling-of-unimplemented-smc-hvc-calls.patch b/queue-4.4/arm-kvm-fix-smccc-handling-of-unimplemented-smc-hvc-calls.patch
new file mode 100644 (file)
index 0000000..8340351
--- /dev/null
@@ -0,0 +1,55 @@
+From 20e8175d246e9f9deb377f2784b3e7dfb2ad3e86 Mon Sep 17 00:00:00 2001
+From: Marc Zyngier <marc.zyngier@arm.com>
+Date: Tue, 6 Feb 2018 17:56:06 +0000
+Subject: arm: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls
+
+From: Marc Zyngier <marc.zyngier@arm.com>
+
+commit 20e8175d246e9f9deb377f2784b3e7dfb2ad3e86 upstream.
+
+KVM doesn't follow the SMCCC when it comes to unimplemented calls,
+and inject an UNDEF instead of returning an error. Since firmware
+calls are now used for security mitigation, they are becoming more
+common, and the undef is counter productive.
+
+Instead, let's follow the SMCCC which states that -1 must be returned
+to the caller when getting an unknown function number.
+
+Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/arm/kvm/handle_exit.c |   13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/kvm/handle_exit.c
++++ b/arch/arm/kvm/handle_exit.c
+@@ -45,7 +45,7 @@ static int handle_hvc(struct kvm_vcpu *v
+       ret = kvm_psci_call(vcpu);
+       if (ret < 0) {
+-              kvm_inject_undefined(vcpu);
++              vcpu_set_reg(vcpu, 0, ~0UL);
+               return 1;
+       }
+@@ -54,7 +54,16 @@ static int handle_hvc(struct kvm_vcpu *v
+ static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
+ {
+-      kvm_inject_undefined(vcpu);
++      /*
++       * "If an SMC instruction executed at Non-secure EL1 is
++       * trapped to EL2 because HCR_EL2.TSC is 1, the exception is a
++       * Trap exception, not a Secure Monitor Call exception [...]"
++       *
++       * We need to advance the PC after the trap, as it would
++       * otherwise return to the same address...
++       */
++      vcpu_set_reg(vcpu, 0, ~0UL);
++      kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+       return 1;
+ }
diff --git a/queue-4.4/blk-mq-quiesce-queue-before-freeing-queue.patch b/queue-4.4/blk-mq-quiesce-queue-before-freeing-queue.patch
new file mode 100644 (file)
index 0000000..6c7def8
--- /dev/null
@@ -0,0 +1,103 @@
+From c2856ae2f315d754a0b6a268e4c6745b332b42e7 Mon Sep 17 00:00:00 2001
+From: Ming Lei <ming.lei@redhat.com>
+Date: Sat, 6 Jan 2018 16:27:37 +0800
+Subject: blk-mq: quiesce queue before freeing queue
+
+From: Ming Lei <ming.lei@redhat.com>
+
+commit c2856ae2f315d754a0b6a268e4c6745b332b42e7 upstream.
+
+After queue is frozen, dispatch still may happen, for example:
+
+1) requests are submitted from several contexts
+2) requests from all these contexts are inserted to queue, but may dispatch
+to LLD in one of these paths, but other paths sill need to move on even all
+these requests are completed(that means blk_mq_freeze_queue_wait() returns
+at that time)
+3) dispatch after queue freezing still moves on and causes use-after-free,
+because request queue is freed
+
+This patch quiesces queue after it is frozen, and makes sure all
+in-progress dispatch are completed.
+
+This patch fixes the following kernel crash when running heavy IOs vs.
+deleting device:
+
+[   36.719251] BUG: unable to handle kernel NULL pointer dereference at 0000000000000008
+[   36.720318] IP: kyber_has_work+0x14/0x40
+[   36.720847] PGD 254bf5067 P4D 254bf5067 PUD 255e6a067 PMD 0
+[   36.721584] Oops: 0000 [#1] PREEMPT SMP
+[   36.722105] Dumping ftrace buffer:
+[   36.722570]    (ftrace buffer empty)
+[   36.723057] Modules linked in: scsi_debug ebtable_filter ebtables ip6table_filter ip6_tables tcm_loop iscsi_target_mod target_core_file target_core_iblock target_core_pscsi target_core_mod xt_CHECKSUM iptable_mangle ipt_MASQUERADE nf_nat_masquerade_ipv4 iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack libcrc32c bridge stp llc fuse iptable_filter ip_tables sd_mod sg btrfs xor zstd_decompress zstd_compress xxhash raid6_pq mptsas mptscsih bcache crc32c_intel ahci mptbase libahci serio_raw scsi_transport_sas nvme libata shpchp lpc_ich virtio_scsi nvme_core binfmt_misc dm_mod iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi null_blk configs
+[   36.733438] CPU: 2 PID: 2374 Comm: fio Not tainted 4.15.0-rc2.blk_mq_quiesce+ #714
+[   36.735143] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.9.3-1.fc25 04/01/2014
+[   36.736688] RIP: 0010:kyber_has_work+0x14/0x40
+[   36.737515] RSP: 0018:ffffc9000209bca0 EFLAGS: 00010202
+[   36.738431] RAX: 0000000000000008 RBX: ffff88025578bfc8 RCX: ffff880257bf4ed0
+[   36.739581] RDX: 0000000000000038 RSI: ffffffff81a98c6d RDI: ffff88025578bfc8
+[   36.740730] RBP: ffff880253cebfc8 R08: ffffc9000209bda0 R09: ffff8802554f3480
+[   36.741885] R10: ffffc9000209be60 R11: ffff880263f72538 R12: ffff88025573e9e8
+[   36.743036] R13: ffff88025578bfd0 R14: 0000000000000001 R15: 0000000000000000
+[   36.744189] FS:  00007f9b9bee67c0(0000) GS:ffff88027fc80000(0000) knlGS:0000000000000000
+[   36.746617] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[   36.748483] CR2: 0000000000000008 CR3: 0000000254bf4001 CR4: 00000000003606e0
+[   36.750164] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+[   36.751455] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+[   36.752796] Call Trace:
+[   36.753992]  blk_mq_do_dispatch_sched+0x7f/0xe0
+[   36.755110]  blk_mq_sched_dispatch_requests+0x119/0x190
+[   36.756179]  __blk_mq_run_hw_queue+0x83/0x90
+[   36.757144]  __blk_mq_delay_run_hw_queue+0xaf/0x110
+[   36.758046]  blk_mq_run_hw_queue+0x24/0x70
+[   36.758845]  blk_mq_flush_plug_list+0x1e7/0x270
+[   36.759676]  blk_flush_plug_list+0xd6/0x240
+[   36.760463]  blk_finish_plug+0x27/0x40
+[   36.761195]  do_io_submit+0x19b/0x780
+[   36.761921]  ? entry_SYSCALL_64_fastpath+0x1a/0x7d
+[   36.762788]  entry_SYSCALL_64_fastpath+0x1a/0x7d
+[   36.763639] RIP: 0033:0x7f9b9699f697
+[   36.764352] RSP: 002b:00007ffc10f991b8 EFLAGS: 00000206 ORIG_RAX: 00000000000000d1
+[   36.765773] RAX: ffffffffffffffda RBX: 00000000008f6f00 RCX: 00007f9b9699f697
+[   36.766965] RDX: 0000000000a5e6c0 RSI: 0000000000000001 RDI: 00007f9b8462a000
+[   36.768377] RBP: 0000000000000000 R08: 0000000000000001 R09: 00000000008f6420
+[   36.769649] R10: 00007f9b846e5000 R11: 0000000000000206 R12: 00007f9b795d6a70
+[   36.770807] R13: 00007f9b795e4140 R14: 00007f9b795e3fe0 R15: 0000000100000000
+[   36.771955] Code: 83 c7 10 e9 3f 68 d1 ff 0f 1f 44 00 00 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 8b 97 b0 00 00 00 48 8d 42 08 48 83 c2 38 <48> 3b 00 74 06 b8 01 00 00 00 c3 48 3b 40 08 75 f4 48 83 c0 10
+[   36.775004] RIP: kyber_has_work+0x14/0x40 RSP: ffffc9000209bca0
+[   36.776012] CR2: 0000000000000008
+[   36.776690] ---[ end trace 4045cbce364ff2a4 ]---
+[   36.777527] Kernel panic - not syncing: Fatal exception
+[   36.778526] Dumping ftrace buffer:
+[   36.779313]    (ftrace buffer empty)
+[   36.780081] Kernel Offset: disabled
+[   36.780877] ---[ end Kernel panic - not syncing: Fatal exception
+
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Tested-by: Yi Zhang <yi.zhang@redhat.com>
+Signed-off-by: Ming Lei <ming.lei@redhat.com>
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ block/blk-core.c |    9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/block/blk-core.c
++++ b/block/blk-core.c
+@@ -579,6 +579,15 @@ void blk_cleanup_queue(struct request_qu
+       queue_flag_set(QUEUE_FLAG_DEAD, q);
+       spin_unlock_irq(lock);
++      /*
++       * make sure all in-progress dispatch are completed because
++       * blk_freeze_queue() can only complete all requests, and
++       * dispatch may still be in-progress since we dispatch requests
++       * from more than one contexts
++       */
++      if (q->mq_ops)
++              blk_mq_quiesce_queue(q);
++
+       /* for synchronous bio-based driver finish in-flight integrity i/o */
+       blk_flush_integrity();
diff --git a/queue-4.4/bluetooth-btsdio-do-not-bind-to-non-removable-bcm43341.patch b/queue-4.4/bluetooth-btsdio-do-not-bind-to-non-removable-bcm43341.patch
new file mode 100644 (file)
index 0000000..bb61409
--- /dev/null
@@ -0,0 +1,57 @@
+From b4cdaba274247c9c841c6a682c08fa91fb3aa549 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 29 Nov 2017 20:29:07 +0100
+Subject: Bluetooth: btsdio: Do not bind to non-removable BCM43341
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+commit b4cdaba274247c9c841c6a682c08fa91fb3aa549 upstream.
+
+BCM43341 devices soldered onto the PCB (non-removable) always (AFAICT)
+use an UART connection for bluetooth. But they also advertise btsdio
+support on their 3th sdio function, this causes 2 problems:
+
+1) A non functioning BT HCI getting registered
+
+2) Since the btsdio driver does not have suspend/resume callbacks,
+mmc_sdio_pre_suspend will return -ENOSYS, causing mmc_pm_notify()
+to react as if the SDIO-card is removed and since the slot is
+marked as non-removable it will never get detected as inserted again.
+Which results in wifi no longer working after a suspend/resume.
+
+This commit fixes both by making btsdio ignore BCM43341 devices
+when connected to a slot which is marked non-removable.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/bluetooth/btsdio.c |    9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/bluetooth/btsdio.c
++++ b/drivers/bluetooth/btsdio.c
+@@ -31,6 +31,7 @@
+ #include <linux/errno.h>
+ #include <linux/skbuff.h>
++#include <linux/mmc/host.h>
+ #include <linux/mmc/sdio_ids.h>
+ #include <linux/mmc/sdio_func.h>
+@@ -291,6 +292,14 @@ static int btsdio_probe(struct sdio_func
+               tuple = tuple->next;
+       }
++      /* BCM43341 devices soldered onto the PCB (non-removable) use an
++       * uart connection for bluetooth, ignore the BT SDIO interface.
++       */
++      if (func->vendor == SDIO_VENDOR_ID_BROADCOM &&
++          func->device == SDIO_DEVICE_ID_BROADCOM_43341 &&
++          !mmc_card_is_removable(func->card->host))
++              return -ENODEV;
++
+       data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
diff --git a/queue-4.4/bluetooth-btusb-restore-qca-rome-suspend-resume-fix-with-a-rewritten-version.patch b/queue-4.4/bluetooth-btusb-restore-qca-rome-suspend-resume-fix-with-a-rewritten-version.patch
new file mode 100644 (file)
index 0000000..dd99b9b
--- /dev/null
@@ -0,0 +1,111 @@
+From 61f5acea8737d9b717fcc22bb6679924f3c82b98 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 8 Jan 2018 10:44:16 +0100
+Subject: Bluetooth: btusb: Restore QCA Rome suspend/resume fix with a "rewritten" version
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+commit 61f5acea8737d9b717fcc22bb6679924f3c82b98 upstream.
+
+Commit 7d06d5895c15 ("Revert "Bluetooth: btusb: fix QCA...suspend/resume"")
+removed the setting of the BTUSB_RESET_RESUME quirk for QCA Rome devices,
+instead favoring adding USB_QUIRK_RESET_RESUME quirks in usb/core/quirks.c.
+
+This was done because the DIY BTUSB_RESET_RESUME reset-resume handling
+has several issues (see the original commit message). An added advantage
+of moving over to the USB-core reset-resume handling is that it also
+disables autosuspend for these devices, which is similarly broken on these.
+
+But there are 2 issues with this approach:
+1) It leaves the broken DIY BTUSB_RESET_RESUME code in place for Realtek
+   devices.
+2) Sofar only 2 of the 10 QCA devices known to the btusb code have been
+   added to usb/core/quirks.c and if we fix the Realtek case the same way
+   we need to add an additional 14 entries. So in essence we need to
+   duplicate a large part of the usb_device_id table in btusb.c in
+   usb/core/quirks.c and manually keep them in sync.
+
+This commit instead restores setting a reset-resume quirk for QCA devices
+in the btusb.c code, avoiding the duplicate usb_device_id table problem.
+
+This commit avoids the problems with the original DIY BTUSB_RESET_RESUME
+code by simply setting the USB_QUIRK_RESET_RESUME quirk directly on the
+usb_device.
+
+This commit also moves the BTUSB_REALTEK case over to directly setting the
+USB_QUIRK_RESET_RESUME on the usb_device and removes the now unused
+BTUSB_RESET_RESUME code.
+
+BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1514836
+Fixes: 7d06d5895c15 ("Revert "Bluetooth: btusb: fix QCA...suspend/resume"")
+Cc: Leif Liddy <leif.linux@gmail.com>
+Cc: Matthias Kaehlcke <mka@chromium.org>
+Cc: Brian Norris <briannorris@chromium.org>
+Cc: Daniel Drake <drake@endlessm.com>
+Cc: Kai-Heng Feng <kai.heng.feng@canonical.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/bluetooth/btusb.c |   21 ++++++++++-----------
+ 1 file changed, 10 insertions(+), 11 deletions(-)
+
+--- a/drivers/bluetooth/btusb.c
++++ b/drivers/bluetooth/btusb.c
+@@ -23,6 +23,7 @@
+ #include <linux/module.h>
+ #include <linux/usb.h>
++#include <linux/usb/quirks.h>
+ #include <linux/firmware.h>
+ #include <asm/unaligned.h>
+@@ -360,8 +361,8 @@ static const struct usb_device_id blackl
+ #define BTUSB_FIRMWARE_LOADED 7
+ #define BTUSB_FIRMWARE_FAILED 8
+ #define BTUSB_BOOTING         9
+-#define BTUSB_RESET_RESUME    10
+-#define BTUSB_DIAG_RUNNING    11
++#define BTUSB_DIAG_RUNNING    10
++#define BTUSB_OOB_WAKE_ENABLED        11
+ struct btusb_data {
+       struct hci_dev       *hdev;
+@@ -2969,6 +2970,12 @@ static int btusb_probe(struct usb_interf
+       if (id->driver_info & BTUSB_QCA_ROME) {
+               data->setup_on_usb = btusb_setup_qca;
+               hdev->set_bdaddr = btusb_set_bdaddr_ath3012;
++
++              /* QCA Rome devices lose their updated firmware over suspend,
++               * but the USB hub doesn't notice any status change.
++               * explicitly request a device reset on resume.
++               */
++              interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
+       }
+ #ifdef CONFIG_BT_HCIBTUSB_RTL
+@@ -2979,7 +2986,7 @@ static int btusb_probe(struct usb_interf
+                * but the USB hub doesn't notice any status change.
+                * Explicitly request a device reset on resume.
+                */
+-              set_bit(BTUSB_RESET_RESUME, &data->flags);
++              interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
+       }
+ #endif
+@@ -3136,14 +3143,6 @@ static int btusb_suspend(struct usb_inte
+       btusb_stop_traffic(data);
+       usb_kill_anchored_urbs(&data->tx_anchor);
+-      /* Optionally request a device reset on resume, but only when
+-       * wakeups are disabled. If wakeups are enabled we assume the
+-       * device will stay powered up throughout suspend.
+-       */
+-      if (test_bit(BTUSB_RESET_RESUME, &data->flags) &&
+-          !device_may_wakeup(&data->udev->dev))
+-              data->udev->reset_resume = 1;
+-
+       return 0;
+ }
diff --git a/queue-4.4/crypto-caam-fix-endless-loop-when-deco-acquire-fails.patch b/queue-4.4/crypto-caam-fix-endless-loop-when-deco-acquire-fails.patch
new file mode 100644 (file)
index 0000000..2b13338
--- /dev/null
@@ -0,0 +1,58 @@
+From 225ece3e7dad4cfc44cca38ce7a3a80f255ea8f1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Horia=20Geant=C4=83?= <horia.geanta@nxp.com>
+Date: Mon, 5 Feb 2018 11:15:52 +0200
+Subject: crypto: caam - fix endless loop when DECO acquire fails
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Horia Geantă <horia.geanta@nxp.com>
+
+commit 225ece3e7dad4cfc44cca38ce7a3a80f255ea8f1 upstream.
+
+In case DECO0 cannot be acquired - i.e. run_descriptor_deco0() fails
+with -ENODEV, caam_probe() enters an endless loop:
+
+run_descriptor_deco0
+       ret -ENODEV
+       -> instantiate_rng
+               -ENODEV, overwritten by -EAGAIN
+               ret -EAGAIN
+               -> caam_probe
+                       -EAGAIN results in endless loop
+
+It turns out the error path in instantiate_rng() is incorrect,
+the checks are done in the wrong order.
+
+Fixes: 1005bccd7a4a6 ("crypto: caam - enable instantiation of all RNG4 state handles")
+Reported-by: Bryan O'Donoghue <pure.logic@nexus-software.ie>
+Suggested-by: Auer Lukas <lukas.auer@aisec.fraunhofer.de>
+Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/crypto/caam/ctrl.c |    8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/crypto/caam/ctrl.c
++++ b/drivers/crypto/caam/ctrl.c
+@@ -224,12 +224,16 @@ static int instantiate_rng(struct device
+                * without any error (HW optimizations for later
+                * CAAM eras), then try again.
+                */
++              if (ret)
++                      break;
++
+               rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK;
+               if ((status && status != JRSTA_SSRC_JUMP_HALT_CC) ||
+-                  !(rdsta_val & (1 << sh_idx)))
++                  !(rdsta_val & (1 << sh_idx))) {
+                       ret = -EAGAIN;
+-              if (ret)
+                       break;
++              }
++
+               dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx);
+               /* Clear the contents before recreating the descriptor */
+               memset(desc, 0x00, CAAM_CMD_SZ * 7);
diff --git a/queue-4.4/edac-octeon-fix-an-uninitialized-variable-warning.patch b/queue-4.4/edac-octeon-fix-an-uninitialized-variable-warning.patch
new file mode 100644 (file)
index 0000000..1511b18
--- /dev/null
@@ -0,0 +1,47 @@
+From 544e92581a2ac44607d7cc602c6b54d18656f56d Mon Sep 17 00:00:00 2001
+From: James Hogan <jhogan@kernel.org>
+Date: Mon, 13 Nov 2017 16:12:06 +0000
+Subject: EDAC, octeon: Fix an uninitialized variable warning
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: James Hogan <jhogan@kernel.org>
+
+commit 544e92581a2ac44607d7cc602c6b54d18656f56d upstream.
+
+Fix an uninitialized variable warning in the Octeon EDAC driver, as seen
+in MIPS cavium_octeon_defconfig builds since v4.14 with Codescape GNU
+Tools 2016.05-03:
+
+  drivers/edac/octeon_edac-lmc.c In function ‘octeon_lmc_edac_poll_o2’:
+  drivers/edac/octeon_edac-lmc.c:87:24: warning: ‘((long unsigned int*)&int_reg)[1]’ may \
+    be used uninitialized in this function [-Wmaybe-uninitialized]
+    if (int_reg.s.sec_err || int_reg.s.ded_err) {
+                        ^
+Iinitialise the whole int_reg variable to zero before the conditional
+assignments in the error injection case.
+
+Signed-off-by: James Hogan <jhogan@kernel.org>
+Acked-by: David Daney <david.daney@cavium.com>
+Cc: linux-edac <linux-edac@vger.kernel.org>
+Cc: linux-mips@linux-mips.org
+Fixes: 1bc021e81565 ("EDAC: Octeon: Add error injection support")
+Link: http://lkml.kernel.org/r/20171113161206.20990-1-james.hogan@mips.com
+Signed-off-by: Borislav Petkov <bp@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/edac/octeon_edac-lmc.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/edac/octeon_edac-lmc.c
++++ b/drivers/edac/octeon_edac-lmc.c
+@@ -79,6 +79,7 @@ static void octeon_lmc_edac_poll_o2(stru
+       if (!pvt->inject)
+               int_reg.u64 = cvmx_read_csr(CVMX_LMCX_INT(mci->mc_idx));
+       else {
++              int_reg.u64 = 0;
+               if (pvt->error_type == 1)
+                       int_reg.s.sec_err = 1;
+               if (pvt->error_type == 2)
diff --git a/queue-4.4/hid-quirks-fix-keyboard-touchpad-on-toshiba-click-mini-not-working.patch b/queue-4.4/hid-quirks-fix-keyboard-touchpad-on-toshiba-click-mini-not-working.patch
new file mode 100644 (file)
index 0000000..e4c9f9d
--- /dev/null
@@ -0,0 +1,57 @@
+From edfc3722cfef4217c7fe92b272cbe0288ba1ff57 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 17 Jan 2018 21:05:55 +0100
+Subject: HID: quirks: Fix keyboard + touchpad on Toshiba Click Mini not working
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+commit edfc3722cfef4217c7fe92b272cbe0288ba1ff57 upstream.
+
+The Toshiba Click Mini uses an i2c attached keyboard/touchpad combo
+(single i2c_hid device for both) which has a vid:pid of 04F3:0401,
+which is also used by a bunch of Elan touchpads which are handled by the
+drivers/input/mouse/elan_i2c driver, but that driver deals with pure
+touchpads and does not work for a combo device such as the one on the
+Toshiba Click Mini.
+
+The combo on the Mini has an ACPI id of ELAN0800, which is not claimed
+by the elan_i2c driver, so check for that and if it is found do not ignore
+the device. This fixes the keyboard/touchpad combo on the Mini not working
+(although with the touchpad in mouse emulation mode).
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hid/hid-core.c |   12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+--- a/drivers/hid/hid-core.c
++++ b/drivers/hid/hid-core.c
+@@ -2308,7 +2308,6 @@ static const struct hid_device_id hid_ig
+       { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x0004) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x000a) },
+       { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0400) },
+-      { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0401) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) },
+@@ -2578,6 +2577,17 @@ bool hid_ignore(struct hid_device *hdev)
+                       strncmp(hdev->name, "www.masterkit.ru MA901", 22) == 0)
+                       return true;
+               break;
++      case USB_VENDOR_ID_ELAN:
++              /*
++               * Many Elan devices have a product id of 0x0401 and are handled
++               * by the elan_i2c input driver. But the ACPI HID ELAN0800 dev
++               * is not (and cannot be) handled by that driver ->
++               * Ignore all 0x0401 devs except for the ELAN0800 dev.
++               */
++              if (hdev->product == 0x0401 &&
++                  strncmp(hdev->name, "ELAN0800", 8) != 0)
++                      return true;
++              break;
+       }
+       if (hdev->type == HID_TYPE_USBMOUSE &&
diff --git a/queue-4.4/kernel-async.c-revert-async-simplify-lowest_in_progress.patch b/queue-4.4/kernel-async.c-revert-async-simplify-lowest_in_progress.patch
new file mode 100644 (file)
index 0000000..0f8c255
--- /dev/null
@@ -0,0 +1,87 @@
+From 4f7e988e63e336827f4150de48163bed05d653bd Mon Sep 17 00:00:00 2001
+From: Rasmus Villemoes <linux@rasmusvillemoes.dk>
+Date: Tue, 6 Feb 2018 15:37:55 -0800
+Subject: kernel/async.c: revert "async: simplify lowest_in_progress()"
+
+From: Rasmus Villemoes <linux@rasmusvillemoes.dk>
+
+commit 4f7e988e63e336827f4150de48163bed05d653bd upstream.
+
+This reverts commit 92266d6ef60c ("async: simplify lowest_in_progress()")
+which was simply wrong: In the case where domain is NULL, we now use the
+wrong offsetof() in the list_first_entry macro, so we don't actually
+fetch the ->cookie value, but rather the eight bytes located
+sizeof(struct list_head) further into the struct async_entry.
+
+On 64 bit, that's the data member, while on 32 bit, that's a u64 built
+from func and data in some order.
+
+I think the bug happens to be harmless in practice: It obviously only
+affects callers which pass a NULL domain, and AFAICT the only such
+caller is
+
+  async_synchronize_full() ->
+  async_synchronize_full_domain(NULL) ->
+  async_synchronize_cookie_domain(ASYNC_COOKIE_MAX, NULL)
+
+and the ASYNC_COOKIE_MAX means that in practice we end up waiting for
+the async_global_pending list to be empty - but it would break if
+somebody happened to pass (void*)-1 as the data element to
+async_schedule, and of course also if somebody ever does a
+async_synchronize_cookie_domain(, NULL) with a "finite" cookie value.
+
+Maybe the "harmless in practice" means this isn't -stable material.  But
+I'm not completely confident my quick git grep'ing is enough, and there
+might be affected code in one of the earlier kernels that has since been
+removed, so I'll leave the decision to the stable guys.
+
+Link: http://lkml.kernel.org/r/20171128104938.3921-1-linux@rasmusvillemoes.dk
+Fixes: 92266d6ef60c "async: simplify lowest_in_progress()"
+Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
+Acked-by: Tejun Heo <tj@kernel.org>
+Cc: Arjan van de Ven <arjan@linux.intel.com>
+Cc: Adam Wallis <awallis@codeaurora.org>
+Cc: Lai Jiangshan <laijs@cn.fujitsu.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ kernel/async.c |   20 ++++++++++++--------
+ 1 file changed, 12 insertions(+), 8 deletions(-)
+
+--- a/kernel/async.c
++++ b/kernel/async.c
+@@ -84,20 +84,24 @@ static atomic_t entry_count;
+ static async_cookie_t lowest_in_progress(struct async_domain *domain)
+ {
+-      struct list_head *pending;
++      struct async_entry *first = NULL;
+       async_cookie_t ret = ASYNC_COOKIE_MAX;
+       unsigned long flags;
+       spin_lock_irqsave(&async_lock, flags);
+-      if (domain)
+-              pending = &domain->pending;
+-      else
+-              pending = &async_global_pending;
++      if (domain) {
++              if (!list_empty(&domain->pending))
++                      first = list_first_entry(&domain->pending,
++                                      struct async_entry, domain_list);
++      } else {
++              if (!list_empty(&async_global_pending))
++                      first = list_first_entry(&async_global_pending,
++                                      struct async_entry, global_list);
++      }
+-      if (!list_empty(pending))
+-              ret = list_first_entry(pending, struct async_entry,
+-                                     domain_list)->cookie;
++      if (first)
++              ret = first->cookie;
+       spin_unlock_irqrestore(&async_lock, flags);
+       return ret;
diff --git a/queue-4.4/kvm-nvmx-fix-races-when-sending-nested-pi-while-dest-enters-leaves-l2.patch b/queue-4.4/kvm-nvmx-fix-races-when-sending-nested-pi-while-dest-enters-leaves-l2.patch
new file mode 100644 (file)
index 0000000..470bfaa
--- /dev/null
@@ -0,0 +1,97 @@
+From 6b6977117f50d60455ace86b2d256f6fb4f3de05 Mon Sep 17 00:00:00 2001
+From: Liran Alon <liran.alon@oracle.com>
+Date: Thu, 9 Nov 2017 20:27:20 +0200
+Subject: KVM: nVMX: Fix races when sending nested PI while dest enters/leaves L2
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Liran Alon <liran.alon@oracle.com>
+
+commit 6b6977117f50d60455ace86b2d256f6fb4f3de05 upstream.
+
+Consider the following scenario:
+1. CPU A calls vmx_deliver_nested_posted_interrupt() to send an IPI
+to CPU B via virtual posted-interrupt mechanism.
+2. CPU B is currently executing L2 guest.
+3. vmx_deliver_nested_posted_interrupt() calls
+kvm_vcpu_trigger_posted_interrupt() which will note that
+vcpu->mode == IN_GUEST_MODE.
+4. Assume that before CPU A sends the physical POSTED_INTR_NESTED_VECTOR
+IPI, CPU B exits from L2 to L0 during event-delivery
+(valid IDT-vectoring-info).
+5. CPU A now sends the physical IPI. The IPI is received in host and
+it's handler (smp_kvm_posted_intr_nested_ipi()) does nothing.
+6. Assume that before CPU A sets pi_pending=true and KVM_REQ_EVENT,
+CPU B continues to run in L0 and reach vcpu_enter_guest(). As
+KVM_REQ_EVENT is not set yet, vcpu_enter_guest() will continue and resume
+L2 guest.
+7. At this point, CPU A sets pi_pending=true and KVM_REQ_EVENT but
+it's too late! CPU B already entered L2 and KVM_REQ_EVENT will only be
+consumed at next L2 entry!
+
+Another scenario to consider:
+1. CPU A calls vmx_deliver_nested_posted_interrupt() to send an IPI
+to CPU B via virtual posted-interrupt mechanism.
+2. Assume that before CPU A calls kvm_vcpu_trigger_posted_interrupt(),
+CPU B is at L0 and is about to resume into L2. Further assume that it is
+in vcpu_enter_guest() after check for KVM_REQ_EVENT.
+3. At this point, CPU A calls kvm_vcpu_trigger_posted_interrupt() which
+will note that vcpu->mode != IN_GUEST_MODE. Therefore, do nothing and
+return false. Then, will set pi_pending=true and KVM_REQ_EVENT.
+4. Now CPU B continue and resumes into L2 guest without processing
+the posted-interrupt until next L2 entry!
+
+To fix both issues, we just need to change
+vmx_deliver_nested_posted_interrupt() to set pi_pending=true and
+KVM_REQ_EVENT before calling kvm_vcpu_trigger_posted_interrupt().
+
+It will fix the first scenario by chaging step (6) to note that
+KVM_REQ_EVENT and pi_pending=true and therefore process
+nested posted-interrupt.
+
+It will fix the second scenario by two possible ways:
+1. If kvm_vcpu_trigger_posted_interrupt() is called while CPU B has changed
+vcpu->mode to IN_GUEST_MODE, physical IPI will be sent and will be received
+when CPU resumes into L2.
+2. If kvm_vcpu_trigger_posted_interrupt() is called while CPU B hasn't yet
+changed vcpu->mode to IN_GUEST_MODE, then after CPU B will change
+vcpu->mode it will call kvm_request_pending() which will return true and
+therefore force another round of vcpu_enter_guest() which will note that
+KVM_REQ_EVENT and pi_pending=true and therefore process nested
+posted-interrupt.
+
+Fixes: 705699a13994 ("KVM: nVMX: Enable nested posted interrupt processing")
+Signed-off-by: Liran Alon <liran.alon@oracle.com>
+Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
+Reviewed-by: Krish Sadhukhan <krish.sadhukhan@oracle.com>
+[Add kvm_vcpu_kick to also handle the case where L1 doesn't intercept L2 HLT
+ and L2 executes HLT instruction. - Paolo]
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/kvm/vmx.c |    5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/arch/x86/kvm/vmx.c
++++ b/arch/x86/kvm/vmx.c
+@@ -4595,14 +4595,15 @@ static int vmx_deliver_nested_posted_int
+       if (is_guest_mode(vcpu) &&
+           vector == vmx->nested.posted_intr_nv) {
+-              /* the PIR and ON have been set by L1. */
+-              kvm_vcpu_trigger_posted_interrupt(vcpu);
+               /*
+                * If a posted intr is not recognized by hardware,
+                * we will accomplish it in the next vmentry.
+                */
+               vmx->nested.pi_pending = true;
+               kvm_make_request(KVM_REQ_EVENT, vcpu);
++              /* the PIR and ON have been set by L1. */
++              if (!kvm_vcpu_trigger_posted_interrupt(vcpu))
++                      kvm_vcpu_kick(vcpu);
+               return 0;
+       }
+       return -1;
diff --git a/queue-4.4/media-cxusb-dib0700-ignore-xc2028_i2c_flush.patch b/queue-4.4/media-cxusb-dib0700-ignore-xc2028_i2c_flush.patch
new file mode 100644 (file)
index 0000000..526775f
--- /dev/null
@@ -0,0 +1,47 @@
+From 9893b905e743ded332575ca04486bd586c0772f7 Mon Sep 17 00:00:00 2001
+From: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Date: Wed, 24 Jan 2018 06:01:57 -0500
+Subject: media: cxusb, dib0700: ignore XC2028_I2C_FLUSH
+
+From: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+
+commit 9893b905e743ded332575ca04486bd586c0772f7 upstream.
+
+The XC2028_I2C_FLUSH only needs to be implemented on a few
+devices. Others can safely ignore it.
+
+That prevents filling the dmesg with lots of messages like:
+
+       dib0700: stk7700ph_xc3028_callback: unknown command 2, arg 0
+
+Fixes: 4d37ece757a8 ("[media] tuner/xc2028: Add I2C flush callback")
+Reported-by: Enrico Mioso <mrkiko.rs@gmail.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/media/usb/dvb-usb/cxusb.c           |    2 ++
+ drivers/media/usb/dvb-usb/dib0700_devices.c |    1 +
+ 2 files changed, 3 insertions(+)
+
+--- a/drivers/media/usb/dvb-usb/cxusb.c
++++ b/drivers/media/usb/dvb-usb/cxusb.c
+@@ -818,6 +818,8 @@ static int dvico_bluebird_xc2028_callbac
+       case XC2028_RESET_CLK:
+               deb_info("%s: XC2028_RESET_CLK %d\n", __func__, arg);
+               break;
++      case XC2028_I2C_FLUSH:
++              break;
+       default:
+               deb_info("%s: unknown command %d, arg %d\n", __func__,
+                        command, arg);
+--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
++++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
+@@ -431,6 +431,7 @@ static int stk7700ph_xc3028_callback(voi
+               state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+               break;
+       case XC2028_RESET_CLK:
++      case XC2028_I2C_FLUSH:
+               break;
+       default:
+               err("%s: unknown command %d, arg %d\n", __func__,
diff --git a/queue-4.4/media-ts2020-avoid-integer-overflows-on-32-bit-machines.patch b/queue-4.4/media-ts2020-avoid-integer-overflows-on-32-bit-machines.patch
new file mode 100644 (file)
index 0000000..7575a51
--- /dev/null
@@ -0,0 +1,47 @@
+From 81742be14b6a90c9fd0ff6eb4218bdf696ad8e46 Mon Sep 17 00:00:00 2001
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Date: Wed, 10 Jan 2018 07:20:39 -0500
+Subject: media: ts2020: avoid integer overflows on 32 bit machines
+
+From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+
+commit 81742be14b6a90c9fd0ff6eb4218bdf696ad8e46 upstream.
+
+Before this patch, when compiled for arm32, the signal strength
+were reported as:
+
+Lock   (0x1f) Signal= 4294908.66dBm C/N= 12.79dB
+
+Because of a 32 bit integer overflow. After it, it is properly
+reported as:
+
+       Lock   (0x1f) Signal= -58.64dBm C/N= 12.79dB
+
+Fixes: 0f91c9d6bab9 ("[media] TS2020: Calculate tuner gain correctly")
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/media/dvb-frontends/ts2020.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/media/dvb-frontends/ts2020.c
++++ b/drivers/media/dvb-frontends/ts2020.c
+@@ -369,7 +369,7 @@ static int ts2020_read_tuner_gain(struct
+               gain2 = clamp_t(long, gain2, 0, 13);
+               v_agc = clamp_t(long, v_agc, 400, 1100);
+-              *_gain = -(gain1 * 2330 +
++              *_gain = -((__s64)gain1 * 2330 +
+                          gain2 * 3500 +
+                          v_agc * 24 / 10 * 10 +
+                          10000);
+@@ -387,7 +387,7 @@ static int ts2020_read_tuner_gain(struct
+               gain3 = clamp_t(long, gain3, 0, 6);
+               v_agc = clamp_t(long, v_agc, 600, 1600);
+-              *_gain = -(gain1 * 2650 +
++              *_gain = -((__s64)gain1 * 2650 +
+                          gain2 * 3380 +
+                          gain3 * 2850 +
+                          v_agc * 176 / 100 * 10 -
diff --git a/queue-4.4/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch b/queue-4.4/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch
new file mode 100644 (file)
index 0000000..ca40952
--- /dev/null
@@ -0,0 +1,56 @@
+From foo@baz Thu Feb 15 08:44:17 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:52:36 +0100
+Subject: media: v4l2-compat-ioctl32: Copy v4l2_window->global_alpha
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Daniel Mentz <danielmentz@google.com>, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214115240.27650-11-hverkuil@xs4all.nl>
+
+From: Daniel Mentz <danielmentz@google.com>
+
+commit 025a26fa14f8fd55d50ab284a30c016a5be953d0 upstream.
+
+Commit b2787845fb91 ("V4L/DVB (5289): Add support for video output
+overlays.") added the field global_alpha to struct v4l2_window but did
+not update the compat layer accordingly. This change adds global_alpha
+to struct v4l2_window32 and copies the value for global_alpha back and
+forth.
+
+Signed-off-by: Daniel Mentz <danielmentz@google.com>
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c |    7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -45,6 +45,7 @@ struct v4l2_window32 {
+       compat_caddr_t          clips; /* actually struct v4l2_clip32 * */
+       __u32                   clipcount;
+       compat_caddr_t          bitmap;
++      __u8                    global_alpha;
+ };
+ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+@@ -53,7 +54,8 @@ static int get_v4l2_window32(struct v4l2
+           copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
+           get_user(kp->field, &up->field) ||
+           get_user(kp->chromakey, &up->chromakey) ||
+-          get_user(kp->clipcount, &up->clipcount))
++          get_user(kp->clipcount, &up->clipcount) ||
++          get_user(kp->global_alpha, &up->global_alpha))
+               return -EFAULT;
+       if (kp->clipcount > 2048)
+               return -EINVAL;
+@@ -86,7 +88,8 @@ static int put_v4l2_window32(struct v4l2
+       if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) ||
+           put_user(kp->field, &up->field) ||
+           put_user(kp->chromakey, &up->chromakey) ||
+-          put_user(kp->clipcount, &up->clipcount))
++          put_user(kp->clipcount, &up->clipcount) ||
++          put_user(kp->global_alpha, &up->global_alpha))
+               return -EFAULT;
+       return 0;
+ }
diff --git a/queue-4.4/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch b/queue-4.4/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch
new file mode 100644 (file)
index 0000000..df03408
--- /dev/null
@@ -0,0 +1,33 @@
+From foo@baz Thu Feb 15 08:44:17 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:52:29 +0100
+Subject: media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214115240.27650-4-hverkuil@xs4all.nl>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit 3ee6d040719ae09110e5cdf24d5386abe5d1b776 upstream.
+
+The result of the VIDIOC_PREPARE_BUF ioctl was never copied back
+to userspace since it was missing in the switch.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -1022,6 +1022,7 @@ static long do_video_ioctl(struct file *
+               err = put_v4l2_create32(&karg.v2crt, up);
+               break;
++      case VIDIOC_PREPARE_BUF:
+       case VIDIOC_QUERYBUF:
+       case VIDIOC_QBUF:
+       case VIDIOC_DQBUF:
diff --git a/queue-4.4/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch b/queue-4.4/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch
new file mode 100644 (file)
index 0000000..4803336
--- /dev/null
@@ -0,0 +1,321 @@
+From foo@baz Thu Feb 15 08:44:17 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:52:32 +0100
+Subject: media: v4l2-compat-ioctl32.c: avoid sizeof(type)
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214115240.27650-7-hverkuil@xs4all.nl>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit 333b1e9f96ce05f7498b581509bb30cde03018bf upstream.
+
+Instead of doing sizeof(struct foo) use sizeof(*up). There even were
+cases where 4 * sizeof(__u32) was used instead of sizeof(kp->reserved),
+which is very dangerous when the size of the reserved array changes.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c |   77 ++++++++++++--------------
+ 1 file changed, 36 insertions(+), 41 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -47,7 +47,7 @@ struct v4l2_window32 {
+ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+ {
+-      if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) ||
++      if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
+           get_user(kp->field, &up->field) ||
+           get_user(kp->chromakey, &up->chromakey) ||
+@@ -64,7 +64,7 @@ static int get_v4l2_window32(struct v4l2
+               if (get_user(p, &up->clips))
+                       return -EFAULT;
+               uclips = compat_ptr(p);
+-              kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
++              kclips = compat_alloc_user_space(n * sizeof(*kclips));
+               kp->clips = kclips;
+               while (--n >= 0) {
+                       if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
+@@ -157,14 +157,14 @@ static int __get_v4l2_format32(struct v4
+ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+ {
+-      if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)))
++      if (!access_ok(VERIFY_READ, up, sizeof(*up)))
+               return -EFAULT;
+       return __get_v4l2_format32(kp, up);
+ }
+ static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
+ {
+-      if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) ||
++      if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format)))
+               return -EFAULT;
+       return __get_v4l2_format32(&kp->format, &up->format);
+@@ -208,14 +208,14 @@ static int __put_v4l2_format32(struct v4
+ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+ {
+-      if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)))
++      if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
+               return -EFAULT;
+       return __put_v4l2_format32(kp, up);
+ }
+ static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
+ {
+-      if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) ||
++      if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) ||
+           copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
+               return -EFAULT;
+@@ -234,7 +234,7 @@ struct v4l2_standard32 {
+ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+ {
+       /* other fields are not set by the user, nor used by the driver */
+-      if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
++      if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           get_user(kp->index, &up->index))
+               return -EFAULT;
+       return 0;
+@@ -242,13 +242,13 @@ static int get_v4l2_standard32(struct v4
+ static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+ {
+-      if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
++      if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           put_user(kp->index, &up->index) ||
+           put_user(kp->id, &up->id) ||
+-          copy_to_user(up->name, kp->name, 24) ||
++          copy_to_user(up->name, kp->name, sizeof(up->name)) ||
+           copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
+           put_user(kp->framelines, &up->framelines) ||
+-          copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
++          copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
+               return -EFAULT;
+       return 0;
+ }
+@@ -296,7 +296,7 @@ static int get_v4l2_plane32(struct v4l2_
+       if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
+           copy_in_user(&up->data_offset, &up32->data_offset,
+-                       sizeof(__u32)))
++                       sizeof(up->data_offset)))
+               return -EFAULT;
+       if (memory == V4L2_MEMORY_USERPTR) {
+@@ -306,11 +306,11 @@ static int get_v4l2_plane32(struct v4l2_
+               if (put_user((unsigned long)up_pln, &up->m.userptr))
+                       return -EFAULT;
+       } else if (memory == V4L2_MEMORY_DMABUF) {
+-              if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(int)))
++              if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd)))
+                       return -EFAULT;
+       } else {
+               if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
+-                               sizeof(__u32)))
++                               sizeof(up32->m.mem_offset)))
+                       return -EFAULT;
+       }
+@@ -322,19 +322,19 @@ static int put_v4l2_plane32(struct v4l2_
+ {
+       if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
+           copy_in_user(&up32->data_offset, &up->data_offset,
+-                       sizeof(__u32)))
++                       sizeof(up->data_offset)))
+               return -EFAULT;
+       /* For MMAP, driver might've set up the offset, so copy it back.
+        * USERPTR stays the same (was userspace-provided), so no copying. */
+       if (memory == V4L2_MEMORY_MMAP)
+               if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
+-                               sizeof(__u32)))
++                               sizeof(up->m.mem_offset)))
+                       return -EFAULT;
+       /* For DMABUF, driver might've set up the fd, so copy it back. */
+       if (memory == V4L2_MEMORY_DMABUF)
+               if (copy_in_user(&up32->m.fd, &up->m.fd,
+-                               sizeof(int)))
++                               sizeof(up->m.fd)))
+                       return -EFAULT;
+       return 0;
+@@ -348,7 +348,7 @@ static int get_v4l2_buffer32(struct v4l2
+       int num_planes;
+       int ret;
+-      if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
++      if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           get_user(kp->index, &up->index) ||
+           get_user(kp->type, &up->type) ||
+           get_user(kp->flags, &up->flags) ||
+@@ -360,8 +360,7 @@ static int get_v4l2_buffer32(struct v4l2
+               if (get_user(kp->bytesused, &up->bytesused) ||
+                   get_user(kp->field, &up->field) ||
+                   get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+-                  get_user(kp->timestamp.tv_usec,
+-                           &up->timestamp.tv_usec))
++                  get_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec))
+                       return -EFAULT;
+       if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
+@@ -378,13 +377,12 @@ static int get_v4l2_buffer32(struct v4l2
+               uplane32 = compat_ptr(p);
+               if (!access_ok(VERIFY_READ, uplane32,
+-                             num_planes * sizeof(struct v4l2_plane32)))
++                             num_planes * sizeof(*uplane32)))
+                       return -EFAULT;
+               /* We don't really care if userspace decides to kill itself
+                * by passing a very big num_planes value */
+-              uplane = compat_alloc_user_space(num_planes *
+-                                               sizeof(struct v4l2_plane));
++              uplane = compat_alloc_user_space(num_planes * sizeof(*uplane));
+               kp->m.planes = (__force struct v4l2_plane *)uplane;
+               while (--num_planes >= 0) {
+@@ -432,7 +430,7 @@ static int put_v4l2_buffer32(struct v4l2
+       int num_planes;
+       int ret;
+-      if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
++      if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           put_user(kp->index, &up->index) ||
+           put_user(kp->type, &up->type) ||
+           put_user(kp->flags, &up->flags) ||
+@@ -443,7 +441,7 @@ static int put_v4l2_buffer32(struct v4l2
+           put_user(kp->field, &up->field) ||
+           put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+           put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
+-          copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
++          copy_to_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) ||
+           put_user(kp->sequence, &up->sequence) ||
+           put_user(kp->reserved2, &up->reserved2) ||
+           put_user(kp->reserved, &up->reserved) ||
+@@ -511,7 +509,7 @@ static int get_v4l2_framebuffer32(struct
+ {
+       u32 tmp;
+-      if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) ||
++      if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           get_user(tmp, &up->base) ||
+           get_user(kp->capability, &up->capability) ||
+           get_user(kp->flags, &up->flags) ||
+@@ -525,7 +523,7 @@ static int put_v4l2_framebuffer32(struct
+ {
+       u32 tmp = (u32)((unsigned long)kp->base);
+-      if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
++      if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           put_user(tmp, &up->base) ||
+           put_user(kp->capability, &up->capability) ||
+           put_user(kp->flags, &up->flags) ||
+@@ -549,14 +547,14 @@ struct v4l2_input32 {
+    Otherwise it is identical to the 32-bit version. */
+ static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
+ {
+-      if (copy_from_user(kp, up, sizeof(struct v4l2_input32)))
++      if (copy_from_user(kp, up, sizeof(*up)))
+               return -EFAULT;
+       return 0;
+ }
+ static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
+ {
+-      if (copy_to_user(up, kp, sizeof(struct v4l2_input32)))
++      if (copy_to_user(up, kp, sizeof(*up)))
+               return -EFAULT;
+       return 0;
+ }
+@@ -604,12 +602,11 @@ static int get_v4l2_ext_controls32(struc
+       int n;
+       compat_caddr_t p;
+-      if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
++      if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           get_user(kp->ctrl_class, &up->ctrl_class) ||
+           get_user(kp->count, &up->count) ||
+           get_user(kp->error_idx, &up->error_idx) ||
+-          copy_from_user(kp->reserved, up->reserved,
+-                         sizeof(kp->reserved)))
++          copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+               return -EFAULT;
+       n = kp->count;
+       if (n == 0) {
+@@ -619,10 +616,9 @@ static int get_v4l2_ext_controls32(struc
+       if (get_user(p, &up->controls))
+               return -EFAULT;
+       ucontrols = compat_ptr(p);
+-      if (!access_ok(VERIFY_READ, ucontrols,
+-                     n * sizeof(struct v4l2_ext_control32)))
++      if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(*ucontrols)))
+               return -EFAULT;
+-      kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
++      kcontrols = compat_alloc_user_space(n * sizeof(*kcontrols));
+       kp->controls = (__force struct v4l2_ext_control *)kcontrols;
+       while (--n >= 0) {
+               u32 id;
+@@ -654,7 +650,7 @@ static int put_v4l2_ext_controls32(struc
+       int n = kp->count;
+       compat_caddr_t p;
+-      if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
++      if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           put_user(kp->ctrl_class, &up->ctrl_class) ||
+           put_user(kp->count, &up->count) ||
+           put_user(kp->error_idx, &up->error_idx) ||
+@@ -666,8 +662,7 @@ static int put_v4l2_ext_controls32(struc
+       if (get_user(p, &up->controls))
+               return -EFAULT;
+       ucontrols = compat_ptr(p);
+-      if (!access_ok(VERIFY_WRITE, ucontrols,
+-                     n * sizeof(struct v4l2_ext_control32)))
++      if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(*ucontrols)))
+               return -EFAULT;
+       while (--n >= 0) {
+@@ -704,7 +699,7 @@ struct v4l2_event32 {
+ static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up)
+ {
+-      if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) ||
++      if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           put_user(kp->type, &up->type) ||
+           copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
+           put_user(kp->pending, &up->pending) ||
+@@ -712,7 +707,7 @@ static int put_v4l2_event32(struct v4l2_
+           put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+           put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) ||
+           put_user(kp->id, &up->id) ||
+-          copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
++          copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
+               return -EFAULT;
+       return 0;
+ }
+@@ -729,7 +724,7 @@ static int get_v4l2_edid32(struct v4l2_e
+ {
+       u32 tmp;
+-      if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) ||
++      if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           get_user(kp->pad, &up->pad) ||
+           get_user(kp->start_block, &up->start_block) ||
+           get_user(kp->blocks, &up->blocks) ||
+@@ -744,7 +739,7 @@ static int put_v4l2_edid32(struct v4l2_e
+ {
+       u32 tmp = (u32)((unsigned long)kp->edid);
+-      if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) ||
++      if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           put_user(kp->pad, &up->pad) ||
+           put_user(kp->start_block, &up->start_block) ||
+           put_user(kp->blocks, &up->blocks) ||
diff --git a/queue-4.4/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch b/queue-4.4/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch
new file mode 100644 (file)
index 0000000..1b4650d
--- /dev/null
@@ -0,0 +1,111 @@
+From foo@baz Thu Feb 15 08:44:17 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:52:37 +0100
+Subject: media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214115240.27650-12-hverkuil@xs4all.nl>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit a751be5b142ef6bcbbb96d9899516f4d9c8d0ef4 upstream.
+
+put_v4l2_window32() didn't copy back the clip list to userspace.
+Drivers can update the clip rectangles, so this should be done.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c |   59 +++++++++++++++++---------
+ 1 file changed, 40 insertions(+), 19 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -50,6 +50,11 @@ struct v4l2_window32 {
+ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+ {
++      struct v4l2_clip32 __user *uclips;
++      struct v4l2_clip __user *kclips;
++      compat_caddr_t p;
++      u32 n;
++
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
+           get_user(kp->field, &up->field) ||
+@@ -59,38 +64,54 @@ static int get_v4l2_window32(struct v4l2
+               return -EFAULT;
+       if (kp->clipcount > 2048)
+               return -EINVAL;
+-      if (kp->clipcount) {
+-              struct v4l2_clip32 __user *uclips;
+-              struct v4l2_clip __user *kclips;
+-              int n = kp->clipcount;
+-              compat_caddr_t p;
++      if (!kp->clipcount) {
++              kp->clips = NULL;
++              return 0;
++      }
+-              if (get_user(p, &up->clips))
++      n = kp->clipcount;
++      if (get_user(p, &up->clips))
++              return -EFAULT;
++      uclips = compat_ptr(p);
++      kclips = compat_alloc_user_space(n * sizeof(*kclips));
++      kp->clips = kclips;
++      while (n--) {
++              if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
+                       return -EFAULT;
+-              uclips = compat_ptr(p);
+-              kclips = compat_alloc_user_space(n * sizeof(*kclips));
+-              kp->clips = kclips;
+-              while (--n >= 0) {
+-                      if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
+-                              return -EFAULT;
+-                      if (put_user(n ? kclips + 1 : NULL, &kclips->next))
+-                              return -EFAULT;
+-                      uclips += 1;
+-                      kclips += 1;
+-              }
+-      } else
+-              kp->clips = NULL;
++              if (put_user(n ? kclips + 1 : NULL, &kclips->next))
++                      return -EFAULT;
++              uclips++;
++              kclips++;
++      }
+       return 0;
+ }
+ static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+ {
++      struct v4l2_clip __user *kclips = kp->clips;
++      struct v4l2_clip32 __user *uclips;
++      u32 n = kp->clipcount;
++      compat_caddr_t p;
++
+       if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) ||
+           put_user(kp->field, &up->field) ||
+           put_user(kp->chromakey, &up->chromakey) ||
+           put_user(kp->clipcount, &up->clipcount) ||
+           put_user(kp->global_alpha, &up->global_alpha))
+               return -EFAULT;
++
++      if (!kp->clipcount)
++              return 0;
++
++      if (get_user(p, &up->clips))
++              return -EFAULT;
++      uclips = compat_ptr(p);
++      while (n--) {
++              if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c)))
++                      return -EFAULT;
++              uclips++;
++              kclips++;
++      }
+       return 0;
+ }
diff --git a/queue-4.4/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch b/queue-4.4/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch
new file mode 100644 (file)
index 0000000..81b0e9b
--- /dev/null
@@ -0,0 +1,132 @@
+From foo@baz Thu Feb 15 08:44:17 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:52:33 +0100
+Subject: media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214115240.27650-8-hverkuil@xs4all.nl>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit 8ed5a59dcb47a6f76034ee760b36e089f3e82529 upstream.
+
+The struct v4l2_plane32 should set m.userptr as well. The same
+happens in v4l2_buffer32 and v4l2-compliance tests for this.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c |   47 +++++++++++++++-----------
+ 1 file changed, 28 insertions(+), 19 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -299,19 +299,24 @@ static int get_v4l2_plane32(struct v4l2_
+                        sizeof(up->data_offset)))
+               return -EFAULT;
+-      if (memory == V4L2_MEMORY_USERPTR) {
++      switch (memory) {
++      case V4L2_MEMORY_MMAP:
++      case V4L2_MEMORY_OVERLAY:
++              if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
++                               sizeof(up32->m.mem_offset)))
++                      return -EFAULT;
++              break;
++      case V4L2_MEMORY_USERPTR:
+               if (get_user(p, &up32->m.userptr))
+                       return -EFAULT;
+               up_pln = compat_ptr(p);
+               if (put_user((unsigned long)up_pln, &up->m.userptr))
+                       return -EFAULT;
+-      } else if (memory == V4L2_MEMORY_DMABUF) {
++              break;
++      case V4L2_MEMORY_DMABUF:
+               if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd)))
+                       return -EFAULT;
+-      } else {
+-              if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
+-                               sizeof(up32->m.mem_offset)))
+-                      return -EFAULT;
++              break;
+       }
+       return 0;
+@@ -320,22 +325,32 @@ static int get_v4l2_plane32(struct v4l2_
+ static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
+                           enum v4l2_memory memory)
+ {
++      unsigned long p;
++
+       if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
+           copy_in_user(&up32->data_offset, &up->data_offset,
+                        sizeof(up->data_offset)))
+               return -EFAULT;
+-      /* For MMAP, driver might've set up the offset, so copy it back.
+-       * USERPTR stays the same (was userspace-provided), so no copying. */
+-      if (memory == V4L2_MEMORY_MMAP)
++      switch (memory) {
++      case V4L2_MEMORY_MMAP:
++      case V4L2_MEMORY_OVERLAY:
+               if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
+                                sizeof(up->m.mem_offset)))
+                       return -EFAULT;
+-      /* For DMABUF, driver might've set up the fd, so copy it back. */
+-      if (memory == V4L2_MEMORY_DMABUF)
++              break;
++      case V4L2_MEMORY_USERPTR:
++              if (get_user(p, &up->m.userptr) ||
++                  put_user((compat_ulong_t)ptr_to_compat((__force void *)p),
++                           &up32->m.userptr))
++                      return -EFAULT;
++              break;
++      case V4L2_MEMORY_DMABUF:
+               if (copy_in_user(&up32->m.fd, &up->m.fd,
+                                sizeof(up->m.fd)))
+                       return -EFAULT;
++              break;
++      }
+       return 0;
+ }
+@@ -395,6 +410,7 @@ static int get_v4l2_buffer32(struct v4l2
+       } else {
+               switch (kp->memory) {
+               case V4L2_MEMORY_MMAP:
++              case V4L2_MEMORY_OVERLAY:
+                       if (get_user(kp->m.offset, &up->m.offset))
+                               return -EFAULT;
+                       break;
+@@ -408,10 +424,6 @@ static int get_v4l2_buffer32(struct v4l2
+                               kp->m.userptr = (unsigned long)compat_ptr(tmp);
+                       }
+                       break;
+-              case V4L2_MEMORY_OVERLAY:
+-                      if (get_user(kp->m.offset, &up->m.offset))
+-                              return -EFAULT;
+-                      break;
+               case V4L2_MEMORY_DMABUF:
+                       if (get_user(kp->m.fd, &up->m.fd))
+                               return -EFAULT;
+@@ -468,6 +480,7 @@ static int put_v4l2_buffer32(struct v4l2
+       } else {
+               switch (kp->memory) {
+               case V4L2_MEMORY_MMAP:
++              case V4L2_MEMORY_OVERLAY:
+                       if (put_user(kp->m.offset, &up->m.offset))
+                               return -EFAULT;
+                       break;
+@@ -475,10 +488,6 @@ static int put_v4l2_buffer32(struct v4l2
+                       if (put_user(kp->m.userptr, &up->m.userptr))
+                               return -EFAULT;
+                       break;
+-              case V4L2_MEMORY_OVERLAY:
+-                      if (put_user(kp->m.offset, &up->m.offset))
+-                              return -EFAULT;
+-                      break;
+               case V4L2_MEMORY_DMABUF:
+                       if (put_user(kp->m.fd, &up->m.fd))
+                               return -EFAULT;
diff --git a/queue-4.4/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch b/queue-4.4/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch
new file mode 100644 (file)
index 0000000..4896af5
--- /dev/null
@@ -0,0 +1,36 @@
+From foo@baz Thu Feb 15 08:44:17 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:52:39 +0100
+Subject: media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214115240.27650-14-hverkuil@xs4all.nl>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit d83a8243aaefe62ace433e4384a4f077bed86acb upstream.
+
+Some ioctls need to copy back the result even if the ioctl returned
+an error. However, don't do this for the error code -ENOTTY.
+It makes no sense in that cases.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -956,6 +956,9 @@ static long do_video_ioctl(struct file *
+               set_fs(old_fs);
+       }
++      if (err == -ENOTTY)
++              return err;
++
+       /* Special case: even after an error we need to put the
+          results back for these ioctls since the error_idx will
+          contain information on which control failed. */
diff --git a/queue-4.4/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch b/queue-4.4/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch
new file mode 100644 (file)
index 0000000..25c9fee
--- /dev/null
@@ -0,0 +1,44 @@
+From foo@baz Thu Feb 15 08:44:17 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:52:38 +0100
+Subject: media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214115240.27650-13-hverkuil@xs4all.nl>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit 169f24ca68bf0f247d111aef07af00dd3a02ae88 upstream.
+
+There is nothing wrong with using an unknown buffer type. So
+stop spamming the kernel log whenever this happens. The kernel
+will just return -EINVAL to signal this.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c |    4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -175,8 +175,6 @@ static int __get_v4l2_format32(struct v4
+               return copy_from_user(&kp->fmt.sdr, &up->fmt.sdr,
+                                     sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
+       default:
+-              pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+-                      kp->type);
+               return -EINVAL;
+       }
+ }
+@@ -226,8 +224,6 @@ static int __put_v4l2_format32(struct v4
+               return copy_to_user(&up->fmt.sdr, &kp->fmt.sdr,
+                                   sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
+       default:
+-              pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+-                      kp->type);
+               return -EINVAL;
+       }
+ }
diff --git a/queue-4.4/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch b/queue-4.4/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch
new file mode 100644 (file)
index 0000000..347416d
--- /dev/null
@@ -0,0 +1,144 @@
+From foo@baz Thu Feb 15 08:44:17 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:52:34 +0100
+Subject: media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214115240.27650-9-hverkuil@xs4all.nl>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit b8c601e8af2d08f733d74defa8465303391bb930 upstream.
+
+ctrl_is_pointer just hardcoded two known string controls, but that
+caused problems when using e.g. custom controls that use a pointer
+for the payload.
+
+Reimplement this function: it now finds the v4l2_ctrl (if the driver
+uses the control framework) or it calls vidioc_query_ext_ctrl (if the
+driver implements that directly).
+
+In both cases it can now check if the control is a pointer control
+or not.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c |   59 +++++++++++++++++---------
+ 1 file changed, 39 insertions(+), 20 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -18,6 +18,8 @@
+ #include <linux/videodev2.h>
+ #include <linux/v4l2-subdev.h>
+ #include <media/v4l2-dev.h>
++#include <media/v4l2-fh.h>
++#include <media/v4l2-ctrls.h>
+ #include <media/v4l2-ioctl.h>
+ static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+@@ -587,24 +589,39 @@ struct v4l2_ext_control32 {
+       };
+ } __attribute__ ((packed));
+-/* The following function really belong in v4l2-common, but that causes
+-   a circular dependency between modules. We need to think about this, but
+-   for now this will do. */
+-
+-/* Return non-zero if this control is a pointer type. Currently only
+-   type STRING is a pointer type. */
+-static inline int ctrl_is_pointer(u32 id)
+-{
+-      switch (id) {
+-      case V4L2_CID_RDS_TX_PS_NAME:
+-      case V4L2_CID_RDS_TX_RADIO_TEXT:
+-              return 1;
+-      default:
+-              return 0;
++/* Return true if this control is a pointer type. */
++static inline bool ctrl_is_pointer(struct file *file, u32 id)
++{
++      struct video_device *vdev = video_devdata(file);
++      struct v4l2_fh *fh = NULL;
++      struct v4l2_ctrl_handler *hdl = NULL;
++      struct v4l2_query_ext_ctrl qec = { id };
++      const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops;
++
++      if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
++              fh = file->private_data;
++
++      if (fh && fh->ctrl_handler)
++              hdl = fh->ctrl_handler;
++      else if (vdev->ctrl_handler)
++              hdl = vdev->ctrl_handler;
++
++      if (hdl) {
++              struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id);
++
++              return ctrl && ctrl->is_ptr;
+       }
++
++      if (!ops->vidioc_query_ext_ctrl)
++              return false;
++
++      return !ops->vidioc_query_ext_ctrl(file, fh, &qec) &&
++              (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD);
+ }
+-static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
++static int get_v4l2_ext_controls32(struct file *file,
++                                 struct v4l2_ext_controls *kp,
++                                 struct v4l2_ext_controls32 __user *up)
+ {
+       struct v4l2_ext_control32 __user *ucontrols;
+       struct v4l2_ext_control __user *kcontrols;
+@@ -636,7 +653,7 @@ static int get_v4l2_ext_controls32(struc
+                       return -EFAULT;
+               if (get_user(id, &kcontrols->id))
+                       return -EFAULT;
+-              if (ctrl_is_pointer(id)) {
++              if (ctrl_is_pointer(file, id)) {
+                       void __user *s;
+                       if (get_user(p, &ucontrols->string))
+@@ -651,7 +668,9 @@ static int get_v4l2_ext_controls32(struc
+       return 0;
+ }
+-static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
++static int put_v4l2_ext_controls32(struct file *file,
++                                 struct v4l2_ext_controls *kp,
++                                 struct v4l2_ext_controls32 __user *up)
+ {
+       struct v4l2_ext_control32 __user *ucontrols;
+       struct v4l2_ext_control __user *kcontrols =
+@@ -683,7 +702,7 @@ static int put_v4l2_ext_controls32(struc
+               /* Do not modify the pointer when copying a pointer control.
+                  The contents of the pointer was changed, not the pointer
+                  itself. */
+-              if (ctrl_is_pointer(id))
++              if (ctrl_is_pointer(file, id))
+                       size -= sizeof(ucontrols->value64);
+               if (copy_in_user(ucontrols, kcontrols, size))
+                       return -EFAULT;
+@@ -897,7 +916,7 @@ static long do_video_ioctl(struct file *
+       case VIDIOC_G_EXT_CTRLS:
+       case VIDIOC_S_EXT_CTRLS:
+       case VIDIOC_TRY_EXT_CTRLS:
+-              err = get_v4l2_ext_controls32(&karg.v2ecs, up);
++              err = get_v4l2_ext_controls32(file, &karg.v2ecs, up);
+               compatible_arg = 0;
+               break;
+       case VIDIOC_DQEVENT:
+@@ -924,7 +943,7 @@ static long do_video_ioctl(struct file *
+       case VIDIOC_G_EXT_CTRLS:
+       case VIDIOC_S_EXT_CTRLS:
+       case VIDIOC_TRY_EXT_CTRLS:
+-              if (put_v4l2_ext_controls32(&karg.v2ecs, up))
++              if (put_v4l2_ext_controls32(file, &karg.v2ecs, up))
+                       err = -EFAULT;
+               break;
+       }
diff --git a/queue-4.4/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch b/queue-4.4/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch
new file mode 100644 (file)
index 0000000..c310039
--- /dev/null
@@ -0,0 +1,430 @@
+From foo@baz Thu Feb 15 08:44:17 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:52:30 +0100
+Subject: media: v4l2-compat-ioctl32.c: fix the indentation
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214115240.27650-5-hverkuil@xs4all.nl>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit b7b957d429f601d6d1942122b339474f31191d75 upstream.
+
+The indentation of this source is all over the place. Fix this.
+This patch only changes whitespace.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c |  208 +++++++++++++-------------
+ 1 file changed, 104 insertions(+), 104 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -48,11 +48,11 @@ struct v4l2_window32 {
+ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+ {
+       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) ||
+-              copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
+-              get_user(kp->field, &up->field) ||
+-              get_user(kp->chromakey, &up->chromakey) ||
+-              get_user(kp->clipcount, &up->clipcount))
+-                      return -EFAULT;
++          copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
++          get_user(kp->field, &up->field) ||
++          get_user(kp->chromakey, &up->chromakey) ||
++          get_user(kp->clipcount, &up->clipcount))
++              return -EFAULT;
+       if (kp->clipcount > 2048)
+               return -EINVAL;
+       if (kp->clipcount) {
+@@ -82,10 +82,10 @@ static int get_v4l2_window32(struct v4l2
+ static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+ {
+       if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) ||
+-              put_user(kp->field, &up->field) ||
+-              put_user(kp->chromakey, &up->chromakey) ||
+-              put_user(kp->clipcount, &up->clipcount))
+-                      return -EFAULT;
++          put_user(kp->field, &up->field) ||
++          put_user(kp->chromakey, &up->chromakey) ||
++          put_user(kp->clipcount, &up->clipcount))
++              return -EFAULT;
+       return 0;
+ }
+@@ -97,7 +97,7 @@ static inline int get_v4l2_pix_format(st
+ }
+ static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
+-                              struct v4l2_pix_format_mplane __user *up)
++                                           struct v4l2_pix_format_mplane __user *up)
+ {
+       if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane)))
+               return -EFAULT;
+@@ -112,7 +112,7 @@ static inline int put_v4l2_pix_format(st
+ }
+ static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
+-                              struct v4l2_pix_format_mplane __user *up)
++                                           struct v4l2_pix_format_mplane __user *up)
+ {
+       if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane)))
+               return -EFAULT;
+@@ -218,7 +218,7 @@ static int __get_v4l2_format32(struct v4
+               return get_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr);
+       default:
+               pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+-                                                              kp->type);
++                      kp->type);
+               return -EINVAL;
+       }
+ }
+@@ -265,7 +265,7 @@ static int __put_v4l2_format32(struct v4
+               return put_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr);
+       default:
+               pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+-                                                              kp->type);
++                      kp->type);
+               return -EINVAL;
+       }
+ }
+@@ -299,7 +299,7 @@ static int get_v4l2_standard32(struct v4
+ {
+       /* other fields are not set by the user, nor used by the driver */
+       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
+-              get_user(kp->index, &up->index))
++          get_user(kp->index, &up->index))
+               return -EFAULT;
+       return 0;
+ }
+@@ -307,13 +307,13 @@ static int get_v4l2_standard32(struct v4
+ static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+ {
+       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
+-              put_user(kp->index, &up->index) ||
+-              put_user(kp->id, &up->id) ||
+-              copy_to_user(up->name, kp->name, 24) ||
+-              copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
+-              put_user(kp->framelines, &up->framelines) ||
+-              copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
+-                      return -EFAULT;
++          put_user(kp->index, &up->index) ||
++          put_user(kp->id, &up->id) ||
++          copy_to_user(up->name, kp->name, 24) ||
++          copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
++          put_user(kp->framelines, &up->framelines) ||
++          copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
++              return -EFAULT;
+       return 0;
+ }
+@@ -353,14 +353,14 @@ struct v4l2_buffer32 {
+ };
+ static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
+-                              enum v4l2_memory memory)
++                          enum v4l2_memory memory)
+ {
+       void __user *up_pln;
+       compat_long_t p;
+       if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
+-              copy_in_user(&up->data_offset, &up32->data_offset,
+-                              sizeof(__u32)))
++          copy_in_user(&up->data_offset, &up32->data_offset,
++                       sizeof(__u32)))
+               return -EFAULT;
+       if (memory == V4L2_MEMORY_USERPTR) {
+@@ -374,7 +374,7 @@ static int get_v4l2_plane32(struct v4l2_
+                       return -EFAULT;
+       } else {
+               if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
+-                                      sizeof(__u32)))
++                               sizeof(__u32)))
+                       return -EFAULT;
+       }
+@@ -382,23 +382,23 @@ static int get_v4l2_plane32(struct v4l2_
+ }
+ static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
+-                              enum v4l2_memory memory)
++                          enum v4l2_memory memory)
+ {
+       if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
+-              copy_in_user(&up32->data_offset, &up->data_offset,
+-                              sizeof(__u32)))
++          copy_in_user(&up32->data_offset, &up->data_offset,
++                       sizeof(__u32)))
+               return -EFAULT;
+       /* For MMAP, driver might've set up the offset, so copy it back.
+        * USERPTR stays the same (was userspace-provided), so no copying. */
+       if (memory == V4L2_MEMORY_MMAP)
+               if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
+-                                      sizeof(__u32)))
++                               sizeof(__u32)))
+                       return -EFAULT;
+       /* For DMABUF, driver might've set up the fd, so copy it back. */
+       if (memory == V4L2_MEMORY_DMABUF)
+               if (copy_in_user(&up32->m.fd, &up->m.fd,
+-                                      sizeof(int)))
++                               sizeof(int)))
+                       return -EFAULT;
+       return 0;
+@@ -413,19 +413,19 @@ static int get_v4l2_buffer32(struct v4l2
+       int ret;
+       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
+-              get_user(kp->index, &up->index) ||
+-              get_user(kp->type, &up->type) ||
+-              get_user(kp->flags, &up->flags) ||
+-              get_user(kp->memory, &up->memory) ||
+-              get_user(kp->length, &up->length))
+-                      return -EFAULT;
++          get_user(kp->index, &up->index) ||
++          get_user(kp->type, &up->type) ||
++          get_user(kp->flags, &up->flags) ||
++          get_user(kp->memory, &up->memory) ||
++          get_user(kp->length, &up->length))
++              return -EFAULT;
+       if (V4L2_TYPE_IS_OUTPUT(kp->type))
+               if (get_user(kp->bytesused, &up->bytesused) ||
+-                      get_user(kp->field, &up->field) ||
+-                      get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+-                      get_user(kp->timestamp.tv_usec,
+-                                      &up->timestamp.tv_usec))
++                  get_user(kp->field, &up->field) ||
++                  get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
++                  get_user(kp->timestamp.tv_usec,
++                           &up->timestamp.tv_usec))
+                       return -EFAULT;
+       if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
+@@ -442,13 +442,13 @@ static int get_v4l2_buffer32(struct v4l2
+               uplane32 = compat_ptr(p);
+               if (!access_ok(VERIFY_READ, uplane32,
+-                              num_planes * sizeof(struct v4l2_plane32)))
++                             num_planes * sizeof(struct v4l2_plane32)))
+                       return -EFAULT;
+               /* We don't really care if userspace decides to kill itself
+                * by passing a very big num_planes value */
+               uplane = compat_alloc_user_space(num_planes *
+-                                              sizeof(struct v4l2_plane));
++                                               sizeof(struct v4l2_plane));
+               kp->m.planes = (__force struct v4l2_plane *)uplane;
+               while (--num_planes >= 0) {
+@@ -466,12 +466,12 @@ static int get_v4l2_buffer32(struct v4l2
+                       break;
+               case V4L2_MEMORY_USERPTR:
+                       {
+-                      compat_long_t tmp;
++                              compat_long_t tmp;
+-                      if (get_user(tmp, &up->m.userptr))
+-                              return -EFAULT;
++                              if (get_user(tmp, &up->m.userptr))
++                                      return -EFAULT;
+-                      kp->m.userptr = (unsigned long)compat_ptr(tmp);
++                              kp->m.userptr = (unsigned long)compat_ptr(tmp);
+                       }
+                       break;
+               case V4L2_MEMORY_OVERLAY:
+@@ -497,22 +497,22 @@ static int put_v4l2_buffer32(struct v4l2
+       int ret;
+       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
+-              put_user(kp->index, &up->index) ||
+-              put_user(kp->type, &up->type) ||
+-              put_user(kp->flags, &up->flags) ||
+-              put_user(kp->memory, &up->memory))
+-                      return -EFAULT;
++          put_user(kp->index, &up->index) ||
++          put_user(kp->type, &up->type) ||
++          put_user(kp->flags, &up->flags) ||
++          put_user(kp->memory, &up->memory))
++              return -EFAULT;
+       if (put_user(kp->bytesused, &up->bytesused) ||
+-              put_user(kp->field, &up->field) ||
+-              put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+-              put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
+-              copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
+-              put_user(kp->sequence, &up->sequence) ||
+-              put_user(kp->reserved2, &up->reserved2) ||
+-              put_user(kp->reserved, &up->reserved) ||
+-              put_user(kp->length, &up->length))
+-                      return -EFAULT;
++          put_user(kp->field, &up->field) ||
++          put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
++          put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
++          copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
++          put_user(kp->sequence, &up->sequence) ||
++          put_user(kp->reserved2, &up->reserved2) ||
++          put_user(kp->reserved, &up->reserved) ||
++          put_user(kp->length, &up->length))
++              return -EFAULT;
+       if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
+               num_planes = kp->length;
+@@ -576,11 +576,11 @@ static int get_v4l2_framebuffer32(struct
+       u32 tmp;
+       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) ||
+-              get_user(tmp, &up->base) ||
+-              get_user(kp->capability, &up->capability) ||
+-              get_user(kp->flags, &up->flags) ||
+-              copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt)))
+-                      return -EFAULT;
++          get_user(tmp, &up->base) ||
++          get_user(kp->capability, &up->capability) ||
++          get_user(kp->flags, &up->flags) ||
++          copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt)))
++              return -EFAULT;
+       kp->base = (__force void *)compat_ptr(tmp);
+       return 0;
+ }
+@@ -590,11 +590,11 @@ static int put_v4l2_framebuffer32(struct
+       u32 tmp = (u32)((unsigned long)kp->base);
+       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
+-              put_user(tmp, &up->base) ||
+-              put_user(kp->capability, &up->capability) ||
+-              put_user(kp->flags, &up->flags) ||
+-              copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt)))
+-                      return -EFAULT;
++          put_user(tmp, &up->base) ||
++          put_user(kp->capability, &up->capability) ||
++          put_user(kp->flags, &up->flags) ||
++          copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt)))
++              return -EFAULT;
+       return 0;
+ }
+@@ -669,12 +669,12 @@ static int get_v4l2_ext_controls32(struc
+       compat_caddr_t p;
+       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
+-              get_user(kp->ctrl_class, &up->ctrl_class) ||
+-              get_user(kp->count, &up->count) ||
+-              get_user(kp->error_idx, &up->error_idx) ||
+-              copy_from_user(kp->reserved, up->reserved,
+-                             sizeof(kp->reserved)))
+-                      return -EFAULT;
++          get_user(kp->ctrl_class, &up->ctrl_class) ||
++          get_user(kp->count, &up->count) ||
++          get_user(kp->error_idx, &up->error_idx) ||
++          copy_from_user(kp->reserved, up->reserved,
++                         sizeof(kp->reserved)))
++              return -EFAULT;
+       n = kp->count;
+       if (n == 0) {
+               kp->controls = NULL;
+@@ -684,7 +684,7 @@ static int get_v4l2_ext_controls32(struc
+               return -EFAULT;
+       ucontrols = compat_ptr(p);
+       if (!access_ok(VERIFY_READ, ucontrols,
+-                      n * sizeof(struct v4l2_ext_control32)))
++                     n * sizeof(struct v4l2_ext_control32)))
+               return -EFAULT;
+       kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
+       kp->controls = (__force struct v4l2_ext_control *)kcontrols;
+@@ -719,11 +719,11 @@ static int put_v4l2_ext_controls32(struc
+       compat_caddr_t p;
+       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
+-              put_user(kp->ctrl_class, &up->ctrl_class) ||
+-              put_user(kp->count, &up->count) ||
+-              put_user(kp->error_idx, &up->error_idx) ||
+-              copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+-                      return -EFAULT;
++          put_user(kp->ctrl_class, &up->ctrl_class) ||
++          put_user(kp->count, &up->count) ||
++          put_user(kp->error_idx, &up->error_idx) ||
++          copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
++              return -EFAULT;
+       if (!kp->count)
+               return 0;
+@@ -731,7 +731,7 @@ static int put_v4l2_ext_controls32(struc
+               return -EFAULT;
+       ucontrols = compat_ptr(p);
+       if (!access_ok(VERIFY_WRITE, ucontrols,
+-                      n * sizeof(struct v4l2_ext_control32)))
++                     n * sizeof(struct v4l2_ext_control32)))
+               return -EFAULT;
+       while (--n >= 0) {
+@@ -769,15 +769,15 @@ struct v4l2_event32 {
+ static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up)
+ {
+       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) ||
+-              put_user(kp->type, &up->type) ||
+-              copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
+-              put_user(kp->pending, &up->pending) ||
+-              put_user(kp->sequence, &up->sequence) ||
+-              put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+-              put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) ||
+-              put_user(kp->id, &up->id) ||
+-              copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
+-                      return -EFAULT;
++          put_user(kp->type, &up->type) ||
++          copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
++          put_user(kp->pending, &up->pending) ||
++          put_user(kp->sequence, &up->sequence) ||
++          put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
++          put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) ||
++          put_user(kp->id, &up->id) ||
++          copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
++              return -EFAULT;
+       return 0;
+ }
+@@ -794,12 +794,12 @@ static int get_v4l2_edid32(struct v4l2_e
+       u32 tmp;
+       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) ||
+-              get_user(kp->pad, &up->pad) ||
+-              get_user(kp->start_block, &up->start_block) ||
+-              get_user(kp->blocks, &up->blocks) ||
+-              get_user(tmp, &up->edid) ||
+-              copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+-                      return -EFAULT;
++          get_user(kp->pad, &up->pad) ||
++          get_user(kp->start_block, &up->start_block) ||
++          get_user(kp->blocks, &up->blocks) ||
++          get_user(tmp, &up->edid) ||
++          copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
++              return -EFAULT;
+       kp->edid = (__force u8 *)compat_ptr(tmp);
+       return 0;
+ }
+@@ -809,12 +809,12 @@ static int put_v4l2_edid32(struct v4l2_e
+       u32 tmp = (u32)((unsigned long)kp->edid);
+       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) ||
+-              put_user(kp->pad, &up->pad) ||
+-              put_user(kp->start_block, &up->start_block) ||
+-              put_user(kp->blocks, &up->blocks) ||
+-              put_user(tmp, &up->edid) ||
+-              copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+-                      return -EFAULT;
++          put_user(kp->pad, &up->pad) ||
++          put_user(kp->start_block, &up->start_block) ||
++          put_user(kp->blocks, &up->blocks) ||
++          put_user(tmp, &up->edid) ||
++          copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
++              return -EFAULT;
+       return 0;
+ }
diff --git a/queue-4.4/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch b/queue-4.4/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch
new file mode 100644 (file)
index 0000000..97e24a8
--- /dev/null
@@ -0,0 +1,43 @@
+From foo@baz Thu Feb 15 08:44:17 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:52:35 +0100
+Subject: media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214115240.27650-10-hverkuil@xs4all.nl>
+
+From: Hans Verkuil <hansverk@cisco.com>
+
+commit 273caa260035c03d89ad63d72d8cd3d9e5c5e3f1 upstream.
+
+If the device is of type VFL_TYPE_SUBDEV then vdev->ioctl_ops
+is NULL so the 'if (!ops->vidioc_query_ext_ctrl)' check would crash.
+Add a test for !ops to the condition.
+
+All sub-devices that have controls will use the control framework,
+so they do not have an equivalent to ops->vidioc_query_ext_ctrl.
+Returning false if ops is NULL is the correct thing to do here.
+
+Fixes: b8c601e8af ("v4l2-compat-ioctl32.c: fix ctrl_is_pointer")
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Reported-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -612,7 +612,7 @@ static inline bool ctrl_is_pointer(struc
+               return ctrl && ctrl->is_ptr;
+       }
+-      if (!ops->vidioc_query_ext_ctrl)
++      if (!ops || !ops->vidioc_query_ext_ctrl)
+               return false;
+       return !ops->vidioc_query_ext_ctrl(file, fh, &qec) &&
diff --git a/queue-4.4/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch b/queue-4.4/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch
new file mode 100644 (file)
index 0000000..066d03c
--- /dev/null
@@ -0,0 +1,172 @@
+From foo@baz Thu Feb 15 08:44:17 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:52:31 +0100
+Subject: media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214115240.27650-6-hverkuil@xs4all.nl>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit 486c521510c44a04cd756a9267e7d1e271c8a4ba upstream.
+
+These helper functions do not really help. Move the code to the
+__get/put_v4l2_format32 functions.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c |  104 +++++---------------------
+ 1 file changed, 20 insertions(+), 84 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -89,78 +89,6 @@ static int put_v4l2_window32(struct v4l2
+       return 0;
+ }
+-static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
+-{
+-      if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format)))
+-              return -EFAULT;
+-      return 0;
+-}
+-
+-static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
+-                                           struct v4l2_pix_format_mplane __user *up)
+-{
+-      if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane)))
+-              return -EFAULT;
+-      return 0;
+-}
+-
+-static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
+-{
+-      if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
+-              return -EFAULT;
+-      return 0;
+-}
+-
+-static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
+-                                           struct v4l2_pix_format_mplane __user *up)
+-{
+-      if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane)))
+-              return -EFAULT;
+-      return 0;
+-}
+-
+-static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
+-{
+-      if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
+-              return -EFAULT;
+-      return 0;
+-}
+-
+-static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
+-{
+-      if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format)))
+-              return -EFAULT;
+-      return 0;
+-}
+-
+-static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
+-{
+-      if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
+-              return -EFAULT;
+-      return 0;
+-}
+-
+-static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
+-{
+-      if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
+-              return -EFAULT;
+-      return 0;
+-}
+-
+-static inline int get_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up)
+-{
+-      if (copy_from_user(kp, up, sizeof(struct v4l2_sdr_format)))
+-              return -EFAULT;
+-      return 0;
+-}
+-
+-static inline int put_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up)
+-{
+-      if (copy_to_user(up, kp, sizeof(struct v4l2_sdr_format)))
+-              return -EFAULT;
+-      return 0;
+-}
+-
+ struct v4l2_format32 {
+       __u32   type;   /* enum v4l2_buf_type */
+       union {
+@@ -199,23 +127,27 @@ static int __get_v4l2_format32(struct v4
+       switch (kp->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+-              return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
++              return copy_from_user(&kp->fmt.pix, &up->fmt.pix,
++                                    sizeof(kp->fmt.pix)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+-              return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
+-                                                &up->fmt.pix_mp);
++              return copy_from_user(&kp->fmt.pix_mp, &up->fmt.pix_mp,
++                                    sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+               return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_VBI_OUTPUT:
+-              return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
++              return copy_from_user(&kp->fmt.vbi, &up->fmt.vbi,
++                                    sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+-              return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
++              return copy_from_user(&kp->fmt.sliced, &up->fmt.sliced,
++                                    sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_SDR_CAPTURE:
+       case V4L2_BUF_TYPE_SDR_OUTPUT:
+-              return get_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr);
++              return copy_from_user(&kp->fmt.sdr, &up->fmt.sdr,
++                                    sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
+       default:
+               pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+                       kp->type);
+@@ -246,23 +178,27 @@ static int __put_v4l2_format32(struct v4
+       switch (kp->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+-              return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
++              return copy_to_user(&up->fmt.pix, &kp->fmt.pix,
++                                  sizeof(kp->fmt.pix)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+-              return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
+-                                                &up->fmt.pix_mp);
++              return copy_to_user(&up->fmt.pix_mp, &kp->fmt.pix_mp,
++                                  sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+               return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_VBI_OUTPUT:
+-              return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
++              return copy_to_user(&up->fmt.vbi, &kp->fmt.vbi,
++                                  sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+-              return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
++              return copy_to_user(&up->fmt.sliced, &kp->fmt.sliced,
++                                  sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_SDR_CAPTURE:
+       case V4L2_BUF_TYPE_SDR_OUTPUT:
+-              return put_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr);
++              return copy_to_user(&up->fmt.sdr, &kp->fmt.sdr,
++                                  sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
+       default:
+               pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+                       kp->type);
diff --git a/queue-4.4/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch b/queue-4.4/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch
new file mode 100644 (file)
index 0000000..33d80de
--- /dev/null
@@ -0,0 +1,1323 @@
+From foo@baz Thu Feb 15 08:44:17 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:52:40 +0100
+Subject: media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Daniel Mentz <danielmentz@google.com>, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214115240.27650-15-hverkuil@xs4all.nl>
+
+From: Daniel Mentz <danielmentz@google.com>
+
+commit a1dfb4c48cc1e64eeb7800a27c66a6f7e88d075a upstream.
+
+The 32-bit compat v4l2 ioctl handling is implemented based on its 64-bit
+equivalent. It converts 32-bit data structures into its 64-bit
+equivalents and needs to provide the data to the 64-bit ioctl in user
+space memory which is commonly allocated using
+compat_alloc_user_space().
+
+However, due to how that function is implemented, it can only be called
+a single time for every syscall invocation.
+
+Supposedly to avoid this limitation, the existing code uses a mix of
+memory from the kernel stack and memory allocated through
+compat_alloc_user_space().
+
+Under normal circumstances, this would not work, because the 64-bit
+ioctl expects all pointers to point to user space memory. As a
+workaround, set_fs(KERNEL_DS) is called to temporarily disable this
+extra safety check and allow kernel pointers. However, this might
+introduce a security vulnerability: The result of the 32-bit to 64-bit
+conversion is writeable by user space because the output buffer has been
+allocated via compat_alloc_user_space(). A malicious user space process
+could then manipulate pointers inside this output buffer, and due to the
+previous set_fs(KERNEL_DS) call, functions like get_user() or put_user()
+no longer prevent kernel memory access.
+
+The new approach is to pre-calculate the total amount of user space
+memory that is needed, allocate it using compat_alloc_user_space() and
+then divide up the allocated memory to accommodate all data structures
+that need to be converted.
+
+An alternative approach would have been to retain the union type karg
+that they allocated on the kernel stack in do_video_ioctl(), copy all
+data from user space into karg and then back to user space. However, we
+decided against this approach because it does not align with other
+compat syscall implementations. Instead, we tried to replicate the
+get_user/put_user pairs as found in other places in the kernel:
+
+    if (get_user(clipcount, &up->clipcount) ||
+        put_user(clipcount, &kp->clipcount)) return -EFAULT;
+
+Notes from hans.verkuil@cisco.com:
+
+This patch was taken from:
+    https://github.com/LineageOS/android_kernel_samsung_apq8084/commit/97b733953c06e4f0398ade18850f0817778255f7
+
+Clearly nobody could be bothered to upstream this patch or at minimum
+tell us :-( We only heard about this a week ago.
+
+This patch was rebased and cleaned up. Compared to the original I
+also swapped the order of the convert_in_user arguments so that they
+matched copy_in_user. It was hard to review otherwise. I also replaced
+the ALLOC_USER_SPACE/ALLOC_AND_GET by a normal function.
+
+Fixes: 6b5a9492ca ("v4l: introduce string control support.")
+
+Signed-off-by: Daniel Mentz <danielmentz@google.com>
+Co-developed-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-compat-ioctl32.c |  752 ++++++++++++++++----------
+ 1 file changed, 487 insertions(+), 265 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+@@ -22,6 +22,14 @@
+ #include <media/v4l2-ctrls.h>
+ #include <media/v4l2-ioctl.h>
++/* Use the same argument order as copy_in_user */
++#define assign_in_user(to, from)                                      \
++({                                                                    \
++      typeof(*from) __assign_tmp;                                     \
++                                                                      \
++      get_user(__assign_tmp, from) || put_user(__assign_tmp, to);     \
++})
++
+ static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ {
+       long ret = -ENOIOCTLCMD;
+@@ -35,12 +43,12 @@ static long native_ioctl(struct file *fi
+ struct v4l2_clip32 {
+       struct v4l2_rect        c;
+-      compat_caddr_t          next;
++      compat_caddr_t          next;
+ };
+ struct v4l2_window32 {
+       struct v4l2_rect        w;
+-      __u32                   field;  /* enum v4l2_field */
++      __u32                   field;  /* enum v4l2_field */
+       __u32                   chromakey;
+       compat_caddr_t          clips; /* actually struct v4l2_clip32 * */
+       __u32                   clipcount;
+@@ -48,37 +56,41 @@ struct v4l2_window32 {
+       __u8                    global_alpha;
+ };
+-static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
++static int get_v4l2_window32(struct v4l2_window __user *kp,
++                           struct v4l2_window32 __user *up,
++                           void __user *aux_buf, u32 aux_space)
+ {
+       struct v4l2_clip32 __user *uclips;
+       struct v4l2_clip __user *kclips;
+       compat_caddr_t p;
+-      u32 n;
++      u32 clipcount;
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+-          copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
+-          get_user(kp->field, &up->field) ||
+-          get_user(kp->chromakey, &up->chromakey) ||
+-          get_user(kp->clipcount, &up->clipcount) ||
+-          get_user(kp->global_alpha, &up->global_alpha))
++          copy_in_user(&kp->w, &up->w, sizeof(up->w)) ||
++          assign_in_user(&kp->field, &up->field) ||
++          assign_in_user(&kp->chromakey, &up->chromakey) ||
++          assign_in_user(&kp->global_alpha, &up->global_alpha) ||
++          get_user(clipcount, &up->clipcount) ||
++          put_user(clipcount, &kp->clipcount))
+               return -EFAULT;
+-      if (kp->clipcount > 2048)
++      if (clipcount > 2048)
+               return -EINVAL;
+-      if (!kp->clipcount) {
+-              kp->clips = NULL;
+-              return 0;
+-      }
++      if (!clipcount)
++              return put_user(NULL, &kp->clips);
+-      n = kp->clipcount;
+       if (get_user(p, &up->clips))
+               return -EFAULT;
+       uclips = compat_ptr(p);
+-      kclips = compat_alloc_user_space(n * sizeof(*kclips));
+-      kp->clips = kclips;
+-      while (n--) {
++      if (aux_space < clipcount * sizeof(*kclips))
++              return -EFAULT;
++      kclips = aux_buf;
++      if (put_user(kclips, &kp->clips))
++              return -EFAULT;
++
++      while (clipcount--) {
+               if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
+                       return -EFAULT;
+-              if (put_user(n ? kclips + 1 : NULL, &kclips->next))
++              if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next))
+                       return -EFAULT;
+               uclips++;
+               kclips++;
+@@ -86,27 +98,28 @@ static int get_v4l2_window32(struct v4l2
+       return 0;
+ }
+-static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
++static int put_v4l2_window32(struct v4l2_window __user *kp,
++                           struct v4l2_window32 __user *up)
+ {
+       struct v4l2_clip __user *kclips = kp->clips;
+       struct v4l2_clip32 __user *uclips;
+-      u32 n = kp->clipcount;
+       compat_caddr_t p;
++      u32 clipcount;
+-      if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) ||
+-          put_user(kp->field, &up->field) ||
+-          put_user(kp->chromakey, &up->chromakey) ||
+-          put_user(kp->clipcount, &up->clipcount) ||
+-          put_user(kp->global_alpha, &up->global_alpha))
++      if (copy_in_user(&up->w, &kp->w, sizeof(kp->w)) ||
++          assign_in_user(&up->field, &kp->field) ||
++          assign_in_user(&up->chromakey, &kp->chromakey) ||
++          assign_in_user(&up->global_alpha, &kp->global_alpha) ||
++          get_user(clipcount, &kp->clipcount) ||
++          put_user(clipcount, &up->clipcount))
+               return -EFAULT;
+-
+-      if (!kp->clipcount)
++      if (!clipcount)
+               return 0;
+       if (get_user(p, &up->clips))
+               return -EFAULT;
+       uclips = compat_ptr(p);
+-      while (n--) {
++      while (clipcount--) {
+               if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c)))
+                       return -EFAULT;
+               uclips++;
+@@ -145,101 +158,158 @@ struct v4l2_create_buffers32 {
+       __u32                   reserved[8];
+ };
+-static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
++static int __bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
++{
++      u32 type;
++
++      if (get_user(type, &up->type))
++              return -EFAULT;
++
++      switch (type) {
++      case V4L2_BUF_TYPE_VIDEO_OVERLAY:
++      case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
++              u32 clipcount;
++
++              if (get_user(clipcount, &up->fmt.win.clipcount))
++                      return -EFAULT;
++              if (clipcount > 2048)
++                      return -EINVAL;
++              *size = clipcount * sizeof(struct v4l2_clip);
++              return 0;
++      }
++      default:
++              *size = 0;
++              return 0;
++      }
++}
++
++static int bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
+ {
+-      if (get_user(kp->type, &up->type))
++      if (!access_ok(VERIFY_READ, up, sizeof(*up)))
+               return -EFAULT;
++      return __bufsize_v4l2_format(up, size);
++}
+-      switch (kp->type) {
++static int __get_v4l2_format32(struct v4l2_format __user *kp,
++                             struct v4l2_format32 __user *up,
++                             void __user *aux_buf, u32 aux_space)
++{
++      u32 type;
++
++      if (get_user(type, &up->type) || put_user(type, &kp->type))
++              return -EFAULT;
++
++      switch (type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+-              return copy_from_user(&kp->fmt.pix, &up->fmt.pix,
+-                                    sizeof(kp->fmt.pix)) ? -EFAULT : 0;
++              return copy_in_user(&kp->fmt.pix, &up->fmt.pix,
++                                  sizeof(kp->fmt.pix)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+-              return copy_from_user(&kp->fmt.pix_mp, &up->fmt.pix_mp,
+-                                    sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
++              return copy_in_user(&kp->fmt.pix_mp, &up->fmt.pix_mp,
++                                  sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+-              return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
++              return get_v4l2_window32(&kp->fmt.win, &up->fmt.win,
++                                       aux_buf, aux_space);
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_VBI_OUTPUT:
+-              return copy_from_user(&kp->fmt.vbi, &up->fmt.vbi,
+-                                    sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
++              return copy_in_user(&kp->fmt.vbi, &up->fmt.vbi,
++                                  sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+-              return copy_from_user(&kp->fmt.sliced, &up->fmt.sliced,
+-                                    sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
++              return copy_in_user(&kp->fmt.sliced, &up->fmt.sliced,
++                                  sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_SDR_CAPTURE:
+       case V4L2_BUF_TYPE_SDR_OUTPUT:
+-              return copy_from_user(&kp->fmt.sdr, &up->fmt.sdr,
+-                                    sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
++              return copy_in_user(&kp->fmt.sdr, &up->fmt.sdr,
++                                  sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
+       default:
+               return -EINVAL;
+       }
+ }
+-static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
++static int get_v4l2_format32(struct v4l2_format __user *kp,
++                           struct v4l2_format32 __user *up,
++                           void __user *aux_buf, u32 aux_space)
++{
++      if (!access_ok(VERIFY_READ, up, sizeof(*up)))
++              return -EFAULT;
++      return __get_v4l2_format32(kp, up, aux_buf, aux_space);
++}
++
++static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *up,
++                             u32 *size)
+ {
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)))
+               return -EFAULT;
+-      return __get_v4l2_format32(kp, up);
++      return __bufsize_v4l2_format(&up->format, size);
+ }
+-static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
++static int get_v4l2_create32(struct v4l2_create_buffers __user *kp,
++                           struct v4l2_create_buffers32 __user *up,
++                           void __user *aux_buf, u32 aux_space)
+ {
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+-          copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format)))
++          copy_in_user(kp, up,
++                       offsetof(struct v4l2_create_buffers32, format)))
+               return -EFAULT;
+-      return __get_v4l2_format32(&kp->format, &up->format);
++      return __get_v4l2_format32(&kp->format, &up->format,
++                                 aux_buf, aux_space);
+ }
+-static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
++static int __put_v4l2_format32(struct v4l2_format __user *kp,
++                             struct v4l2_format32 __user *up)
+ {
+-      if (put_user(kp->type, &up->type))
++      u32 type;
++
++      if (get_user(type, &kp->type))
+               return -EFAULT;
+-      switch (kp->type) {
++      switch (type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+-              return copy_to_user(&up->fmt.pix, &kp->fmt.pix,
++              return copy_in_user(&up->fmt.pix, &kp->fmt.pix,
+                                   sizeof(kp->fmt.pix)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+-              return copy_to_user(&up->fmt.pix_mp, &kp->fmt.pix_mp,
++              return copy_in_user(&up->fmt.pix_mp, &kp->fmt.pix_mp,
+                                   sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+               return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_VBI_OUTPUT:
+-              return copy_to_user(&up->fmt.vbi, &kp->fmt.vbi,
++              return copy_in_user(&up->fmt.vbi, &kp->fmt.vbi,
+                                   sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+-              return copy_to_user(&up->fmt.sliced, &kp->fmt.sliced,
++              return copy_in_user(&up->fmt.sliced, &kp->fmt.sliced,
+                                   sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
+       case V4L2_BUF_TYPE_SDR_CAPTURE:
+       case V4L2_BUF_TYPE_SDR_OUTPUT:
+-              return copy_to_user(&up->fmt.sdr, &kp->fmt.sdr,
++              return copy_in_user(&up->fmt.sdr, &kp->fmt.sdr,
+                                   sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
+       default:
+               return -EINVAL;
+       }
+ }
+-static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
++static int put_v4l2_format32(struct v4l2_format __user *kp,
++                           struct v4l2_format32 __user *up)
+ {
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
+               return -EFAULT;
+       return __put_v4l2_format32(kp, up);
+ }
+-static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
++static int put_v4l2_create32(struct v4l2_create_buffers __user *kp,
++                           struct v4l2_create_buffers32 __user *up)
+ {
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+-          copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) ||
+-          copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
++          copy_in_user(up, kp,
++                       offsetof(struct v4l2_create_buffers32, format)) ||
++          copy_in_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
+               return -EFAULT;
+       return __put_v4l2_format32(&kp->format, &up->format);
+ }
+@@ -253,24 +323,27 @@ struct v4l2_standard32 {
+       __u32                reserved[4];
+ };
+-static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
++static int get_v4l2_standard32(struct v4l2_standard __user *kp,
++                             struct v4l2_standard32 __user *up)
+ {
+       /* other fields are not set by the user, nor used by the driver */
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+-          get_user(kp->index, &up->index))
++          assign_in_user(&kp->index, &up->index))
+               return -EFAULT;
+       return 0;
+ }
+-static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
++static int put_v4l2_standard32(struct v4l2_standard __user *kp,
++                             struct v4l2_standard32 __user *up)
+ {
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+-          put_user(kp->index, &up->index) ||
+-          put_user(kp->id, &up->id) ||
+-          copy_to_user(up->name, kp->name, sizeof(up->name)) ||
+-          copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
+-          put_user(kp->framelines, &up->framelines) ||
+-          copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
++          assign_in_user(&up->index, &kp->index) ||
++          assign_in_user(&up->id, &kp->id) ||
++          copy_in_user(up->name, kp->name, sizeof(up->name)) ||
++          copy_in_user(&up->frameperiod, &kp->frameperiod,
++                       sizeof(up->frameperiod)) ||
++          assign_in_user(&up->framelines, &kp->framelines) ||
++          copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+               return -EFAULT;
+       return 0;
+ }
+@@ -310,11 +383,11 @@ struct v4l2_buffer32 {
+       __u32                   reserved;
+ };
+-static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
++static int get_v4l2_plane32(struct v4l2_plane __user *up,
++                          struct v4l2_plane32 __user *up32,
+                           enum v4l2_memory memory)
+ {
+-      void __user *up_pln;
+-      compat_long_t p;
++      compat_ulong_t p;
+       if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
+           copy_in_user(&up->data_offset, &up32->data_offset,
+@@ -329,10 +402,8 @@ static int get_v4l2_plane32(struct v4l2_
+                       return -EFAULT;
+               break;
+       case V4L2_MEMORY_USERPTR:
+-              if (get_user(p, &up32->m.userptr))
+-                      return -EFAULT;
+-              up_pln = compat_ptr(p);
+-              if (put_user((unsigned long)up_pln, &up->m.userptr))
++              if (get_user(p, &up32->m.userptr) ||
++                  put_user((unsigned long)compat_ptr(p), &up->m.userptr))
+                       return -EFAULT;
+               break;
+       case V4L2_MEMORY_DMABUF:
+@@ -344,7 +415,8 @@ static int get_v4l2_plane32(struct v4l2_
+       return 0;
+ }
+-static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
++static int put_v4l2_plane32(struct v4l2_plane __user *up,
++                          struct v4l2_plane32 __user *up32,
+                           enum v4l2_memory memory)
+ {
+       unsigned long p;
+@@ -368,8 +440,7 @@ static int put_v4l2_plane32(struct v4l2_
+                       return -EFAULT;
+               break;
+       case V4L2_MEMORY_DMABUF:
+-              if (copy_in_user(&up32->m.fd, &up->m.fd,
+-                               sizeof(up->m.fd)))
++              if (copy_in_user(&up32->m.fd, &up->m.fd, sizeof(up->m.fd)))
+                       return -EFAULT;
+               break;
+       }
+@@ -377,37 +448,75 @@ static int put_v4l2_plane32(struct v4l2_
+       return 0;
+ }
+-static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
++static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *up, u32 *size)
+ {
++      u32 type;
++      u32 length;
++
++      if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
++          get_user(type, &up->type) ||
++          get_user(length, &up->length))
++              return -EFAULT;
++
++      if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
++              if (length > VIDEO_MAX_PLANES)
++                      return -EINVAL;
++
++              /*
++               * We don't really care if userspace decides to kill itself
++               * by passing a very big length value
++               */
++              *size = length * sizeof(struct v4l2_plane);
++      } else {
++              *size = 0;
++      }
++      return 0;
++}
++
++static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
++                           struct v4l2_buffer32 __user *up,
++                           void __user *aux_buf, u32 aux_space)
++{
++      u32 type;
++      u32 length;
++      enum v4l2_memory memory;
+       struct v4l2_plane32 __user *uplane32;
+       struct v4l2_plane __user *uplane;
+       compat_caddr_t p;
+-      int num_planes;
+       int ret;
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+-          get_user(kp->index, &up->index) ||
+-          get_user(kp->type, &up->type) ||
+-          get_user(kp->flags, &up->flags) ||
+-          get_user(kp->memory, &up->memory) ||
+-          get_user(kp->length, &up->length))
+-              return -EFAULT;
+-
+-      if (V4L2_TYPE_IS_OUTPUT(kp->type))
+-              if (get_user(kp->bytesused, &up->bytesused) ||
+-                  get_user(kp->field, &up->field) ||
+-                  get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+-                  get_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec))
++          assign_in_user(&kp->index, &up->index) ||
++          get_user(type, &up->type) ||
++          put_user(type, &kp->type) ||
++          assign_in_user(&kp->flags, &up->flags) ||
++          get_user(memory, &up->memory) ||
++          put_user(memory, &kp->memory) ||
++          get_user(length, &up->length) ||
++          put_user(length, &kp->length))
++              return -EFAULT;
++
++      if (V4L2_TYPE_IS_OUTPUT(type))
++              if (assign_in_user(&kp->bytesused, &up->bytesused) ||
++                  assign_in_user(&kp->field, &up->field) ||
++                  assign_in_user(&kp->timestamp.tv_sec,
++                                 &up->timestamp.tv_sec) ||
++                  assign_in_user(&kp->timestamp.tv_usec,
++                                 &up->timestamp.tv_usec))
+                       return -EFAULT;
+-      if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
+-              num_planes = kp->length;
++      if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
++              u32 num_planes = length;
++
+               if (num_planes == 0) {
+-                      kp->m.planes = NULL;
+-                      /* num_planes == 0 is legal, e.g. when userspace doesn't
+-                       * need planes array on DQBUF*/
+-                      return 0;
++                      /*
++                       * num_planes == 0 is legal, e.g. when userspace doesn't
++                       * need planes array on DQBUF
++                       */
++                      return put_user(NULL, &kp->m.planes);
+               }
++              if (num_planes > VIDEO_MAX_PLANES)
++                      return -EINVAL;
+               if (get_user(p, &up->m.planes))
+                       return -EFAULT;
+@@ -417,37 +526,43 @@ static int get_v4l2_buffer32(struct v4l2
+                              num_planes * sizeof(*uplane32)))
+                       return -EFAULT;
+-              /* We don't really care if userspace decides to kill itself
+-               * by passing a very big num_planes value */
+-              uplane = compat_alloc_user_space(num_planes * sizeof(*uplane));
+-              kp->m.planes = (__force struct v4l2_plane *)uplane;
++              /*
++               * We don't really care if userspace decides to kill itself
++               * by passing a very big num_planes value
++               */
++              if (aux_space < num_planes * sizeof(*uplane))
++                      return -EFAULT;
++
++              uplane = aux_buf;
++              if (put_user((__force struct v4l2_plane *)uplane,
++                           &kp->m.planes))
++                      return -EFAULT;
+-              while (--num_planes >= 0) {
+-                      ret = get_v4l2_plane32(uplane, uplane32, kp->memory);
++              while (num_planes--) {
++                      ret = get_v4l2_plane32(uplane, uplane32, memory);
+                       if (ret)
+                               return ret;
+-                      ++uplane;
+-                      ++uplane32;
++                      uplane++;
++                      uplane32++;
+               }
+       } else {
+-              switch (kp->memory) {
++              switch (memory) {
+               case V4L2_MEMORY_MMAP:
+               case V4L2_MEMORY_OVERLAY:
+-                      if (get_user(kp->m.offset, &up->m.offset))
++                      if (assign_in_user(&kp->m.offset, &up->m.offset))
+                               return -EFAULT;
+                       break;
+-              case V4L2_MEMORY_USERPTR:
+-                      {
+-                              compat_long_t tmp;
+-
+-                              if (get_user(tmp, &up->m.userptr))
+-                                      return -EFAULT;
++              case V4L2_MEMORY_USERPTR: {
++                      compat_ulong_t userptr;
+-                              kp->m.userptr = (unsigned long)compat_ptr(tmp);
+-                      }
++                      if (get_user(userptr, &up->m.userptr) ||
++                          put_user((unsigned long)compat_ptr(userptr),
++                                   &kp->m.userptr))
++                              return -EFAULT;
+                       break;
++              }
+               case V4L2_MEMORY_DMABUF:
+-                      if (get_user(kp->m.fd, &up->m.fd))
++                      if (assign_in_user(&kp->m.fd, &up->m.fd))
+                               return -EFAULT;
+                       break;
+               }
+@@ -456,62 +571,70 @@ static int get_v4l2_buffer32(struct v4l2
+       return 0;
+ }
+-static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
++static int put_v4l2_buffer32(struct v4l2_buffer __user *kp,
++                           struct v4l2_buffer32 __user *up)
+ {
++      u32 type;
++      u32 length;
++      enum v4l2_memory memory;
+       struct v4l2_plane32 __user *uplane32;
+       struct v4l2_plane __user *uplane;
+       compat_caddr_t p;
+-      int num_planes;
+       int ret;
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+-          put_user(kp->index, &up->index) ||
+-          put_user(kp->type, &up->type) ||
+-          put_user(kp->flags, &up->flags) ||
+-          put_user(kp->memory, &up->memory))
+-              return -EFAULT;
+-
+-      if (put_user(kp->bytesused, &up->bytesused) ||
+-          put_user(kp->field, &up->field) ||
+-          put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+-          put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
+-          copy_to_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) ||
+-          put_user(kp->sequence, &up->sequence) ||
+-          put_user(kp->reserved2, &up->reserved2) ||
+-          put_user(kp->reserved, &up->reserved) ||
+-          put_user(kp->length, &up->length))
++          assign_in_user(&up->index, &kp->index) ||
++          get_user(type, &kp->type) ||
++          put_user(type, &up->type) ||
++          assign_in_user(&up->flags, &kp->flags) ||
++          get_user(memory, &kp->memory) ||
++          put_user(memory, &up->memory))
++              return -EFAULT;
++
++      if (assign_in_user(&up->bytesused, &kp->bytesused) ||
++          assign_in_user(&up->field, &kp->field) ||
++          assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
++          assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) ||
++          copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) ||
++          assign_in_user(&up->sequence, &kp->sequence) ||
++          assign_in_user(&up->reserved2, &kp->reserved2) ||
++          assign_in_user(&up->reserved, &kp->reserved) ||
++          get_user(length, &kp->length) ||
++          put_user(length, &up->length))
+               return -EFAULT;
+-      if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
+-              num_planes = kp->length;
++      if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
++              u32 num_planes = length;
++
+               if (num_planes == 0)
+                       return 0;
+-              uplane = (__force struct v4l2_plane __user *)kp->m.planes;
++              if (get_user(uplane, ((__force struct v4l2_plane __user **)&kp->m.planes)))
++                      return -EFAULT;
+               if (get_user(p, &up->m.planes))
+                       return -EFAULT;
+               uplane32 = compat_ptr(p);
+-              while (--num_planes >= 0) {
+-                      ret = put_v4l2_plane32(uplane, uplane32, kp->memory);
++              while (num_planes--) {
++                      ret = put_v4l2_plane32(uplane, uplane32, memory);
+                       if (ret)
+                               return ret;
+                       ++uplane;
+                       ++uplane32;
+               }
+       } else {
+-              switch (kp->memory) {
++              switch (memory) {
+               case V4L2_MEMORY_MMAP:
+               case V4L2_MEMORY_OVERLAY:
+-                      if (put_user(kp->m.offset, &up->m.offset))
++                      if (assign_in_user(&up->m.offset, &kp->m.offset))
+                               return -EFAULT;
+                       break;
+               case V4L2_MEMORY_USERPTR:
+-                      if (put_user(kp->m.userptr, &up->m.userptr))
++                      if (assign_in_user(&up->m.userptr, &kp->m.userptr))
+                               return -EFAULT;
+                       break;
+               case V4L2_MEMORY_DMABUF:
+-                      if (put_user(kp->m.fd, &up->m.fd))
++                      if (assign_in_user(&up->m.fd, &kp->m.fd))
+                               return -EFAULT;
+                       break;
+               }
+@@ -523,7 +646,7 @@ static int put_v4l2_buffer32(struct v4l2
+ struct v4l2_framebuffer32 {
+       __u32                   capability;
+       __u32                   flags;
+-      compat_caddr_t          base;
++      compat_caddr_t          base;
+       struct {
+               __u32           width;
+               __u32           height;
+@@ -536,29 +659,32 @@ struct v4l2_framebuffer32 {
+       } fmt;
+ };
+-static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
++static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
++                                struct v4l2_framebuffer32 __user *up)
+ {
+-      u32 tmp;
++      compat_caddr_t tmp;
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           get_user(tmp, &up->base) ||
+-          get_user(kp->capability, &up->capability) ||
+-          get_user(kp->flags, &up->flags) ||
+-          copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt)))
++          put_user((__force void *)compat_ptr(tmp), &kp->base) ||
++          assign_in_user(&kp->capability, &up->capability) ||
++          assign_in_user(&kp->flags, &up->flags) ||
++          copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt)))
+               return -EFAULT;
+-      kp->base = (__force void *)compat_ptr(tmp);
+       return 0;
+ }
+-static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
++static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
++                                struct v4l2_framebuffer32 __user *up)
+ {
+-      u32 tmp = (u32)((unsigned long)kp->base);
++      void *base;
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+-          put_user(tmp, &up->base) ||
+-          put_user(kp->capability, &up->capability) ||
+-          put_user(kp->flags, &up->flags) ||
+-          copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt)))
++          get_user(base, &kp->base) ||
++          put_user(ptr_to_compat(base), &up->base) ||
++          assign_in_user(&up->capability, &kp->capability) ||
++          assign_in_user(&up->flags, &kp->flags) ||
++          copy_in_user(&up->fmt, &kp->fmt, sizeof(kp->fmt)))
+               return -EFAULT;
+       return 0;
+ }
+@@ -571,21 +697,26 @@ struct v4l2_input32 {
+       __u32        tuner;             /*  Associated tuner */
+       compat_u64   std;
+       __u32        status;
+-      __u32        reserved[4];
++      __u32        capabilities;
++      __u32        reserved[3];
+ };
+-/* The 64-bit v4l2_input struct has extra padding at the end of the struct.
+-   Otherwise it is identical to the 32-bit version. */
+-static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
++/*
++ * The 64-bit v4l2_input struct has extra padding at the end of the struct.
++ * Otherwise it is identical to the 32-bit version.
++ */
++static inline int get_v4l2_input32(struct v4l2_input __user *kp,
++                                 struct v4l2_input32 __user *up)
+ {
+-      if (copy_from_user(kp, up, sizeof(*up)))
++      if (copy_in_user(kp, up, sizeof(*up)))
+               return -EFAULT;
+       return 0;
+ }
+-static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
++static inline int put_v4l2_input32(struct v4l2_input __user *kp,
++                                 struct v4l2_input32 __user *up)
+ {
+-      if (copy_to_user(up, kp, sizeof(*up)))
++      if (copy_in_user(up, kp, sizeof(*up)))
+               return -EFAULT;
+       return 0;
+ }
+@@ -639,40 +770,64 @@ static inline bool ctrl_is_pointer(struc
+               (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD);
+ }
++static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *up,
++                                   u32 *size)
++{
++      u32 count;
++
++      if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
++          get_user(count, &up->count))
++              return -EFAULT;
++      if (count > V4L2_CID_MAX_CTRLS)
++              return -EINVAL;
++      *size = count * sizeof(struct v4l2_ext_control);
++      return 0;
++}
++
+ static int get_v4l2_ext_controls32(struct file *file,
+-                                 struct v4l2_ext_controls *kp,
+-                                 struct v4l2_ext_controls32 __user *up)
++                                 struct v4l2_ext_controls __user *kp,
++                                 struct v4l2_ext_controls32 __user *up,
++                                 void __user *aux_buf, u32 aux_space)
+ {
+       struct v4l2_ext_control32 __user *ucontrols;
+       struct v4l2_ext_control __user *kcontrols;
+-      int n;
++      u32 count;
++      u32 n;
+       compat_caddr_t p;
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+-          get_user(kp->ctrl_class, &up->ctrl_class) ||
+-          get_user(kp->count, &up->count) ||
+-          get_user(kp->error_idx, &up->error_idx) ||
+-          copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+-              return -EFAULT;
+-      n = kp->count;
+-      if (n == 0) {
+-              kp->controls = NULL;
+-              return 0;
+-      }
++          assign_in_user(&kp->ctrl_class, &up->ctrl_class) ||
++          get_user(count, &up->count) ||
++          put_user(count, &kp->count) ||
++          assign_in_user(&kp->error_idx, &up->error_idx) ||
++          copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
++              return -EFAULT;
++
++      if (count == 0)
++              return put_user(NULL, &kp->controls);
++      if (count > V4L2_CID_MAX_CTRLS)
++              return -EINVAL;
+       if (get_user(p, &up->controls))
+               return -EFAULT;
+       ucontrols = compat_ptr(p);
+-      if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(*ucontrols)))
++      if (!access_ok(VERIFY_READ, ucontrols, count * sizeof(*ucontrols)))
++              return -EFAULT;
++      if (aux_space < count * sizeof(*kcontrols))
+               return -EFAULT;
+-      kcontrols = compat_alloc_user_space(n * sizeof(*kcontrols));
+-      kp->controls = (__force struct v4l2_ext_control *)kcontrols;
+-      while (--n >= 0) {
++      kcontrols = aux_buf;
++      if (put_user((__force struct v4l2_ext_control *)kcontrols,
++                   &kp->controls))
++              return -EFAULT;
++
++      for (n = 0; n < count; n++) {
+               u32 id;
+               if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
+                       return -EFAULT;
++
+               if (get_user(id, &kcontrols->id))
+                       return -EFAULT;
++
+               if (ctrl_is_pointer(file, id)) {
+                       void __user *s;
+@@ -689,43 +844,54 @@ static int get_v4l2_ext_controls32(struc
+ }
+ static int put_v4l2_ext_controls32(struct file *file,
+-                                 struct v4l2_ext_controls *kp,
++                                 struct v4l2_ext_controls __user *kp,
+                                  struct v4l2_ext_controls32 __user *up)
+ {
+       struct v4l2_ext_control32 __user *ucontrols;
+-      struct v4l2_ext_control __user *kcontrols =
+-              (__force struct v4l2_ext_control __user *)kp->controls;
+-      int n = kp->count;
++      struct v4l2_ext_control __user *kcontrols;
++      u32 count;
++      u32 n;
+       compat_caddr_t p;
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+-          put_user(kp->ctrl_class, &up->ctrl_class) ||
+-          put_user(kp->count, &up->count) ||
+-          put_user(kp->error_idx, &up->error_idx) ||
+-          copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
++          assign_in_user(&up->ctrl_class, &kp->ctrl_class) ||
++          get_user(count, &kp->count) ||
++          put_user(count, &up->count) ||
++          assign_in_user(&up->error_idx, &kp->error_idx) ||
++          copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)) ||
++          get_user(kcontrols, &kp->controls))
+               return -EFAULT;
+-      if (!kp->count)
+-              return 0;
++      if (!count)
++              return 0;
+       if (get_user(p, &up->controls))
+               return -EFAULT;
+       ucontrols = compat_ptr(p);
+-      if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(*ucontrols)))
++      if (!access_ok(VERIFY_WRITE, ucontrols, count * sizeof(*ucontrols)))
+               return -EFAULT;
+-      while (--n >= 0) {
+-              unsigned size = sizeof(*ucontrols);
++      for (n = 0; n < count; n++) {
++              unsigned int size = sizeof(*ucontrols);
+               u32 id;
+-              if (get_user(id, &kcontrols->id))
++              if (get_user(id, &kcontrols->id) ||
++                  put_user(id, &ucontrols->id) ||
++                  assign_in_user(&ucontrols->size, &kcontrols->size) ||
++                  copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
++                               sizeof(ucontrols->reserved2)))
+                       return -EFAULT;
+-              /* Do not modify the pointer when copying a pointer control.
+-                 The contents of the pointer was changed, not the pointer
+-                 itself. */
++
++              /*
++               * Do not modify the pointer when copying a pointer control.
++               * The contents of the pointer was changed, not the pointer
++               * itself.
++               */
+               if (ctrl_is_pointer(file, id))
+                       size -= sizeof(ucontrols->value64);
++
+               if (copy_in_user(ucontrols, kcontrols, size))
+                       return -EFAULT;
++
+               ucontrols++;
+               kcontrols++;
+       }
+@@ -745,17 +911,18 @@ struct v4l2_event32 {
+       __u32                           reserved[8];
+ };
+-static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up)
++static int put_v4l2_event32(struct v4l2_event __user *kp,
++                          struct v4l2_event32 __user *up)
+ {
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+-          put_user(kp->type, &up->type) ||
+-          copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
+-          put_user(kp->pending, &up->pending) ||
+-          put_user(kp->sequence, &up->sequence) ||
+-          put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+-          put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) ||
+-          put_user(kp->id, &up->id) ||
+-          copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
++          assign_in_user(&up->type, &kp->type) ||
++          copy_in_user(&up->u, &kp->u, sizeof(kp->u)) ||
++          assign_in_user(&up->pending, &kp->pending) ||
++          assign_in_user(&up->sequence, &kp->sequence) ||
++          assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
++          assign_in_user(&up->timestamp.tv_nsec, &kp->timestamp.tv_nsec) ||
++          assign_in_user(&up->id, &kp->id) ||
++          copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+               return -EFAULT;
+       return 0;
+ }
+@@ -768,31 +935,34 @@ struct v4l2_edid32 {
+       compat_caddr_t edid;
+ };
+-static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
++static int get_v4l2_edid32(struct v4l2_edid __user *kp,
++                         struct v4l2_edid32 __user *up)
+ {
+-      u32 tmp;
++      compat_uptr_t tmp;
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+-          get_user(kp->pad, &up->pad) ||
+-          get_user(kp->start_block, &up->start_block) ||
+-          get_user(kp->blocks, &up->blocks) ||
++          assign_in_user(&kp->pad, &up->pad) ||
++          assign_in_user(&kp->start_block, &up->start_block) ||
++          assign_in_user(&kp->blocks, &up->blocks) ||
+           get_user(tmp, &up->edid) ||
+-          copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
++          put_user(compat_ptr(tmp), &kp->edid) ||
++          copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+               return -EFAULT;
+-      kp->edid = (__force u8 *)compat_ptr(tmp);
+       return 0;
+ }
+-static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
++static int put_v4l2_edid32(struct v4l2_edid __user *kp,
++                         struct v4l2_edid32 __user *up)
+ {
+-      u32 tmp = (u32)((unsigned long)kp->edid);
++      void *edid;
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+-          put_user(kp->pad, &up->pad) ||
+-          put_user(kp->start_block, &up->start_block) ||
+-          put_user(kp->blocks, &up->blocks) ||
+-          put_user(tmp, &up->edid) ||
+-          copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
++          assign_in_user(&up->pad, &kp->pad) ||
++          assign_in_user(&up->start_block, &kp->start_block) ||
++          assign_in_user(&up->blocks, &kp->blocks) ||
++          get_user(edid, &kp->edid) ||
++          put_user(ptr_to_compat(edid), &up->edid) ||
++          copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+               return -EFAULT;
+       return 0;
+ }
+@@ -809,7 +979,7 @@ static int put_v4l2_edid32(struct v4l2_e
+ #define VIDIOC_ENUMINPUT32    _IOWR('V', 26, struct v4l2_input32)
+ #define VIDIOC_G_EDID32               _IOWR('V', 40, struct v4l2_edid32)
+ #define VIDIOC_S_EDID32               _IOWR('V', 41, struct v4l2_edid32)
+-#define VIDIOC_TRY_FMT32              _IOWR('V', 64, struct v4l2_format32)
++#define VIDIOC_TRY_FMT32      _IOWR('V', 64, struct v4l2_format32)
+ #define VIDIOC_G_EXT_CTRLS32    _IOWR('V', 71, struct v4l2_ext_controls32)
+ #define VIDIOC_S_EXT_CTRLS32    _IOWR('V', 72, struct v4l2_ext_controls32)
+ #define VIDIOC_TRY_EXT_CTRLS32  _IOWR('V', 73, struct v4l2_ext_controls32)
+@@ -825,22 +995,23 @@ static int put_v4l2_edid32(struct v4l2_e
+ #define VIDIOC_G_OUTPUT32     _IOR ('V', 46, s32)
+ #define VIDIOC_S_OUTPUT32     _IOWR('V', 47, s32)
++static int alloc_userspace(unsigned int size, u32 aux_space,
++                         void __user **up_native)
++{
++      *up_native = compat_alloc_user_space(size + aux_space);
++      if (!*up_native)
++              return -ENOMEM;
++      if (clear_user(*up_native, size))
++              return -EFAULT;
++      return 0;
++}
++
+ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ {
+-      union {
+-              struct v4l2_format v2f;
+-              struct v4l2_buffer v2b;
+-              struct v4l2_framebuffer v2fb;
+-              struct v4l2_input v2i;
+-              struct v4l2_standard v2s;
+-              struct v4l2_ext_controls v2ecs;
+-              struct v4l2_event v2ev;
+-              struct v4l2_create_buffers v2crt;
+-              struct v4l2_edid v2edid;
+-              unsigned long vx;
+-              int vi;
+-      } karg;
+       void __user *up = compat_ptr(arg);
++      void __user *up_native = NULL;
++      void __user *aux_buf;
++      u32 aux_space;
+       int compatible_arg = 1;
+       long err = 0;
+@@ -879,30 +1050,52 @@ static long do_video_ioctl(struct file *
+       case VIDIOC_STREAMOFF:
+       case VIDIOC_S_INPUT:
+       case VIDIOC_S_OUTPUT:
+-              err = get_user(karg.vi, (s32 __user *)up);
++              err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
++              if (!err && assign_in_user((unsigned int __user *)up_native,
++                                         (compat_uint_t __user *)up))
++                      err = -EFAULT;
+               compatible_arg = 0;
+               break;
+       case VIDIOC_G_INPUT:
+       case VIDIOC_G_OUTPUT:
++              err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
+               compatible_arg = 0;
+               break;
+       case VIDIOC_G_EDID:
+       case VIDIOC_S_EDID:
+-              err = get_v4l2_edid32(&karg.v2edid, up);
++              err = alloc_userspace(sizeof(struct v4l2_edid), 0, &up_native);
++              if (!err)
++                      err = get_v4l2_edid32(up_native, up);
+               compatible_arg = 0;
+               break;
+       case VIDIOC_G_FMT:
+       case VIDIOC_S_FMT:
+       case VIDIOC_TRY_FMT:
+-              err = get_v4l2_format32(&karg.v2f, up);
++              err = bufsize_v4l2_format(up, &aux_space);
++              if (!err)
++                      err = alloc_userspace(sizeof(struct v4l2_format),
++                                            aux_space, &up_native);
++              if (!err) {
++                      aux_buf = up_native + sizeof(struct v4l2_format);
++                      err = get_v4l2_format32(up_native, up,
++                                              aux_buf, aux_space);
++              }
+               compatible_arg = 0;
+               break;
+       case VIDIOC_CREATE_BUFS:
+-              err = get_v4l2_create32(&karg.v2crt, up);
++              err = bufsize_v4l2_create(up, &aux_space);
++              if (!err)
++                      err = alloc_userspace(sizeof(struct v4l2_create_buffers),
++                                            aux_space, &up_native);
++              if (!err) {
++                      aux_buf = up_native + sizeof(struct v4l2_create_buffers);
++                      err = get_v4l2_create32(up_native, up,
++                                              aux_buf, aux_space);
++              }
+               compatible_arg = 0;
+               break;
+@@ -910,36 +1103,63 @@ static long do_video_ioctl(struct file *
+       case VIDIOC_QUERYBUF:
+       case VIDIOC_QBUF:
+       case VIDIOC_DQBUF:
+-              err = get_v4l2_buffer32(&karg.v2b, up);
++              err = bufsize_v4l2_buffer(up, &aux_space);
++              if (!err)
++                      err = alloc_userspace(sizeof(struct v4l2_buffer),
++                                            aux_space, &up_native);
++              if (!err) {
++                      aux_buf = up_native + sizeof(struct v4l2_buffer);
++                      err = get_v4l2_buffer32(up_native, up,
++                                              aux_buf, aux_space);
++              }
+               compatible_arg = 0;
+               break;
+       case VIDIOC_S_FBUF:
+-              err = get_v4l2_framebuffer32(&karg.v2fb, up);
++              err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
++                                    &up_native);
++              if (!err)
++                      err = get_v4l2_framebuffer32(up_native, up);
+               compatible_arg = 0;
+               break;
+       case VIDIOC_G_FBUF:
++              err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
++                                    &up_native);
+               compatible_arg = 0;
+               break;
+       case VIDIOC_ENUMSTD:
+-              err = get_v4l2_standard32(&karg.v2s, up);
++              err = alloc_userspace(sizeof(struct v4l2_standard), 0,
++                                    &up_native);
++              if (!err)
++                      err = get_v4l2_standard32(up_native, up);
+               compatible_arg = 0;
+               break;
+       case VIDIOC_ENUMINPUT:
+-              err = get_v4l2_input32(&karg.v2i, up);
++              err = alloc_userspace(sizeof(struct v4l2_input), 0, &up_native);
++              if (!err)
++                      err = get_v4l2_input32(up_native, up);
+               compatible_arg = 0;
+               break;
+       case VIDIOC_G_EXT_CTRLS:
+       case VIDIOC_S_EXT_CTRLS:
+       case VIDIOC_TRY_EXT_CTRLS:
+-              err = get_v4l2_ext_controls32(file, &karg.v2ecs, up);
++              err = bufsize_v4l2_ext_controls(up, &aux_space);
++              if (!err)
++                      err = alloc_userspace(sizeof(struct v4l2_ext_controls),
++                                            aux_space, &up_native);
++              if (!err) {
++                      aux_buf = up_native + sizeof(struct v4l2_ext_controls);
++                      err = get_v4l2_ext_controls32(file, up_native, up,
++                                                    aux_buf, aux_space);
++              }
+               compatible_arg = 0;
+               break;
+       case VIDIOC_DQEVENT:
++              err = alloc_userspace(sizeof(struct v4l2_event), 0, &up_native);
+               compatible_arg = 0;
+               break;
+       }
+@@ -948,25 +1168,26 @@ static long do_video_ioctl(struct file *
+       if (compatible_arg)
+               err = native_ioctl(file, cmd, (unsigned long)up);
+-      else {
+-              mm_segment_t old_fs = get_fs();
+-
+-              set_fs(KERNEL_DS);
+-              err = native_ioctl(file, cmd, (unsigned long)&karg);
+-              set_fs(old_fs);
+-      }
++      else
++              err = native_ioctl(file, cmd, (unsigned long)up_native);
+       if (err == -ENOTTY)
+               return err;
+-      /* Special case: even after an error we need to put the
+-         results back for these ioctls since the error_idx will
+-         contain information on which control failed. */
++      /*
++       * Special case: even after an error we need to put the
++       * results back for these ioctls since the error_idx will
++       * contain information on which control failed.
++       */
+       switch (cmd) {
+       case VIDIOC_G_EXT_CTRLS:
+       case VIDIOC_S_EXT_CTRLS:
+       case VIDIOC_TRY_EXT_CTRLS:
+-              if (put_v4l2_ext_controls32(file, &karg.v2ecs, up))
++              if (put_v4l2_ext_controls32(file, up_native, up))
++                      err = -EFAULT;
++              break;
++      case VIDIOC_S_EDID:
++              if (put_v4l2_edid32(up_native, up))
+                       err = -EFAULT;
+               break;
+       }
+@@ -978,45 +1199,46 @@ static long do_video_ioctl(struct file *
+       case VIDIOC_S_OUTPUT:
+       case VIDIOC_G_INPUT:
+       case VIDIOC_G_OUTPUT:
+-              err = put_user(((s32)karg.vi), (s32 __user *)up);
++              if (assign_in_user((compat_uint_t __user *)up,
++                                 ((unsigned int __user *)up_native)))
++                      err = -EFAULT;
+               break;
+       case VIDIOC_G_FBUF:
+-              err = put_v4l2_framebuffer32(&karg.v2fb, up);
++              err = put_v4l2_framebuffer32(up_native, up);
+               break;
+       case VIDIOC_DQEVENT:
+-              err = put_v4l2_event32(&karg.v2ev, up);
++              err = put_v4l2_event32(up_native, up);
+               break;
+       case VIDIOC_G_EDID:
+-      case VIDIOC_S_EDID:
+-              err = put_v4l2_edid32(&karg.v2edid, up);
++              err = put_v4l2_edid32(up_native, up);
+               break;
+       case VIDIOC_G_FMT:
+       case VIDIOC_S_FMT:
+       case VIDIOC_TRY_FMT:
+-              err = put_v4l2_format32(&karg.v2f, up);
++              err = put_v4l2_format32(up_native, up);
+               break;
+       case VIDIOC_CREATE_BUFS:
+-              err = put_v4l2_create32(&karg.v2crt, up);
++              err = put_v4l2_create32(up_native, up);
+               break;
+       case VIDIOC_PREPARE_BUF:
+       case VIDIOC_QUERYBUF:
+       case VIDIOC_QBUF:
+       case VIDIOC_DQBUF:
+-              err = put_v4l2_buffer32(&karg.v2b, up);
++              err = put_v4l2_buffer32(up_native, up);
+               break;
+       case VIDIOC_ENUMSTD:
+-              err = put_v4l2_standard32(&karg.v2s, up);
++              err = put_v4l2_standard32(up_native, up);
+               break;
+       case VIDIOC_ENUMINPUT:
+-              err = put_v4l2_input32(&karg.v2i, up);
++              err = put_v4l2_input32(up_native, up);
+               break;
+       }
+       return err;
diff --git a/queue-4.4/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch b/queue-4.4/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch
new file mode 100644 (file)
index 0000000..f7ca017
--- /dev/null
@@ -0,0 +1,38 @@
+From foo@baz Thu Feb 15 08:44:17 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:52:27 +0100
+Subject: media: v4l2-ioctl.c: don't copy back the result for -ENOTTY
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214115240.27650-2-hverkuil@xs4all.nl>
+
+From: Hans Verkuil <hans.verkuil@cisco.com>
+
+commit 181a4a2d5a0a7b43cab08a70710d727e7764ccdd upstream.
+
+If the ioctl returned -ENOTTY, then don't bother copying
+back the result as there is no point.
+
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/v4l2-ioctl.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/media/v4l2-core/v4l2-ioctl.c
++++ b/drivers/media/v4l2-core/v4l2-ioctl.c
+@@ -2783,8 +2783,11 @@ video_usercopy(struct file *file, unsign
+       /* Handles IOCTL */
+       err = func(file, cmd, parg);
+-      if (err == -ENOIOCTLCMD)
++      if (err == -ENOTTY || err == -ENOIOCTLCMD) {
+               err = -ENOTTY;
++              goto out;
++      }
++
+       if (err == 0) {
+               if (cmd == VIDIOC_DQBUF)
+                       trace_v4l2_dqbuf(video_devdata(file)->minor, parg);
diff --git a/queue-4.4/pktcdvd-fix-pkt_setup_dev-error-path.patch b/queue-4.4/pktcdvd-fix-pkt_setup_dev-error-path.patch
new file mode 100644 (file)
index 0000000..1466cf8
--- /dev/null
@@ -0,0 +1,52 @@
+From 5a0ec388ef0f6e33841aeb810d7fa23f049ec4cd Mon Sep 17 00:00:00 2001
+From: Bart Van Assche <bart.vanassche@wdc.com>
+Date: Tue, 2 Jan 2018 11:39:47 -0800
+Subject: pktcdvd: Fix pkt_setup_dev() error path
+
+From: Bart Van Assche <bart.vanassche@wdc.com>
+
+commit 5a0ec388ef0f6e33841aeb810d7fa23f049ec4cd upstream.
+
+Commit 523e1d399ce0 ("block: make gendisk hold a reference to its queue")
+modified add_disk() and disk_release() but did not update any of the
+error paths that trigger a put_disk() call after disk->queue has been
+assigned. That introduced the following behavior in the pktcdvd driver
+if pkt_new_dev() fails:
+
+Kernel BUG at 00000000e98fd882 [verbose debug info unavailable]
+
+Since disk_release() calls blk_put_queue() anyway if disk->queue != NULL,
+fix this by removing the blk_cleanup_queue() call from the pkt_setup_dev()
+error path.
+
+Fixes: commit 523e1d399ce0 ("block: make gendisk hold a reference to its queue")
+Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com>
+Cc: Tejun Heo <tj@kernel.org>
+Cc: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/block/pktcdvd.c |    4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/block/pktcdvd.c
++++ b/drivers/block/pktcdvd.c
+@@ -2779,7 +2779,7 @@ static int pkt_setup_dev(dev_t dev, dev_
+       pd->pkt_dev = MKDEV(pktdev_major, idx);
+       ret = pkt_new_dev(pd, dev);
+       if (ret)
+-              goto out_new_dev;
++              goto out_mem2;
+       /* inherit events of the host device */
+       disk->events = pd->bdev->bd_disk->events;
+@@ -2797,8 +2797,6 @@ static int pkt_setup_dev(dev_t dev, dev_
+       mutex_unlock(&ctl_mutex);
+       return 0;
+-out_new_dev:
+-      blk_cleanup_queue(disk->queue);
+ out_mem2:
+       put_disk(disk);
+ out_mem:
diff --git a/queue-4.4/revert-bluetooth-btusb-fix-qca-rome-suspend-resume.patch b/queue-4.4/revert-bluetooth-btusb-fix-qca-rome-suspend-resume.patch
new file mode 100644 (file)
index 0000000..1c1ed9c
--- /dev/null
@@ -0,0 +1,51 @@
+From 7d06d5895c159f64c46560dc258e553ad8670fe0 Mon Sep 17 00:00:00 2001
+From: Kai-Heng Feng <kai.heng.feng@canonical.com>
+Date: Wed, 20 Dec 2017 19:00:07 +0800
+Subject: Revert "Bluetooth: btusb: fix QCA Rome suspend/resume"
+
+From: Kai-Heng Feng <kai.heng.feng@canonical.com>
+
+commit 7d06d5895c159f64c46560dc258e553ad8670fe0 upstream.
+
+This reverts commit fd865802c66bc451dc515ed89360f84376ce1a56.
+
+This commit causes a regression on some QCA ROME chips. The USB device
+reset happens in btusb_open(), hence firmware loading gets interrupted.
+
+Furthermore, this commit stops working after commit
+("a0085f2510e8976614ad8f766b209448b385492f Bluetooth: btusb: driver to
+enable the usb-wakeup feature"). Reset-resume quirk only gets enabled in
+btusb_suspend() when it's not a wakeup source.
+
+If we really want to reset the USB device, we need to do it before
+btusb_open(). Let's handle it in drivers/usb/core/quirks.c.
+
+Cc: Leif Liddy <leif.linux@gmail.com>
+Cc: Matthias Kaehlcke <mka@chromium.org>
+Cc: Brian Norris <briannorris@chromium.org>
+Cc: Daniel Drake <drake@endlessm.com>
+Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
+Reviewed-by: Brian Norris <briannorris@chromium.org>
+Tested-by: Brian Norris <briannorris@chromium.org>
+Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/bluetooth/btusb.c |    6 ------
+ 1 file changed, 6 deletions(-)
+
+--- a/drivers/bluetooth/btusb.c
++++ b/drivers/bluetooth/btusb.c
+@@ -2969,12 +2969,6 @@ static int btusb_probe(struct usb_interf
+       if (id->driver_info & BTUSB_QCA_ROME) {
+               data->setup_on_usb = btusb_setup_qca;
+               hdev->set_bdaddr = btusb_set_bdaddr_ath3012;
+-
+-              /* QCA Rome devices lose their updated firmware over suspend,
+-               * but the USB hub doesn't notice any status change.
+-               * Explicitly request a device reset on resume.
+-               */
+-              set_bit(BTUSB_RESET_RESUME, &data->flags);
+       }
+ #ifdef CONFIG_BT_HCIBTUSB_RTL
index 249f802c5020d933bfb41c57afc7761e17f9a364..81de8064741ffe523d0a5bf9be81cbe78fb4ddba 100644 (file)
@@ -68,3 +68,36 @@ crypto-hash-introduce-crypto_hash_alg_has_setkey.patch
 crypto-cryptd-pass-through-absence-of-setkey.patch
 crypto-poly1305-remove-setkey-method.patch
 nsfs-mark-dentry-with-dcache_rcuaccess.patch
+media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch
+vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch
+media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch
+media-v4l2-compat-ioctl32.c-fix-the-indentation.patch
+media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch
+media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch
+media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch
+media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch
+media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch
+media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch
+media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch
+media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch
+media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch
+media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch
+crypto-caam-fix-endless-loop-when-deco-acquire-fails.patch
+arm-kvm-fix-smccc-handling-of-unimplemented-smc-hvc-calls.patch
+kvm-nvmx-fix-races-when-sending-nested-pi-while-dest-enters-leaves-l2.patch
+watchdog-imx2_wdt-restore-previous-timeout-after-suspend-resume.patch
+media-ts2020-avoid-integer-overflows-on-32-bit-machines.patch
+media-cxusb-dib0700-ignore-xc2028_i2c_flush.patch
+kernel-async.c-revert-async-simplify-lowest_in_progress.patch
+hid-quirks-fix-keyboard-touchpad-on-toshiba-click-mini-not-working.patch
+bluetooth-btsdio-do-not-bind-to-non-removable-bcm43341.patch
+revert-bluetooth-btusb-fix-qca-rome-suspend-resume.patch
+bluetooth-btusb-restore-qca-rome-suspend-resume-fix-with-a-rewritten-version.patch
+signal-openrisc-fix-do_unaligned_access-to-send-the-proper-signal.patch
+signal-sh-ensure-si_signo-is-initialized-in-do_divide_error.patch
+alpha-fix-crash-if-pthread_create-races-with-signal-delivery.patch
+alpha-fix-reboot-on-avanti-platform.patch
+xtensa-fix-futex_atomic_cmpxchg_inatomic.patch
+edac-octeon-fix-an-uninitialized-variable-warning.patch
+pktcdvd-fix-pkt_setup_dev-error-path.patch
+blk-mq-quiesce-queue-before-freeing-queue.patch
diff --git a/queue-4.4/signal-openrisc-fix-do_unaligned_access-to-send-the-proper-signal.patch b/queue-4.4/signal-openrisc-fix-do_unaligned_access-to-send-the-proper-signal.patch
new file mode 100644 (file)
index 0000000..7099117
--- /dev/null
@@ -0,0 +1,56 @@
+From 500d58300571b6602341b041f97c082a461ef994 Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Tue, 1 Aug 2017 04:16:47 -0500
+Subject: signal/openrisc: Fix do_unaligned_access to send the proper signal
+
+From: Eric W. Biederman <ebiederm@xmission.com>
+
+commit 500d58300571b6602341b041f97c082a461ef994 upstream.
+
+While reviewing the signal sending on openrisc the do_unaligned_access
+function stood out because it is obviously wrong.  A comment about an
+si_code set above when actually si_code is never set.  Leading to a
+random si_code being sent to userspace in the event of an unaligned
+access.
+
+Looking further SIGBUS BUS_ADRALN is the proper pair of signal and
+si_code to send for an unaligned access. That is what other
+architectures do and what is required by posix.
+
+Given that do_unaligned_access is broken in a way that no one can be
+relying on it on openrisc fix the code to just do the right thing.
+
+Fixes: 769a8a96229e ("OpenRISC: Traps")
+Cc: Jonas Bonn <jonas@southpole.se>
+Cc: Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
+Cc: Stafford Horne <shorne@gmail.com>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: openrisc@lists.librecores.org
+Acked-by: Stafford Horne <shorne@gmail.com>
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/openrisc/kernel/traps.c |   10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/arch/openrisc/kernel/traps.c
++++ b/arch/openrisc/kernel/traps.c
+@@ -302,12 +302,12 @@ asmlinkage void do_unaligned_access(stru
+       siginfo_t info;
+       if (user_mode(regs)) {
+-              /* Send a SIGSEGV */
+-              info.si_signo = SIGSEGV;
++              /* Send a SIGBUS */
++              info.si_signo = SIGBUS;
+               info.si_errno = 0;
+-              /* info.si_code has been set above */
+-              info.si_addr = (void *)address;
+-              force_sig_info(SIGSEGV, &info, current);
++              info.si_code = BUS_ADRALN;
++              info.si_addr = (void __user *)address;
++              force_sig_info(SIGBUS, &info, current);
+       } else {
+               printk("KERNEL: Unaligned Access 0x%.8lx\n", address);
+               show_registers(regs);
diff --git a/queue-4.4/signal-sh-ensure-si_signo-is-initialized-in-do_divide_error.patch b/queue-4.4/signal-sh-ensure-si_signo-is-initialized-in-do_divide_error.patch
new file mode 100644 (file)
index 0000000..580dcfc
--- /dev/null
@@ -0,0 +1,35 @@
+From 0e88bb002a9b2ee8cc3cc9478ce2dc126f849696 Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Mon, 24 Jul 2017 17:30:30 -0500
+Subject: signal/sh: Ensure si_signo is initialized in do_divide_error
+
+From: Eric W. Biederman <ebiederm@xmission.com>
+
+commit 0e88bb002a9b2ee8cc3cc9478ce2dc126f849696 upstream.
+
+Set si_signo.
+
+Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
+Cc: Rich Felker <dalias@libc.org>
+Cc: Paul Mundt <lethal@linux-sh.org>
+Cc: linux-sh@vger.kernel.org
+Fixes: 0983b31849bb ("sh: Wire up division and address error exceptions on SH-2A.")
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/sh/kernel/traps_32.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/arch/sh/kernel/traps_32.c
++++ b/arch/sh/kernel/traps_32.c
+@@ -607,7 +607,8 @@ asmlinkage void do_divide_error(unsigned
+               break;
+       }
+-      force_sig_info(SIGFPE, &info, current);
++      info.si_signo = SIGFPE;
++      force_sig_info(info.si_signo, &info, current);
+ }
+ #endif
diff --git a/queue-4.4/vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch b/queue-4.4/vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch
new file mode 100644 (file)
index 0000000..349f751
--- /dev/null
@@ -0,0 +1,51 @@
+From foo@baz Thu Feb 15 08:44:17 CET 2018
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Wed, 14 Feb 2018 12:52:28 +0100
+Subject: vb2: V4L2_BUF_FLAG_DONE is set after DQBUF
+To: stable@vger.kernel.org
+Cc: linux-media@vger.kernel.org, Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>, Hans Verkuil <hans.verkuil@cisco.com>, Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Message-ID: <20180214115240.27650-3-hverkuil@xs4all.nl>
+
+From: Ricardo Ribalda <ricardo.ribalda@gmail.com>
+
+commit 3171cc2b4eb9831ab4df1d80d0410a945b8bc84e upstream.
+
+According to the doc, V4L2_BUF_FLAG_DONE is cleared after DQBUF:
+
+V4L2_BUF_FLAG_DONE 0x00000004  ... After calling the VIDIOC_QBUF or
+VIDIOC_DQBUF it is always cleared ...
+
+Unfortunately, it seems that videobuf2 keeps it set after DQBUF. This
+can be tested with vivid and dev_debug:
+
+[257604.338082] video1: VIDIOC_DQBUF: 71:33:25.00260479 index=3,
+type=vid-cap, flags=0x00002004, field=none, sequence=163,
+memory=userptr, bytesused=460800, offset/userptr=0x344b000,
+length=460800
+
+This patch forces FLAG_DONE to 0 after calling DQBUF.
+
+Reported-by: Dimitrios Katsaros <patcherwork@gmail.com>
+Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
+Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/v4l2-core/videobuf2-v4l2.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/media/v4l2-core/videobuf2-v4l2.c
++++ b/drivers/media/v4l2-core/videobuf2-v4l2.c
+@@ -593,6 +593,12 @@ static int vb2_internal_dqbuf(struct vb2
+                       b->flags & V4L2_BUF_FLAG_LAST)
+               q->last_buffer_dequeued = true;
++      /*
++       *  After calling the VIDIOC_DQBUF V4L2_BUF_FLAG_DONE must be
++       *  cleared.
++       */
++      b->flags &= ~V4L2_BUF_FLAG_DONE;
++
+       return ret;
+ }
diff --git a/queue-4.4/watchdog-imx2_wdt-restore-previous-timeout-after-suspend-resume.patch b/queue-4.4/watchdog-imx2_wdt-restore-previous-timeout-after-suspend-resume.patch
new file mode 100644 (file)
index 0000000..4e7186a
--- /dev/null
@@ -0,0 +1,88 @@
+From 0be267255cef64e1c58475baa7b25568355a3816 Mon Sep 17 00:00:00 2001
+From: Martin Kaiser <martin@kaiser.cx>
+Date: Mon, 1 Jan 2018 18:26:47 +0100
+Subject: watchdog: imx2_wdt: restore previous timeout after suspend+resume
+
+From: Martin Kaiser <martin@kaiser.cx>
+
+commit 0be267255cef64e1c58475baa7b25568355a3816 upstream.
+
+When the watchdog device is suspended, its timeout is set to the maximum
+value. During resume, the previously set timeout should be restored.
+This does not work at the moment.
+
+The suspend function calls
+
+imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
+
+and resume reverts this by calling
+
+imx2_wdt_set_timeout(wdog, wdog->timeout);
+
+However, imx2_wdt_set_timeout() updates wdog->timeout. Therefore,
+wdog->timeout is set to IMX2_WDT_MAX_TIME when we enter the resume
+function.
+
+Fix this by adding a new function __imx2_wdt_set_timeout() which
+only updates the hardware settings. imx2_wdt_set_timeout() now calls
+__imx2_wdt_set_timeout() and then saves the new timeout to
+wdog->timeout.
+
+During suspend, we call __imx2_wdt_set_timeout() directly so that
+wdog->timeout won't be updated and we can restore the previous value
+during resume. This approach makes wdog->timeout different from the
+actual setting in the hardware which is usually not a good thing.
+However, the two differ only while we're suspended and no kernel code is
+running, so it should be ok in this case.
+
+Signed-off-by: Martin Kaiser <martin@kaiser.cx>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/watchdog/imx2_wdt.c |   20 +++++++++++++++-----
+ 1 file changed, 15 insertions(+), 5 deletions(-)
+
+--- a/drivers/watchdog/imx2_wdt.c
++++ b/drivers/watchdog/imx2_wdt.c
+@@ -161,15 +161,21 @@ static void imx2_wdt_timer_ping(unsigned
+       mod_timer(&wdev->timer, jiffies + wdog->timeout * HZ / 2);
+ }
+-static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
+-                              unsigned int new_timeout)
++static void __imx2_wdt_set_timeout(struct watchdog_device *wdog,
++                                 unsigned int new_timeout)
+ {
+       struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
+-      wdog->timeout = new_timeout;
+-
+       regmap_update_bits(wdev->regmap, IMX2_WDT_WCR, IMX2_WDT_WCR_WT,
+                          WDOG_SEC_TO_COUNT(new_timeout));
++}
++
++static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
++                              unsigned int new_timeout)
++{
++      __imx2_wdt_set_timeout(wdog, new_timeout);
++
++      wdog->timeout = new_timeout;
+       return 0;
+ }
+@@ -353,7 +359,11 @@ static int imx2_wdt_suspend(struct devic
+       /* The watchdog IP block is running */
+       if (imx2_wdt_is_running(wdev)) {
+-              imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
++              /*
++               * Don't update wdog->timeout, we'll restore the current value
++               * during resume.
++               */
++              __imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
+               imx2_wdt_ping(wdog);
+               /* The watchdog is not active */
diff --git a/queue-4.4/xtensa-fix-futex_atomic_cmpxchg_inatomic.patch b/queue-4.4/xtensa-fix-futex_atomic_cmpxchg_inatomic.patch
new file mode 100644 (file)
index 0000000..d7ad819
--- /dev/null
@@ -0,0 +1,70 @@
+From ca47480921587ae30417dd234a9f79af188e3666 Mon Sep 17 00:00:00 2001
+From: Max Filippov <jcmvbkbc@gmail.com>
+Date: Fri, 5 Jan 2018 14:27:58 -0800
+Subject: xtensa: fix futex_atomic_cmpxchg_inatomic
+
+From: Max Filippov <jcmvbkbc@gmail.com>
+
+commit ca47480921587ae30417dd234a9f79af188e3666 upstream.
+
+Return 0 if the operation was successful, not the userspace memory
+value. Check that userspace value equals passed oldval, not itself.
+Don't update *uval if the value wasn't read from userspace memory.
+
+This fixes process hang due to infinite loop in futex_lock_pi.
+It also fixes a bunch of glibc tests nptl/tst-mutexpi*.
+
+Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/xtensa/include/asm/futex.h |   23 ++++++++++-------------
+ 1 file changed, 10 insertions(+), 13 deletions(-)
+
+--- a/arch/xtensa/include/asm/futex.h
++++ b/arch/xtensa/include/asm/futex.h
+@@ -109,7 +109,6 @@ futex_atomic_cmpxchg_inatomic(u32 *uval,
+                             u32 oldval, u32 newval)
+ {
+       int ret = 0;
+-      u32 prev;
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+               return -EFAULT;
+@@ -120,26 +119,24 @@ futex_atomic_cmpxchg_inatomic(u32 *uval,
+       __asm__ __volatile__ (
+       "       # futex_atomic_cmpxchg_inatomic\n"
+-      "1:     l32i    %1, %3, 0\n"
+-      "       mov     %0, %5\n"
+-      "       wsr     %1, scompare1\n"
+-      "2:     s32c1i  %0, %3, 0\n"
+-      "3:\n"
++      "       wsr     %5, scompare1\n"
++      "1:     s32c1i  %1, %4, 0\n"
++      "       s32i    %1, %6, 0\n"
++      "2:\n"
+       "       .section .fixup,\"ax\"\n"
+       "       .align 4\n"
+-      "4:     .long   3b\n"
+-      "5:     l32r    %1, 4b\n"
+-      "       movi    %0, %6\n"
++      "3:     .long   2b\n"
++      "4:     l32r    %1, 3b\n"
++      "       movi    %0, %7\n"
+       "       jx      %1\n"
+       "       .previous\n"
+       "       .section __ex_table,\"a\"\n"
+-      "       .long 1b,5b,2b,5b\n"
++      "       .long 1b,4b\n"
+       "       .previous\n"
+-      : "+r" (ret), "=&r" (prev), "+m" (*uaddr)
+-      : "r" (uaddr), "r" (oldval), "r" (newval), "I" (-EFAULT)
++      : "+r" (ret), "+r" (newval), "+m" (*uaddr), "+m" (*uval)
++      : "r" (uaddr), "r" (oldval), "r" (uval), "I" (-EFAULT)
+       : "memory");
+-      *uval = prev;
+       return ret;
+ }