From 901398522bbad8980c64964a41bda42d045bcc2d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 15 Feb 2018 09:35:19 +0100 Subject: [PATCH] 4.4-stable patches 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 --- ...ad_create-races-with-signal-delivery.patch | 56 + .../alpha-fix-reboot-on-avanti-platform.patch | 32 + ...dling-of-unimplemented-smc-hvc-calls.patch | 55 + ...q-quiesce-queue-before-freeing-queue.patch | 103 ++ ...o-not-bind-to-non-removable-bcm43341.patch | 57 + ...-resume-fix-with-a-rewritten-version.patch | 111 ++ ...endless-loop-when-deco-acquire-fails.patch | 58 + ...ix-an-uninitialized-variable-warning.patch | 47 + ...ad-on-toshiba-click-mini-not-working.patch | 57 + ...rt-async-simplify-lowest_in_progress.patch | 87 ++ ...ested-pi-while-dest-enters-leaves-l2.patch | 97 ++ ...xusb-dib0700-ignore-xc2028_i2c_flush.patch | 47 + ...integer-overflows-on-32-bit-machines.patch | 47 + ...octl32-copy-v4l2_window-global_alpha.patch | 56 + ...l32.c-add-missing-vidioc_prepare_buf.patch | 33 + ...2-compat-ioctl32.c-avoid-sizeof-type.patch | 321 ++++ ...-copy-clip-list-in-put_v4l2_window32.patch | 111 ++ ...c-copy-m.userptr-in-put_v4l2_plane32.patch | 132 ++ ...y-back-the-result-for-certain-errors.patch | 36 + ...drop-pr_info-for-unknown-buffer-type.patch | 44 + ...compat-ioctl32.c-fix-ctrl_is_pointer.patch | 144 ++ ...compat-ioctl32.c-fix-the-indentation.patch | 430 ++++++ ...ake-ctrl_is_pointer-work-for-subdevs.patch | 43 + ...functions-to-__get-put_v4l2_format32.patch | 172 +++ ...tl32.c-refactor-compat-ioctl32-logic.patch | 1323 +++++++++++++++++ ...on-t-copy-back-the-result-for-enotty.patch | 38 + ...pktcdvd-fix-pkt_setup_dev-error-path.patch | 52 + ...th-btusb-fix-qca-rome-suspend-resume.patch | 51 + queue-4.4/series | 33 + ...ned_access-to-send-the-proper-signal.patch | 56 + ...no-is-initialized-in-do_divide_error.patch | 35 + ...4l2_buf_flag_done-is-set-after-dqbuf.patch | 51 + ...revious-timeout-after-suspend-resume.patch | 88 ++ ...sa-fix-futex_atomic_cmpxchg_inatomic.patch | 70 + 34 files changed, 4173 insertions(+) create mode 100644 queue-4.4/alpha-fix-crash-if-pthread_create-races-with-signal-delivery.patch create mode 100644 queue-4.4/alpha-fix-reboot-on-avanti-platform.patch create mode 100644 queue-4.4/arm-kvm-fix-smccc-handling-of-unimplemented-smc-hvc-calls.patch create mode 100644 queue-4.4/blk-mq-quiesce-queue-before-freeing-queue.patch create mode 100644 queue-4.4/bluetooth-btsdio-do-not-bind-to-non-removable-bcm43341.patch create mode 100644 queue-4.4/bluetooth-btusb-restore-qca-rome-suspend-resume-fix-with-a-rewritten-version.patch create mode 100644 queue-4.4/crypto-caam-fix-endless-loop-when-deco-acquire-fails.patch create mode 100644 queue-4.4/edac-octeon-fix-an-uninitialized-variable-warning.patch create mode 100644 queue-4.4/hid-quirks-fix-keyboard-touchpad-on-toshiba-click-mini-not-working.patch create mode 100644 queue-4.4/kernel-async.c-revert-async-simplify-lowest_in_progress.patch create mode 100644 queue-4.4/kvm-nvmx-fix-races-when-sending-nested-pi-while-dest-enters-leaves-l2.patch create mode 100644 queue-4.4/media-cxusb-dib0700-ignore-xc2028_i2c_flush.patch create mode 100644 queue-4.4/media-ts2020-avoid-integer-overflows-on-32-bit-machines.patch create mode 100644 queue-4.4/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch create mode 100644 queue-4.4/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch create mode 100644 queue-4.4/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch create mode 100644 queue-4.4/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch create mode 100644 queue-4.4/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch create mode 100644 queue-4.4/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch create mode 100644 queue-4.4/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch create mode 100644 queue-4.4/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch create mode 100644 queue-4.4/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch create mode 100644 queue-4.4/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch create mode 100644 queue-4.4/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch create mode 100644 queue-4.4/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch create mode 100644 queue-4.4/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch create mode 100644 queue-4.4/pktcdvd-fix-pkt_setup_dev-error-path.patch create mode 100644 queue-4.4/revert-bluetooth-btusb-fix-qca-rome-suspend-resume.patch create mode 100644 queue-4.4/signal-openrisc-fix-do_unaligned_access-to-send-the-proper-signal.patch create mode 100644 queue-4.4/signal-sh-ensure-si_signo-is-initialized-in-do_divide_error.patch create mode 100644 queue-4.4/vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch create mode 100644 queue-4.4/watchdog-imx2_wdt-restore-previous-timeout-after-suspend-resume.patch create mode 100644 queue-4.4/xtensa-fix-futex_atomic_cmpxchg_inatomic.patch 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 index 00000000000..72dd4315831 --- /dev/null +++ b/queue-4.4/alpha-fix-crash-if-pthread_create-races-with-signal-delivery.patch @@ -0,0 +1,56 @@ +From 21ffceda1c8b3807615c40d440d7815e0c85d366 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Tue, 2 Jan 2018 14:01:34 -0500 +Subject: alpha: fix crash if pthread_create races with signal delivery + +From: Mikulas Patocka + +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 +Signed-off-by: Matt Turner +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..100748e08d9 --- /dev/null +++ b/queue-4.4/alpha-fix-reboot-on-avanti-platform.patch @@ -0,0 +1,32 @@ +From 55fc633c41a08ce9244ff5f528f420b16b1e04d6 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Tue, 2 Jan 2018 13:59:54 -0500 +Subject: alpha: fix reboot on Avanti platform + +From: Mikulas Patocka + +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 +Signed-off-by: Matt Turner +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..83403519815 --- /dev/null +++ b/queue-4.4/arm-kvm-fix-smccc-handling-of-unimplemented-smc-hvc-calls.patch @@ -0,0 +1,55 @@ +From 20e8175d246e9f9deb377f2784b3e7dfb2ad3e86 Mon Sep 17 00:00:00 2001 +From: Marc Zyngier +Date: Tue, 6 Feb 2018 17:56:06 +0000 +Subject: arm: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls + +From: Marc Zyngier + +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 +Signed-off-by: Marc Zyngier +Signed-off-by: Catalin Marinas +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..6c7def8a18e --- /dev/null +++ b/queue-4.4/blk-mq-quiesce-queue-before-freeing-queue.patch @@ -0,0 +1,103 @@ +From c2856ae2f315d754a0b6a268e4c6745b332b42e7 Mon Sep 17 00:00:00 2001 +From: Ming Lei +Date: Sat, 6 Jan 2018 16:27:37 +0800 +Subject: blk-mq: quiesce queue before freeing queue + +From: Ming Lei + +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 +Tested-by: Yi Zhang +Signed-off-by: Ming Lei +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..bb614098539 --- /dev/null +++ b/queue-4.4/bluetooth-btsdio-do-not-bind-to-non-removable-bcm43341.patch @@ -0,0 +1,57 @@ +From b4cdaba274247c9c841c6a682c08fa91fb3aa549 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 29 Nov 2017 20:29:07 +0100 +Subject: Bluetooth: btsdio: Do not bind to non-removable BCM43341 + +From: Hans de Goede + +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 +Signed-off-by: Marcel Holtmann +Signed-off-by: Greg Kroah-Hartman + +--- + 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 + #include + ++#include + #include + #include + +@@ -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 index 00000000000..dd99b9bec9c --- /dev/null +++ b/queue-4.4/bluetooth-btusb-restore-qca-rome-suspend-resume-fix-with-a-rewritten-version.patch @@ -0,0 +1,111 @@ +From 61f5acea8737d9b717fcc22bb6679924f3c82b98 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +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 + +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 +Cc: Matthias Kaehlcke +Cc: Brian Norris +Cc: Daniel Drake +Cc: Kai-Heng Feng +Signed-off-by: Hans de Goede +Signed-off-by: Marcel Holtmann +Signed-off-by: Greg Kroah-Hartman + +--- + 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 + #include ++#include + #include + #include + +@@ -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 index 00000000000..2b13338f706 --- /dev/null +++ b/queue-4.4/crypto-caam-fix-endless-loop-when-deco-acquire-fails.patch @@ -0,0 +1,58 @@ +From 225ece3e7dad4cfc44cca38ce7a3a80f255ea8f1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Horia=20Geant=C4=83?= +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ă + +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 +Suggested-by: Auer Lukas +Signed-off-by: Horia Geantă +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..1511b184e97 --- /dev/null +++ b/queue-4.4/edac-octeon-fix-an-uninitialized-variable-warning.patch @@ -0,0 +1,47 @@ +From 544e92581a2ac44607d7cc602c6b54d18656f56d Mon Sep 17 00:00:00 2001 +From: James Hogan +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 + +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 +Acked-by: David Daney +Cc: linux-edac +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..e4c9f9dd309 --- /dev/null +++ b/queue-4.4/hid-quirks-fix-keyboard-touchpad-on-toshiba-click-mini-not-working.patch @@ -0,0 +1,57 @@ +From edfc3722cfef4217c7fe92b272cbe0288ba1ff57 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +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 + +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 +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..0f8c255ca9e --- /dev/null +++ b/queue-4.4/kernel-async.c-revert-async-simplify-lowest_in_progress.patch @@ -0,0 +1,87 @@ +From 4f7e988e63e336827f4150de48163bed05d653bd Mon Sep 17 00:00:00 2001 +From: Rasmus Villemoes +Date: Tue, 6 Feb 2018 15:37:55 -0800 +Subject: kernel/async.c: revert "async: simplify lowest_in_progress()" + +From: Rasmus Villemoes + +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 +Acked-by: Tejun Heo +Cc: Arjan van de Ven +Cc: Adam Wallis +Cc: Lai Jiangshan +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..470bfaa7b7c --- /dev/null +++ b/queue-4.4/kvm-nvmx-fix-races-when-sending-nested-pi-while-dest-enters-leaves-l2.patch @@ -0,0 +1,97 @@ +From 6b6977117f50d60455ace86b2d256f6fb4f3de05 Mon Sep 17 00:00:00 2001 +From: Liran Alon +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 + +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 +Reviewed-by: Nikita Leshenko +Reviewed-by: Krish Sadhukhan +[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 +Signed-off-by: Radim Krčmář +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..526775f5d4d --- /dev/null +++ b/queue-4.4/media-cxusb-dib0700-ignore-xc2028_i2c_flush.patch @@ -0,0 +1,47 @@ +From 9893b905e743ded332575ca04486bd586c0772f7 Mon Sep 17 00:00:00 2001 +From: Mauro Carvalho Chehab +Date: Wed, 24 Jan 2018 06:01:57 -0500 +Subject: media: cxusb, dib0700: ignore XC2028_I2C_FLUSH + +From: Mauro Carvalho Chehab + +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 +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..7575a511478 --- /dev/null +++ b/queue-4.4/media-ts2020-avoid-integer-overflows-on-32-bit-machines.patch @@ -0,0 +1,47 @@ +From 81742be14b6a90c9fd0ff6eb4218bdf696ad8e46 Mon Sep 17 00:00:00 2001 +From: Mauro Carvalho Chehab +Date: Wed, 10 Jan 2018 07:20:39 -0500 +Subject: media: ts2020: avoid integer overflows on 32 bit machines + +From: Mauro Carvalho Chehab + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..ca409525e23 --- /dev/null +++ b/queue-4.4/media-v4l2-compat-ioctl32-copy-v4l2_window-global_alpha.patch @@ -0,0 +1,56 @@ +From foo@baz Thu Feb 15 08:44:17 CET 2018 +From: Hans Verkuil +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 , Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214115240.27650-11-hverkuil@xs4all.nl> + +From: Daniel Mentz + +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 +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..df03408ef8b --- /dev/null +++ b/queue-4.4/media-v4l2-compat-ioctl32.c-add-missing-vidioc_prepare_buf.patch @@ -0,0 +1,33 @@ +From foo@baz Thu Feb 15 08:44:17 CET 2018 +From: Hans Verkuil +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 , Mauro Carvalho Chehab +Message-ID: <20180214115240.27650-4-hverkuil@xs4all.nl> + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..480333606b6 --- /dev/null +++ b/queue-4.4/media-v4l2-compat-ioctl32.c-avoid-sizeof-type.patch @@ -0,0 +1,321 @@ +From foo@baz Thu Feb 15 08:44:17 CET 2018 +From: Hans Verkuil +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 , Mauro Carvalho Chehab +Message-ID: <20180214115240.27650-7-hverkuil@xs4all.nl> + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..1b4650d4dbf --- /dev/null +++ b/queue-4.4/media-v4l2-compat-ioctl32.c-copy-clip-list-in-put_v4l2_window32.patch @@ -0,0 +1,111 @@ +From foo@baz Thu Feb 15 08:44:17 CET 2018 +From: Hans Verkuil +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 , Mauro Carvalho Chehab +Message-ID: <20180214115240.27650-12-hverkuil@xs4all.nl> + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..81b0e9bc7f0 --- /dev/null +++ b/queue-4.4/media-v4l2-compat-ioctl32.c-copy-m.userptr-in-put_v4l2_plane32.patch @@ -0,0 +1,132 @@ +From foo@baz Thu Feb 15 08:44:17 CET 2018 +From: Hans Verkuil +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 , Mauro Carvalho Chehab +Message-ID: <20180214115240.27650-8-hverkuil@xs4all.nl> + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..4896af57ef9 --- /dev/null +++ b/queue-4.4/media-v4l2-compat-ioctl32.c-don-t-copy-back-the-result-for-certain-errors.patch @@ -0,0 +1,36 @@ +From foo@baz Thu Feb 15 08:44:17 CET 2018 +From: Hans Verkuil +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 , Mauro Carvalho Chehab +Message-ID: <20180214115240.27650-14-hverkuil@xs4all.nl> + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..25c9fee6ed5 --- /dev/null +++ b/queue-4.4/media-v4l2-compat-ioctl32.c-drop-pr_info-for-unknown-buffer-type.patch @@ -0,0 +1,44 @@ +From foo@baz Thu Feb 15 08:44:17 CET 2018 +From: Hans Verkuil +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 , Mauro Carvalho Chehab +Message-ID: <20180214115240.27650-13-hverkuil@xs4all.nl> + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..347416da232 --- /dev/null +++ b/queue-4.4/media-v4l2-compat-ioctl32.c-fix-ctrl_is_pointer.patch @@ -0,0 +1,144 @@ +From foo@baz Thu Feb 15 08:44:17 CET 2018 +From: Hans Verkuil +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 , Mauro Carvalho Chehab +Message-ID: <20180214115240.27650-9-hverkuil@xs4all.nl> + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + #include ++#include ++#include + #include + + 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 index 00000000000..c310039bea0 --- /dev/null +++ b/queue-4.4/media-v4l2-compat-ioctl32.c-fix-the-indentation.patch @@ -0,0 +1,430 @@ +From foo@baz Thu Feb 15 08:44:17 CET 2018 +From: Hans Verkuil +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 , Mauro Carvalho Chehab +Message-ID: <20180214115240.27650-5-hverkuil@xs4all.nl> + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..97e24a80c4f --- /dev/null +++ b/queue-4.4/media-v4l2-compat-ioctl32.c-make-ctrl_is_pointer-work-for-subdevs.patch @@ -0,0 +1,43 @@ +From foo@baz Thu Feb 15 08:44:17 CET 2018 +From: Hans Verkuil +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 , Mauro Carvalho Chehab +Message-ID: <20180214115240.27650-10-hverkuil@xs4all.nl> + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Reported-by: Laurent Pinchart +Reviewed-by: Laurent Pinchart +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..066d03cf8b8 --- /dev/null +++ b/queue-4.4/media-v4l2-compat-ioctl32.c-move-helper-functions-to-__get-put_v4l2_format32.patch @@ -0,0 +1,172 @@ +From foo@baz Thu Feb 15 08:44:17 CET 2018 +From: Hans Verkuil +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 , Mauro Carvalho Chehab +Message-ID: <20180214115240.27650-6-hverkuil@xs4all.nl> + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..33d80deee8f --- /dev/null +++ b/queue-4.4/media-v4l2-compat-ioctl32.c-refactor-compat-ioctl32-logic.patch @@ -0,0 +1,1323 @@ +From foo@baz Thu Feb 15 08:44:17 CET 2018 +From: Hans Verkuil +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 , Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214115240.27650-15-hverkuil@xs4all.nl> + +From: Daniel Mentz + +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 +Co-developed-by: Hans Verkuil +Acked-by: Sakari Ailus +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + ++/* 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 index 00000000000..f7ca017cedc --- /dev/null +++ b/queue-4.4/media-v4l2-ioctl.c-don-t-copy-back-the-result-for-enotty.patch @@ -0,0 +1,38 @@ +From foo@baz Thu Feb 15 08:44:17 CET 2018 +From: Hans Verkuil +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 , Mauro Carvalho Chehab +Message-ID: <20180214115240.27650-2-hverkuil@xs4all.nl> + +From: Hans Verkuil + +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 +Acked-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..1466cf8105e --- /dev/null +++ b/queue-4.4/pktcdvd-fix-pkt_setup_dev-error-path.patch @@ -0,0 +1,52 @@ +From 5a0ec388ef0f6e33841aeb810d7fa23f049ec4cd Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +Date: Tue, 2 Jan 2018 11:39:47 -0800 +Subject: pktcdvd: Fix pkt_setup_dev() error path + +From: Bart Van Assche + +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 +Cc: Tejun Heo +Cc: Maciej S. Szmigiero +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..1c1ed9ce874 --- /dev/null +++ b/queue-4.4/revert-bluetooth-btusb-fix-qca-rome-suspend-resume.patch @@ -0,0 +1,51 @@ +From 7d06d5895c159f64c46560dc258e553ad8670fe0 Mon Sep 17 00:00:00 2001 +From: Kai-Heng Feng +Date: Wed, 20 Dec 2017 19:00:07 +0800 +Subject: Revert "Bluetooth: btusb: fix QCA Rome suspend/resume" + +From: Kai-Heng Feng + +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 +Cc: Matthias Kaehlcke +Cc: Brian Norris +Cc: Daniel Drake +Signed-off-by: Kai-Heng Feng +Reviewed-by: Brian Norris +Tested-by: Brian Norris +Signed-off-by: Marcel Holtmann +Signed-off-by: Greg Kroah-Hartman + +--- + 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 diff --git a/queue-4.4/series b/queue-4.4/series index 249f802c502..81de8064741 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -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 index 00000000000..7099117d7cf --- /dev/null +++ b/queue-4.4/signal-openrisc-fix-do_unaligned_access-to-send-the-proper-signal.patch @@ -0,0 +1,56 @@ +From 500d58300571b6602341b041f97c082a461ef994 Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +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 + +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 +Cc: Stefan Kristiansson +Cc: Stafford Horne +Cc: Arnd Bergmann +Cc: openrisc@lists.librecores.org +Acked-by: Stafford Horne +Signed-off-by: "Eric W. Biederman" +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..580dcfc121c --- /dev/null +++ b/queue-4.4/signal-sh-ensure-si_signo-is-initialized-in-do_divide_error.patch @@ -0,0 +1,35 @@ +From 0e88bb002a9b2ee8cc3cc9478ce2dc126f849696 Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +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 + +commit 0e88bb002a9b2ee8cc3cc9478ce2dc126f849696 upstream. + +Set si_signo. + +Cc: Yoshinori Sato +Cc: Rich Felker +Cc: Paul Mundt +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" +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..349f7515334 --- /dev/null +++ b/queue-4.4/vb2-v4l2_buf_flag_done-is-set-after-dqbuf.patch @@ -0,0 +1,51 @@ +From foo@baz Thu Feb 15 08:44:17 CET 2018 +From: Hans Verkuil +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 , Hans Verkuil , Mauro Carvalho Chehab +Message-ID: <20180214115240.27650-3-hverkuil@xs4all.nl> + +From: Ricardo Ribalda + +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 +Signed-off-by: Ricardo Ribalda Delgado +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..4e7186a924e --- /dev/null +++ b/queue-4.4/watchdog-imx2_wdt-restore-previous-timeout-after-suspend-resume.patch @@ -0,0 +1,88 @@ +From 0be267255cef64e1c58475baa7b25568355a3816 Mon Sep 17 00:00:00 2001 +From: Martin Kaiser +Date: Mon, 1 Jan 2018 18:26:47 +0100 +Subject: watchdog: imx2_wdt: restore previous timeout after suspend+resume + +From: Martin Kaiser + +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 +Reviewed-by: Guenter Roeck +Signed-off-by: Guenter Roeck +Signed-off-by: Wim Van Sebroeck +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..d7ad81908ee --- /dev/null +++ b/queue-4.4/xtensa-fix-futex_atomic_cmpxchg_inatomic.patch @@ -0,0 +1,70 @@ +From ca47480921587ae30417dd234a9f79af188e3666 Mon Sep 17 00:00:00 2001 +From: Max Filippov +Date: Fri, 5 Jan 2018 14:27:58 -0800 +Subject: xtensa: fix futex_atomic_cmpxchg_inatomic + +From: Max Filippov + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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; + } + -- 2.47.2