From: Greg Kroah-Hartman Date: Tue, 23 Jul 2019 11:07:21 +0000 (+0200) Subject: 5.2-stable patches X-Git-Tag: v5.2.3~34 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4610ea963d0fd2f5c42b770de087bbedeb24f073;p=thirdparty%2Fkernel%2Fstable-queue.git 5.2-stable patches added patches: arm64-fix-incorrect-irqflag-restore-for-priority-masking.patch arm64-irqflags-add-condition-flags-to-inline-asm-clobber-list.patch arm64-tegra-fix-agic-register-range.patch fs-proc-proc_sysctl.c-fix-the-default-values-of-i_uid-i_gid-on-proc-sys-inodes.patch i3c-fix-i2c-and-i3c-scl-rate-by-bus-mode.patch intel_th-msu-fix-unused-variable-warning-on-arm64-platform.patch signal-correct-namespace-fixups-of-si_pid-and-si_uid.patch signal-usb-replace-kill_pid_info_as_cred-with-kill_pid_usb_asyncio.patch --- diff --git a/queue-5.2/arm64-fix-incorrect-irqflag-restore-for-priority-masking.patch b/queue-5.2/arm64-fix-incorrect-irqflag-restore-for-priority-masking.patch new file mode 100644 index 00000000000..8dfbfee5150 --- /dev/null +++ b/queue-5.2/arm64-fix-incorrect-irqflag-restore-for-priority-masking.patch @@ -0,0 +1,479 @@ +From bd82d4bd21880b7c4d5f5756be435095d6ae07b5 Mon Sep 17 00:00:00 2001 +From: Julien Thierry +Date: Tue, 11 Jun 2019 10:38:10 +0100 +Subject: arm64: Fix incorrect irqflag restore for priority masking + +From: Julien Thierry + +commit bd82d4bd21880b7c4d5f5756be435095d6ae07b5 upstream. + +When using IRQ priority masking to disable interrupts, in order to deal +with the PSR.I state, local_irq_save() would convert the I bit into a +PMR value (GIC_PRIO_IRQOFF). This resulted in local_irq_restore() +potentially modifying the value of PMR in undesired location due to the +state of PSR.I upon flag saving [1]. + +In an attempt to solve this issue in a less hackish manner, introduce +a bit (GIC_PRIO_IGNORE_PMR) for the PMR values that can represent +whether PSR.I is being used to disable interrupts, in which case it +takes precedence of the status of interrupt masking via PMR. + +GIC_PRIO_PSR_I_SET is chosen such that ( | +GIC_PRIO_PSR_I_SET) does not mask more interrupts than as +some sections (e.g. arch_cpu_idle(), interrupt acknowledge path) +requires PMR not to mask interrupts that could be signaled to the +CPU when using only PSR.I. + +[1] https://www.spinics.net/lists/arm-kernel/msg716956.html + +Fixes: 4a503217ce37 ("arm64: irqflags: Use ICC_PMR_EL1 for interrupt masking") +Cc: # 5.1.x- +Reported-by: Zenghui Yu +Cc: Steven Rostedt +Cc: Wei Li +Cc: Will Deacon +Cc: Christoffer Dall +Cc: James Morse +Cc: Suzuki K Pouloze +Cc: Oleg Nesterov +Reviewed-by: Marc Zyngier +Signed-off-by: Julien Thierry +Signed-off-by: Catalin Marinas +Signed-off-by: Greg Kroah-Hartman + +--- + arch/arm64/include/asm/arch_gicv3.h | 4 +- + arch/arm64/include/asm/daifflags.h | 68 +++++++++++++++++++++--------------- + arch/arm64/include/asm/irqflags.h | 67 ++++++++++++++--------------------- + arch/arm64/include/asm/kvm_host.h | 7 ++- + arch/arm64/include/asm/ptrace.h | 10 ++++- + arch/arm64/kernel/entry.S | 38 +++++++++++++++++--- + arch/arm64/kernel/process.c | 2 - + arch/arm64/kernel/smp.c | 8 ++-- + arch/arm64/kvm/hyp/switch.c | 2 - + 9 files changed, 123 insertions(+), 83 deletions(-) + +--- a/arch/arm64/include/asm/arch_gicv3.h ++++ b/arch/arm64/include/asm/arch_gicv3.h +@@ -152,7 +152,9 @@ static inline bool gic_prio_masking_enab + + static inline void gic_pmr_mask_irqs(void) + { +- BUILD_BUG_ON(GICD_INT_DEF_PRI <= GIC_PRIO_IRQOFF); ++ BUILD_BUG_ON(GICD_INT_DEF_PRI < (GIC_PRIO_IRQOFF | ++ GIC_PRIO_PSR_I_SET)); ++ BUILD_BUG_ON(GICD_INT_DEF_PRI >= GIC_PRIO_IRQON); + gic_write_pmr(GIC_PRIO_IRQOFF); + } + +--- a/arch/arm64/include/asm/daifflags.h ++++ b/arch/arm64/include/asm/daifflags.h +@@ -7,6 +7,7 @@ + + #include + ++#include + #include + + #define DAIF_PROCCTX 0 +@@ -21,6 +22,11 @@ static inline void local_daif_mask(void) + : + : + : "memory"); ++ ++ /* Don't really care for a dsb here, we don't intend to enable IRQs */ ++ if (system_uses_irq_prio_masking()) ++ gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET); ++ + trace_hardirqs_off(); + } + +@@ -32,7 +38,7 @@ static inline unsigned long local_daif_s + + if (system_uses_irq_prio_masking()) { + /* If IRQs are masked with PMR, reflect it in the flags */ +- if (read_sysreg_s(SYS_ICC_PMR_EL1) <= GIC_PRIO_IRQOFF) ++ if (read_sysreg_s(SYS_ICC_PMR_EL1) != GIC_PRIO_IRQON) + flags |= PSR_I_BIT; + } + +@@ -48,36 +54,44 @@ static inline void local_daif_restore(un + if (!irq_disabled) { + trace_hardirqs_on(); + +- if (system_uses_irq_prio_masking()) +- arch_local_irq_enable(); +- } else if (!(flags & PSR_A_BIT)) { +- /* +- * If interrupts are disabled but we can take +- * asynchronous errors, we can take NMIs +- */ + if (system_uses_irq_prio_masking()) { +- flags &= ~PSR_I_BIT; ++ gic_write_pmr(GIC_PRIO_IRQON); ++ dsb(sy); ++ } ++ } else if (system_uses_irq_prio_masking()) { ++ u64 pmr; ++ ++ if (!(flags & PSR_A_BIT)) { + /* +- * There has been concern that the write to daif +- * might be reordered before this write to PMR. +- * From the ARM ARM DDI 0487D.a, section D1.7.1 +- * "Accessing PSTATE fields": +- * Writes to the PSTATE fields have side-effects on +- * various aspects of the PE operation. All of these +- * side-effects are guaranteed: +- * - Not to be visible to earlier instructions in +- * the execution stream. +- * - To be visible to later instructions in the +- * execution stream +- * +- * Also, writes to PMR are self-synchronizing, so no +- * interrupts with a lower priority than PMR is signaled +- * to the PE after the write. +- * +- * So we don't need additional synchronization here. ++ * If interrupts are disabled but we can take ++ * asynchronous errors, we can take NMIs + */ +- arch_local_irq_disable(); ++ flags &= ~PSR_I_BIT; ++ pmr = GIC_PRIO_IRQOFF; ++ } else { ++ pmr = GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET; + } ++ ++ /* ++ * There has been concern that the write to daif ++ * might be reordered before this write to PMR. ++ * From the ARM ARM DDI 0487D.a, section D1.7.1 ++ * "Accessing PSTATE fields": ++ * Writes to the PSTATE fields have side-effects on ++ * various aspects of the PE operation. All of these ++ * side-effects are guaranteed: ++ * - Not to be visible to earlier instructions in ++ * the execution stream. ++ * - To be visible to later instructions in the ++ * execution stream ++ * ++ * Also, writes to PMR are self-synchronizing, so no ++ * interrupts with a lower priority than PMR is signaled ++ * to the PE after the write. ++ * ++ * So we don't need additional synchronization here. ++ */ ++ gic_write_pmr(pmr); + } + + write_sysreg(flags, daif); +--- a/arch/arm64/include/asm/irqflags.h ++++ b/arch/arm64/include/asm/irqflags.h +@@ -56,43 +56,46 @@ static inline void arch_local_irq_disabl + */ + static inline unsigned long arch_local_save_flags(void) + { +- unsigned long daif_bits; + unsigned long flags; + +- daif_bits = read_sysreg(daif); +- +- /* +- * The asm is logically equivalent to: +- * +- * if (system_uses_irq_prio_masking()) +- * flags = (daif_bits & PSR_I_BIT) ? +- * GIC_PRIO_IRQOFF : +- * read_sysreg_s(SYS_ICC_PMR_EL1); +- * else +- * flags = daif_bits; +- */ + asm volatile(ALTERNATIVE( +- "mov %0, %1\n" +- "nop\n" +- "nop", +- __mrs_s("%0", SYS_ICC_PMR_EL1) +- "ands %1, %1, " __stringify(PSR_I_BIT) "\n" +- "csel %0, %0, %2, eq", +- ARM64_HAS_IRQ_PRIO_MASKING) +- : "=&r" (flags), "+r" (daif_bits) +- : "r" ((unsigned long) GIC_PRIO_IRQOFF) +- : "cc", "memory"); ++ "mrs %0, daif", ++ __mrs_s("%0", SYS_ICC_PMR_EL1), ++ ARM64_HAS_IRQ_PRIO_MASKING) ++ : "=&r" (flags) ++ : ++ : "memory"); + + return flags; + } + ++static inline int arch_irqs_disabled_flags(unsigned long flags) ++{ ++ int res; ++ ++ asm volatile(ALTERNATIVE( ++ "and %w0, %w1, #" __stringify(PSR_I_BIT), ++ "eor %w0, %w1, #" __stringify(GIC_PRIO_IRQON), ++ ARM64_HAS_IRQ_PRIO_MASKING) ++ : "=&r" (res) ++ : "r" ((int) flags) ++ : "memory"); ++ ++ return res; ++} ++ + static inline unsigned long arch_local_irq_save(void) + { + unsigned long flags; + + flags = arch_local_save_flags(); + +- arch_local_irq_disable(); ++ /* ++ * There are too many states with IRQs disabled, just keep the current ++ * state if interrupts are already disabled/masked. ++ */ ++ if (!arch_irqs_disabled_flags(flags)) ++ arch_local_irq_disable(); + + return flags; + } +@@ -113,21 +116,5 @@ static inline void arch_local_irq_restor + : "memory"); + } + +-static inline int arch_irqs_disabled_flags(unsigned long flags) +-{ +- int res; +- +- asm volatile(ALTERNATIVE( +- "and %w0, %w1, #" __stringify(PSR_I_BIT) "\n" +- "nop", +- "cmp %w1, #" __stringify(GIC_PRIO_IRQOFF) "\n" +- "cset %w0, ls", +- ARM64_HAS_IRQ_PRIO_MASKING) +- : "=&r" (res) +- : "r" ((int) flags) +- : "cc", "memory"); +- +- return res; +-} + #endif + #endif +--- a/arch/arm64/include/asm/kvm_host.h ++++ b/arch/arm64/include/asm/kvm_host.h +@@ -597,11 +597,12 @@ static inline void kvm_arm_vhe_guest_ent + * will not signal the CPU of interrupts of lower priority, and the + * only way to get out will be via guest exceptions. + * Naturally, we want to avoid this. ++ * ++ * local_daif_mask() already sets GIC_PRIO_PSR_I_SET, we just need a ++ * dsb to ensure the redistributor is forwards EL2 IRQs to the CPU. + */ +- if (system_uses_irq_prio_masking()) { +- gic_write_pmr(GIC_PRIO_IRQON); ++ if (system_uses_irq_prio_masking()) + dsb(sy); +- } + } + + static inline void kvm_arm_vhe_guest_exit(void) +--- a/arch/arm64/include/asm/ptrace.h ++++ b/arch/arm64/include/asm/ptrace.h +@@ -24,9 +24,15 @@ + * means masking more IRQs (or at least that the same IRQs remain masked). + * + * To mask interrupts, we clear the most significant bit of PMR. ++ * ++ * Some code sections either automatically switch back to PSR.I or explicitly ++ * require to not use priority masking. If bit GIC_PRIO_PSR_I_SET is included ++ * in the the priority mask, it indicates that PSR.I should be set and ++ * interrupt disabling temporarily does not rely on IRQ priorities. + */ +-#define GIC_PRIO_IRQON 0xf0 +-#define GIC_PRIO_IRQOFF (GIC_PRIO_IRQON & ~0x80) ++#define GIC_PRIO_IRQON 0xc0 ++#define GIC_PRIO_IRQOFF (GIC_PRIO_IRQON & ~0x80) ++#define GIC_PRIO_PSR_I_SET (1 << 4) + + /* Additional SPSR bits not exposed in the UABI */ + #define PSR_IL_BIT (1 << 20) +--- a/arch/arm64/kernel/entry.S ++++ b/arch/arm64/kernel/entry.S +@@ -247,6 +247,7 @@ alternative_else_nop_endif + /* + * Registers that may be useful after this macro is invoked: + * ++ * x20 - ICC_PMR_EL1 + * x21 - aborted SP + * x22 - aborted PC + * x23 - aborted PSTATE +@@ -438,6 +439,24 @@ alternative_endif + .endm + #endif + ++ .macro gic_prio_kentry_setup, tmp:req ++#ifdef CONFIG_ARM64_PSEUDO_NMI ++ alternative_if ARM64_HAS_IRQ_PRIO_MASKING ++ mov \tmp, #(GIC_PRIO_PSR_I_SET | GIC_PRIO_IRQON) ++ msr_s SYS_ICC_PMR_EL1, \tmp ++ alternative_else_nop_endif ++#endif ++ .endm ++ ++ .macro gic_prio_irq_setup, pmr:req, tmp:req ++#ifdef CONFIG_ARM64_PSEUDO_NMI ++ alternative_if ARM64_HAS_IRQ_PRIO_MASKING ++ orr \tmp, \pmr, #GIC_PRIO_PSR_I_SET ++ msr_s SYS_ICC_PMR_EL1, \tmp ++ alternative_else_nop_endif ++#endif ++ .endm ++ + .text + + /* +@@ -616,6 +635,7 @@ el1_dbg: + cmp x24, #ESR_ELx_EC_BRK64 // if BRK64 + cinc x24, x24, eq // set bit '0' + tbz x24, #0, el1_inv // EL1 only ++ gic_prio_kentry_setup tmp=x3 + mrs x0, far_el1 + mov x2, sp // struct pt_regs + bl do_debug_exception +@@ -633,12 +653,10 @@ ENDPROC(el1_sync) + .align 6 + el1_irq: + kernel_entry 1 ++ gic_prio_irq_setup pmr=x20, tmp=x1 + enable_da_f + + #ifdef CONFIG_ARM64_PSEUDO_NMI +-alternative_if ARM64_HAS_IRQ_PRIO_MASKING +- ldr x20, [sp, #S_PMR_SAVE] +-alternative_else_nop_endif + test_irqs_unmasked res=x0, pmr=x20 + cbz x0, 1f + bl asm_nmi_enter +@@ -668,8 +686,9 @@ alternative_else_nop_endif + + #ifdef CONFIG_ARM64_PSEUDO_NMI + /* +- * if IRQs were disabled when we received the interrupt, we have an NMI +- * and we are not re-enabling interrupt upon eret. Skip tracing. ++ * When using IRQ priority masking, we can get spurious interrupts while ++ * PMR is set to GIC_PRIO_IRQOFF. An NMI might also have occurred in a ++ * section with interrupts disabled. Skip tracing in those cases. + */ + test_irqs_unmasked res=x0, pmr=x20 + cbz x0, 1f +@@ -798,6 +817,7 @@ el0_ia: + * Instruction abort handling + */ + mrs x26, far_el1 ++ gic_prio_kentry_setup tmp=x0 + enable_da_f + #ifdef CONFIG_TRACE_IRQFLAGS + bl trace_hardirqs_off +@@ -843,6 +863,7 @@ el0_sp_pc: + * Stack or PC alignment exception handling + */ + mrs x26, far_el1 ++ gic_prio_kentry_setup tmp=x0 + enable_da_f + #ifdef CONFIG_TRACE_IRQFLAGS + bl trace_hardirqs_off +@@ -877,6 +898,7 @@ el0_dbg: + * Debug exception handling + */ + tbnz x24, #0, el0_inv // EL0 only ++ gic_prio_kentry_setup tmp=x3 + mrs x0, far_el1 + mov x1, x25 + mov x2, sp +@@ -898,7 +920,9 @@ ENDPROC(el0_sync) + el0_irq: + kernel_entry 0 + el0_irq_naked: ++ gic_prio_irq_setup pmr=x20, tmp=x0 + enable_da_f ++ + #ifdef CONFIG_TRACE_IRQFLAGS + bl trace_hardirqs_off + #endif +@@ -920,6 +944,7 @@ ENDPROC(el0_irq) + el1_error: + kernel_entry 1 + mrs x1, esr_el1 ++ gic_prio_kentry_setup tmp=x2 + enable_dbg + mov x0, sp + bl do_serror +@@ -930,6 +955,7 @@ el0_error: + kernel_entry 0 + el0_error_naked: + mrs x1, esr_el1 ++ gic_prio_kentry_setup tmp=x2 + enable_dbg + mov x0, sp + bl do_serror +@@ -954,6 +980,7 @@ work_pending: + */ + ret_to_user: + disable_daif ++ gic_prio_kentry_setup tmp=x3 + ldr x1, [tsk, #TSK_TI_FLAGS] + and x2, x1, #_TIF_WORK_MASK + cbnz x2, work_pending +@@ -970,6 +997,7 @@ ENDPROC(ret_to_user) + */ + .align 6 + el0_svc: ++ gic_prio_kentry_setup tmp=x1 + mov x0, sp + bl el0_svc_handler + b ret_to_user +--- a/arch/arm64/kernel/process.c ++++ b/arch/arm64/kernel/process.c +@@ -83,7 +83,7 @@ static void __cpu_do_idle_irqprio(void) + * be raised. + */ + pmr = gic_read_pmr(); +- gic_write_pmr(GIC_PRIO_IRQON); ++ gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET); + + __cpu_do_idle(); + +--- a/arch/arm64/kernel/smp.c ++++ b/arch/arm64/kernel/smp.c +@@ -181,11 +181,13 @@ static void init_gic_priority_masking(vo + + WARN_ON(!(cpuflags & PSR_I_BIT)); + +- gic_write_pmr(GIC_PRIO_IRQOFF); +- + /* We can only unmask PSR.I if we can take aborts */ +- if (!(cpuflags & PSR_A_BIT)) ++ if (!(cpuflags & PSR_A_BIT)) { ++ gic_write_pmr(GIC_PRIO_IRQOFF); + write_sysreg(cpuflags & ~PSR_I_BIT, daif); ++ } else { ++ gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET); ++ } + } + + /* +--- a/arch/arm64/kvm/hyp/switch.c ++++ b/arch/arm64/kvm/hyp/switch.c +@@ -604,7 +604,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struc + * Naturally, we want to avoid this. + */ + if (system_uses_irq_prio_masking()) { +- gic_write_pmr(GIC_PRIO_IRQON); ++ gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET); + dsb(sy); + } + diff --git a/queue-5.2/arm64-irqflags-add-condition-flags-to-inline-asm-clobber-list.patch b/queue-5.2/arm64-irqflags-add-condition-flags-to-inline-asm-clobber-list.patch new file mode 100644 index 00000000000..a7e71e08b3f --- /dev/null +++ b/queue-5.2/arm64-irqflags-add-condition-flags-to-inline-asm-clobber-list.patch @@ -0,0 +1,46 @@ +From f57065782f245ca96f1472209a485073bbc11247 Mon Sep 17 00:00:00 2001 +From: Julien Thierry +Date: Tue, 11 Jun 2019 10:38:08 +0100 +Subject: arm64: irqflags: Add condition flags to inline asm clobber list + +From: Julien Thierry + +commit f57065782f245ca96f1472209a485073bbc11247 upstream. + +Some of the inline assembly instruction use the condition flags and need +to include "cc" in the clobber list. + +Fixes: 4a503217ce37 ("arm64: irqflags: Use ICC_PMR_EL1 for interrupt masking") +Cc: # 5.1.x- +Suggested-by: Marc Zyngier +Cc: Will Deacon +Reviewed-by: Marc Zyngier +Acked-by: Mark Rutland +Signed-off-by: Julien Thierry +Signed-off-by: Catalin Marinas +Signed-off-by: Greg Kroah-Hartman + +--- + arch/arm64/include/asm/irqflags.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/arm64/include/asm/irqflags.h ++++ b/arch/arm64/include/asm/irqflags.h +@@ -81,7 +81,7 @@ static inline unsigned long arch_local_s + ARM64_HAS_IRQ_PRIO_MASKING) + : "=&r" (flags), "+r" (daif_bits) + : "r" ((unsigned long) GIC_PRIO_IRQOFF) +- : "memory"); ++ : "cc", "memory"); + + return flags; + } +@@ -125,7 +125,7 @@ static inline int arch_irqs_disabled_fla + ARM64_HAS_IRQ_PRIO_MASKING) + : "=&r" (res) + : "r" ((int) flags) +- : "memory"); ++ : "cc", "memory"); + + return res; + } diff --git a/queue-5.2/arm64-tegra-fix-agic-register-range.patch b/queue-5.2/arm64-tegra-fix-agic-register-range.patch new file mode 100644 index 00000000000..a329a9b919e --- /dev/null +++ b/queue-5.2/arm64-tegra-fix-agic-register-range.patch @@ -0,0 +1,38 @@ +From ba24eee6686f6ed3738602b54d959253316a9541 Mon Sep 17 00:00:00 2001 +From: Jon Hunter +Date: Thu, 20 Jun 2019 09:17:00 +0100 +Subject: arm64: tegra: Fix AGIC register range + +From: Jon Hunter + +commit ba24eee6686f6ed3738602b54d959253316a9541 upstream. + +The Tegra AGIC interrupt controller is an ARM GIC400 interrupt +controller. Per the ARM GIC device-tree binding, the first address +region is for the GIC distributor registers and the second address +region is for the GIC CPU interface registers. The address space for +the distributor registers is 4kB, but currently this is incorrectly +defined as 8kB for the Tegra AGIC and overlaps with the CPU interface +registers. Correct the address space for the distributor to be 4kB. + +Cc: stable@vger.kernel.org +Signed-off-by: Jon Hunter +Fixes: bcdbde433542 ("arm64: tegra: Add AGIC node for Tegra210") +Signed-off-by: Thierry Reding +Signed-off-by: Greg Kroah-Hartman + +--- + arch/arm64/boot/dts/nvidia/tegra210.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi ++++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi +@@ -1258,7 +1258,7 @@ + compatible = "nvidia,tegra210-agic"; + #interrupt-cells = <3>; + interrupt-controller; +- reg = <0x702f9000 0x2000>, ++ reg = <0x702f9000 0x1000>, + <0x702fa000 0x2000>; + interrupts = ; + clocks = <&tegra_car TEGRA210_CLK_APE>; diff --git a/queue-5.2/fs-proc-proc_sysctl.c-fix-the-default-values-of-i_uid-i_gid-on-proc-sys-inodes.patch b/queue-5.2/fs-proc-proc_sysctl.c-fix-the-default-values-of-i_uid-i_gid-on-proc-sys-inodes.patch new file mode 100644 index 00000000000..583c2c0d16f --- /dev/null +++ b/queue-5.2/fs-proc-proc_sysctl.c-fix-the-default-values-of-i_uid-i_gid-on-proc-sys-inodes.patch @@ -0,0 +1,87 @@ +From 5ec27ec735ba0477d48c80561cc5e856f0c5dfaf Mon Sep 17 00:00:00 2001 +From: Radoslaw Burny +Date: Tue, 16 Jul 2019 16:26:51 -0700 +Subject: fs/proc/proc_sysctl.c: fix the default values of i_uid/i_gid on /proc/sys inodes. + +From: Radoslaw Burny + +commit 5ec27ec735ba0477d48c80561cc5e856f0c5dfaf upstream. + +Normally, the inode's i_uid/i_gid are translated relative to s_user_ns, +but this is not a correct behavior for proc. Since sysctl permission +check in test_perm is done against GLOBAL_ROOT_[UG]ID, it makes more +sense to use these values in u_[ug]id of proc inodes. In other words: +although uid/gid in the inode is not read during test_perm, the inode +logically belongs to the root of the namespace. I have confirmed this +with Eric Biederman at LPC and in this thread: + https://lore.kernel.org/lkml/87k1kzjdff.fsf@xmission.com + +Consequences +============ + +Since the i_[ug]id values of proc nodes are not used for permissions +checks, this change usually makes no functional difference. However, it +causes an issue in a setup where: + + * a namespace container is created without root user in container - + hence the i_[ug]id of proc nodes are set to INVALID_[UG]ID + + * container creator tries to configure it by writing /proc/sys files, + e.g. writing /proc/sys/kernel/shmmax to configure shared memory limit + +Kernel does not allow to open an inode for writing if its i_[ug]id are +invalid, making it impossible to write shmmax and thus - configure the +container. + +Using a container with no root mapping is apparently rare, but we do use +this configuration at Google. Also, we use a generic tool to configure +the container limits, and the inability to write any of them causes a +failure. + +History +======= + +The invalid uids/gids in inodes first appeared due to 81754357770e (fs: +Update i_[ug]id_(read|write) to translate relative to s_user_ns). +However, AFAIK, this did not immediately cause any issues. The +inability to write to these "invalid" inodes was only caused by a later +commit 0bd23d09b874 (vfs: Don't modify inodes with a uid or gid unknown +to the vfs). + +Tested: Used a repro program that creates a user namespace without any +mapping and stat'ed /proc/$PID/root/proc/sys/kernel/shmmax from outside. +Before the change, it shows the overflow uid, with the change it's 0. +The overflow uid indicates that the uid in the inode is not correct and +thus it is not possible to open the file for writing. + +Link: http://lkml.kernel.org/r/20190708115130.250149-1-rburny@google.com +Fixes: 0bd23d09b874 ("vfs: Don't modify inodes with a uid or gid unknown to the vfs") +Signed-off-by: Radoslaw Burny +Acked-by: Luis Chamberlain +Cc: Kees Cook +Cc: "Eric W . Biederman" +Cc: Seth Forshee +Cc: John Sperbeck +Cc: Alexey Dobriyan +Cc: [4.8+] +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/proc/proc_sysctl.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/fs/proc/proc_sysctl.c ++++ b/fs/proc/proc_sysctl.c +@@ -499,6 +499,10 @@ static struct inode *proc_sys_make_inode + + if (root->set_ownership) + root->set_ownership(head, table, &inode->i_uid, &inode->i_gid); ++ else { ++ inode->i_uid = GLOBAL_ROOT_UID; ++ inode->i_gid = GLOBAL_ROOT_GID; ++ } + + return inode; + } diff --git a/queue-5.2/i3c-fix-i2c-and-i3c-scl-rate-by-bus-mode.patch b/queue-5.2/i3c-fix-i2c-and-i3c-scl-rate-by-bus-mode.patch new file mode 100644 index 00000000000..7f5a31e3791 --- /dev/null +++ b/queue-5.2/i3c-fix-i2c-and-i3c-scl-rate-by-bus-mode.patch @@ -0,0 +1,123 @@ +From ecc8fb54bd443bf69996d9d5ddb8d90a50f14936 Mon Sep 17 00:00:00 2001 +From: Vitor Soares +Date: Wed, 19 Jun 2019 20:36:31 +0200 +Subject: i3c: fix i2c and i3c scl rate by bus mode + +From: Vitor Soares + +commit ecc8fb54bd443bf69996d9d5ddb8d90a50f14936 upstream. + +Currently the I3C framework limits SCL frequency to FM speed when +dealing with a mixed slow bus, even if all I2C devices are FM+ capable. + +The core was also not accounting for I3C speed limitations when +operating in mixed slow mode and was erroneously using FM+ speed as the +max I2C speed when operating in mixed fast mode. + +Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") +Signed-off-by: Vitor Soares +Cc: Boris Brezillon +Cc: +Cc: +Signed-off-by: Boris Brezillon +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/i3c/master.c | 51 ++++++++++++++++++++++++++++++++++++++------------- + 1 file changed, 38 insertions(+), 13 deletions(-) + +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -91,6 +91,12 @@ void i3c_bus_normaluse_unlock(struct i3c + up_read(&bus->lock); + } + ++static struct i3c_master_controller * ++i3c_bus_to_i3c_master(struct i3c_bus *i3cbus) ++{ ++ return container_of(i3cbus, struct i3c_master_controller, bus); ++} ++ + static struct i3c_master_controller *dev_to_i3cmaster(struct device *dev) + { + return container_of(dev, struct i3c_master_controller, dev); +@@ -565,20 +571,38 @@ static const struct device_type i3c_mast + .groups = i3c_masterdev_groups, + }; + +-int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode) ++int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode, ++ unsigned long max_i2c_scl_rate) + { +- i3cbus->mode = mode; ++ struct i3c_master_controller *master = i3c_bus_to_i3c_master(i3cbus); + +- if (!i3cbus->scl_rate.i3c) +- i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; ++ i3cbus->mode = mode; + +- if (!i3cbus->scl_rate.i2c) { +- if (i3cbus->mode == I3C_BUS_MODE_MIXED_SLOW) +- i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; +- else +- i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_PLUS_SCL_RATE; ++ switch (i3cbus->mode) { ++ case I3C_BUS_MODE_PURE: ++ if (!i3cbus->scl_rate.i3c) ++ i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; ++ break; ++ case I3C_BUS_MODE_MIXED_FAST: ++ if (!i3cbus->scl_rate.i3c) ++ i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; ++ if (!i3cbus->scl_rate.i2c) ++ i3cbus->scl_rate.i2c = max_i2c_scl_rate; ++ break; ++ case I3C_BUS_MODE_MIXED_SLOW: ++ if (!i3cbus->scl_rate.i2c) ++ i3cbus->scl_rate.i2c = max_i2c_scl_rate; ++ if (!i3cbus->scl_rate.i3c || ++ i3cbus->scl_rate.i3c > i3cbus->scl_rate.i2c) ++ i3cbus->scl_rate.i3c = i3cbus->scl_rate.i2c; ++ break; ++ default: ++ return -EINVAL; + } + ++ dev_dbg(&master->dev, "i2c-scl = %ld Hz i3c-scl = %ld Hz\n", ++ i3cbus->scl_rate.i2c, i3cbus->scl_rate.i3c); ++ + /* + * I3C/I2C frequency may have been overridden, check that user-provided + * values are not exceeding max possible frequency. +@@ -1966,9 +1990,6 @@ of_i3c_master_add_i2c_boardinfo(struct i + /* LVR is encoded in reg[2]. */ + boardinfo->lvr = reg[2]; + +- if (boardinfo->lvr & I3C_LVR_I2C_FM_MODE) +- master->bus.scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE; +- + list_add_tail(&boardinfo->node, &master->boardinfo.i2c); + of_node_get(node); + +@@ -2417,6 +2438,7 @@ int i3c_master_register(struct i3c_maste + const struct i3c_master_controller_ops *ops, + bool secondary) + { ++ unsigned long i2c_scl_rate = I3C_BUS_I2C_FM_PLUS_SCL_RATE; + struct i3c_bus *i3cbus = i3c_master_get_bus(master); + enum i3c_bus_mode mode = I3C_BUS_MODE_PURE; + struct i2c_dev_boardinfo *i2cbi; +@@ -2466,9 +2488,12 @@ int i3c_master_register(struct i3c_maste + ret = -EINVAL; + goto err_put_dev; + } ++ ++ if (i2cbi->lvr & I3C_LVR_I2C_FM_MODE) ++ i2c_scl_rate = I3C_BUS_I2C_FM_SCL_RATE; + } + +- ret = i3c_bus_set_mode(i3cbus, mode); ++ ret = i3c_bus_set_mode(i3cbus, mode, i2c_scl_rate); + if (ret) + goto err_put_dev; + diff --git a/queue-5.2/intel_th-msu-fix-unused-variable-warning-on-arm64-platform.patch b/queue-5.2/intel_th-msu-fix-unused-variable-warning-on-arm64-platform.patch new file mode 100644 index 00000000000..580434f1a08 --- /dev/null +++ b/queue-5.2/intel_th-msu-fix-unused-variable-warning-on-arm64-platform.patch @@ -0,0 +1,120 @@ +From b96fb368b08f1637cbf780a6b83e36c2c5ed4ff5 Mon Sep 17 00:00:00 2001 +From: Shaokun Zhang +Date: Fri, 21 Jun 2019 19:19:27 +0300 +Subject: intel_th: msu: Fix unused variable warning on arm64 platform +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Shaokun Zhang + +commit b96fb368b08f1637cbf780a6b83e36c2c5ed4ff5 upstream. + +Commit ba39bd8306057 ("intel_th: msu: Switch over to scatterlist") +introduced the following warnings on non-x86 architectures, as a result +of reordering the multi mode buffer allocation sequence: + +> drivers/hwtracing/intel_th/msu.c: In function ‘msc_buffer_win_alloc’: +> drivers/hwtracing/intel_th/msu.c:783:21: warning: unused variable ‘i’ +> [-Wunused-variable] +> int ret = -ENOMEM, i; +> ^ +> drivers/hwtracing/intel_th/msu.c: In function ‘msc_buffer_win_free’: +> drivers/hwtracing/intel_th/msu.c:863:6: warning: unused variable ‘i’ +> [-Wunused-variable] +> int i; +> ^ + +Fix this compiler warning by factoring out set_memory sequences and making +them x86-only. + +Suggested-by: Alexander Shishkin +Signed-off-by: Shaokun Zhang +Fixes: ba39bd8306057 ("intel_th: msu: Switch over to scatterlist") +Reviewed-by: Andy Shevchenko +Signed-off-by: Alexander Shishkin +Cc: stable +Link: https://lore.kernel.org/r/20190621161930.60785-2-alexander.shishkin@linux.intel.com +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/hwtracing/intel_th/msu.c | 40 ++++++++++++++++++++++++++------------- + 1 file changed, 27 insertions(+), 13 deletions(-) + +--- a/drivers/hwtracing/intel_th/msu.c ++++ b/drivers/hwtracing/intel_th/msu.c +@@ -767,6 +767,30 @@ err_nomem: + return -ENOMEM; + } + ++#ifdef CONFIG_X86 ++static void msc_buffer_set_uc(struct msc_window *win, unsigned int nr_blocks) ++{ ++ int i; ++ ++ for (i = 0; i < nr_blocks; i++) ++ /* Set the page as uncached */ ++ set_memory_uc((unsigned long)msc_win_block(win, i), 1); ++} ++ ++static void msc_buffer_set_wb(struct msc_window *win) ++{ ++ int i; ++ ++ for (i = 0; i < win->nr_blocks; i++) ++ /* Reset the page to write-back */ ++ set_memory_wb((unsigned long)msc_win_block(win, i), 1); ++} ++#else /* !X86 */ ++static inline void ++msc_buffer_set_uc(struct msc_window *win, unsigned int nr_blocks) {} ++static inline void msc_buffer_set_wb(struct msc_window *win) {} ++#endif /* CONFIG_X86 */ ++ + /** + * msc_buffer_win_alloc() - alloc a window for a multiblock mode + * @msc: MSC device +@@ -780,7 +804,7 @@ err_nomem: + static int msc_buffer_win_alloc(struct msc *msc, unsigned int nr_blocks) + { + struct msc_window *win; +- int ret = -ENOMEM, i; ++ int ret = -ENOMEM; + + if (!nr_blocks) + return 0; +@@ -811,11 +835,7 @@ static int msc_buffer_win_alloc(struct m + if (ret < 0) + goto err_nomem; + +-#ifdef CONFIG_X86 +- for (i = 0; i < ret; i++) +- /* Set the page as uncached */ +- set_memory_uc((unsigned long)msc_win_block(win, i), 1); +-#endif ++ msc_buffer_set_uc(win, ret); + + win->nr_blocks = ret; + +@@ -860,8 +880,6 @@ static void __msc_buffer_win_free(struct + */ + static void msc_buffer_win_free(struct msc *msc, struct msc_window *win) + { +- int i; +- + msc->nr_pages -= win->nr_blocks; + + list_del(&win->entry); +@@ -870,11 +888,7 @@ static void msc_buffer_win_free(struct m + msc->base_addr = 0; + } + +-#ifdef CONFIG_X86 +- for (i = 0; i < win->nr_blocks; i++) +- /* Reset the page to write-back */ +- set_memory_wb((unsigned long)msc_win_block(win, i), 1); +-#endif ++ msc_buffer_set_wb(win); + + __msc_buffer_win_free(msc, win); + diff --git a/queue-5.2/series b/queue-5.2/series index bbaee68bdbd..e06409bfb3c 100644 --- a/queue-5.2/series +++ b/queue-5.2/series @@ -333,3 +333,11 @@ kvm-ppc-book3s-hv-signed-extend-decrementer-value-if-not-using-large-decrementer kvm-ppc-book3s-hv-clear-pending-decrementer-exceptions-on-nested-guest-entry.patch kvm-ppc-book3s-hv-fix-cr0-setting-in-tm-emulation.patch kvm-x86-vpmu-refine-kvm_pmu-err-msg-when-event-creation-failed.patch +arm64-tegra-fix-agic-register-range.patch +arm64-irqflags-add-condition-flags-to-inline-asm-clobber-list.patch +arm64-fix-incorrect-irqflag-restore-for-priority-masking.patch +intel_th-msu-fix-unused-variable-warning-on-arm64-platform.patch +signal-usb-replace-kill_pid_info_as_cred-with-kill_pid_usb_asyncio.patch +signal-correct-namespace-fixups-of-si_pid-and-si_uid.patch +fs-proc-proc_sysctl.c-fix-the-default-values-of-i_uid-i_gid-on-proc-sys-inodes.patch +i3c-fix-i2c-and-i3c-scl-rate-by-bus-mode.patch diff --git a/queue-5.2/signal-correct-namespace-fixups-of-si_pid-and-si_uid.patch b/queue-5.2/signal-correct-namespace-fixups-of-si_pid-and-si_uid.patch new file mode 100644 index 00000000000..b4e95aa1b9b --- /dev/null +++ b/queue-5.2/signal-correct-namespace-fixups-of-si_pid-and-si_uid.patch @@ -0,0 +1,142 @@ +From 7a0cf094944e2540758b7f957eb6846d5126f535 Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Wed, 15 May 2019 22:54:56 -0500 +Subject: signal: Correct namespace fixups of si_pid and si_uid + +From: Eric W. Biederman + +commit 7a0cf094944e2540758b7f957eb6846d5126f535 upstream. + +The function send_signal was split from __send_signal so that it would +be possible to bypass the namespace logic based upon current[1]. As it +turns out the si_pid and the si_uid fixup are both inappropriate in +the case of kill_pid_usb_asyncio so move that logic into send_signal. + +It is difficult to arrange but possible for a signal with an si_code +of SI_TIMER or SI_SIGIO to be sent across namespace boundaries. In +which case tests for when it is ok to change si_pid and si_uid based +on SI_FROMUSER are incorrect. Replace the use of SI_FROMUSER with a +new test has_si_pid_and_used based on siginfo_layout. + +Now that the uid fixup is no longer present after expanding +SEND_SIG_NOINFO properly calculate the si_uid that the target +task needs to read. + +[1] 7978b567d315 ("signals: add from_ancestor_ns parameter to send_signal()") +Cc: stable@vger.kernel.org +Fixes: 6588c1e3ff01 ("signals: SI_USER: Masquerade si_pid when crossing pid ns boundary") +Fixes: 6b550f949594 ("user namespace: make signal.c respect user namespaces") +Signed-off-by: "Eric W. Biederman" +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/signal.c | 67 +++++++++++++++++++++++++++++++++----------------------- + 1 file changed, 40 insertions(+), 27 deletions(-) + +--- a/kernel/signal.c ++++ b/kernel/signal.c +@@ -1057,27 +1057,6 @@ static inline bool legacy_queue(struct s + return (sig < SIGRTMIN) && sigismember(&signals->signal, sig); + } + +-#ifdef CONFIG_USER_NS +-static inline void userns_fixup_signal_uid(struct kernel_siginfo *info, struct task_struct *t) +-{ +- if (current_user_ns() == task_cred_xxx(t, user_ns)) +- return; +- +- if (SI_FROMKERNEL(info)) +- return; +- +- rcu_read_lock(); +- info->si_uid = from_kuid_munged(task_cred_xxx(t, user_ns), +- make_kuid(current_user_ns(), info->si_uid)); +- rcu_read_unlock(); +-} +-#else +-static inline void userns_fixup_signal_uid(struct kernel_siginfo *info, struct task_struct *t) +-{ +- return; +-} +-#endif +- + static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struct *t, + enum pid_type type, int from_ancestor_ns) + { +@@ -1135,7 +1114,11 @@ static int __send_signal(int sig, struct + q->info.si_code = SI_USER; + q->info.si_pid = task_tgid_nr_ns(current, + task_active_pid_ns(t)); +- q->info.si_uid = from_kuid_munged(current_user_ns(), current_uid()); ++ rcu_read_lock(); ++ q->info.si_uid = ++ from_kuid_munged(task_cred_xxx(t, user_ns), ++ current_uid()); ++ rcu_read_unlock(); + break; + case (unsigned long) SEND_SIG_PRIV: + clear_siginfo(&q->info); +@@ -1147,13 +1130,8 @@ static int __send_signal(int sig, struct + break; + default: + copy_siginfo(&q->info, info); +- if (from_ancestor_ns) +- q->info.si_pid = 0; + break; + } +- +- userns_fixup_signal_uid(&q->info, t); +- + } else if (!is_si_special(info)) { + if (sig >= SIGRTMIN && info->si_code != SI_USER) { + /* +@@ -1197,6 +1175,28 @@ ret: + return ret; + } + ++static inline bool has_si_pid_and_uid(struct kernel_siginfo *info) ++{ ++ bool ret = false; ++ switch (siginfo_layout(info->si_signo, info->si_code)) { ++ case SIL_KILL: ++ case SIL_CHLD: ++ case SIL_RT: ++ ret = true; ++ break; ++ case SIL_TIMER: ++ case SIL_POLL: ++ case SIL_FAULT: ++ case SIL_FAULT_MCEERR: ++ case SIL_FAULT_BNDERR: ++ case SIL_FAULT_PKUERR: ++ case SIL_SYS: ++ ret = false; ++ break; ++ } ++ return ret; ++} ++ + static int send_signal(int sig, struct kernel_siginfo *info, struct task_struct *t, + enum pid_type type) + { +@@ -1206,7 +1206,20 @@ static int send_signal(int sig, struct k + from_ancestor_ns = si_fromuser(info) && + !task_pid_nr_ns(current, task_active_pid_ns(t)); + #endif ++ if (!is_si_special(info) && has_si_pid_and_uid(info)) { ++ struct user_namespace *t_user_ns; ++ ++ rcu_read_lock(); ++ t_user_ns = task_cred_xxx(t, user_ns); ++ if (current_user_ns() != t_user_ns) { ++ kuid_t uid = make_kuid(current_user_ns(), info->si_uid); ++ info->si_uid = from_kuid_munged(t_user_ns, uid); ++ } ++ rcu_read_unlock(); + ++ if (!task_pid_nr_ns(current, task_active_pid_ns(t))) ++ info->si_pid = 0; ++ } + return __send_signal(sig, info, t, type, from_ancestor_ns); + } + diff --git a/queue-5.2/signal-usb-replace-kill_pid_info_as_cred-with-kill_pid_usb_asyncio.patch b/queue-5.2/signal-usb-replace-kill_pid_info_as_cred-with-kill_pid_usb_asyncio.patch new file mode 100644 index 00000000000..1caeda68876 --- /dev/null +++ b/queue-5.2/signal-usb-replace-kill_pid_info_as_cred-with-kill_pid_usb_asyncio.patch @@ -0,0 +1,458 @@ +From 70f1b0d34bdf03065fe869e93cc17cad1ea20c4a Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Thu, 7 Feb 2019 19:44:12 -0600 +Subject: signal/usb: Replace kill_pid_info_as_cred with kill_pid_usb_asyncio + +From: Eric W. Biederman + +commit 70f1b0d34bdf03065fe869e93cc17cad1ea20c4a upstream. + +The usb support for asyncio encoded one of it's values in the wrong +field. It should have used si_value but instead used si_addr which is +not present in the _rt union member of struct siginfo. + +The practical result of this is that on a 64bit big endian kernel +when delivering a signal to a 32bit process the si_addr field +is set to NULL, instead of the expected pointer value. + +This issue can not be fixed in copy_siginfo_to_user32 as the usb +usage of the the _sigfault (aka si_addr) member of the siginfo +union when SI_ASYNCIO is set is incompatible with the POSIX and +glibc usage of the _rt member of the siginfo union. + +Therefore replace kill_pid_info_as_cred with kill_pid_usb_asyncio a +dedicated function for this one specific case. There are no other +users of kill_pid_info_as_cred so this specialization should have no +impact on the amount of code in the kernel. Have kill_pid_usb_asyncio +take instead of a siginfo_t which is difficult and error prone, 3 +arguments, a signal number, an errno value, and an address enconded as +a sigval_t. The encoding of the address as a sigval_t allows the +code that reads the userspace request for a signal to handle this +compat issue along with all of the other compat issues. + +Add BUILD_BUG_ONs in kernel/signal.c to ensure that we can now place +the pointer value at the in si_pid (instead of si_addr). That is the +code now verifies that si_pid and si_addr always occur at the same +location. Further the code veries that for native structures a value +placed in si_pid and spilling into si_uid will appear in userspace in +si_addr (on a byte by byte copy of siginfo or a field by field copy of +siginfo). The code also verifies that for a 64bit kernel and a 32bit +userspace the 32bit pointer will fit in si_pid. + +I have used the usbsig.c program below written by Alan Stern and +slightly tweaked by me to run on a big endian machine to verify the +issue exists (on sparc64) and to confirm the patch below fixes the issue. + + /* usbsig.c -- test USB async signal delivery */ + + #define _GNU_SOURCE + #include + #include + #include + #include + #include + #include + #include + #include + #include + + static struct usbdevfs_urb urb; + static struct usbdevfs_disconnectsignal ds; + static volatile sig_atomic_t done = 0; + + void urb_handler(int sig, siginfo_t *info , void *ucontext) + { + printf("Got signal %d, signo %d errno %d code %d addr: %p urb: %p\n", + sig, info->si_signo, info->si_errno, info->si_code, + info->si_addr, &urb); + + printf("%s\n", (info->si_addr == &urb) ? "Good" : "Bad"); + } + + void ds_handler(int sig, siginfo_t *info , void *ucontext) + { + printf("Got signal %d, signo %d errno %d code %d addr: %p ds: %p\n", + sig, info->si_signo, info->si_errno, info->si_code, + info->si_addr, &ds); + + printf("%s\n", (info->si_addr == &ds) ? "Good" : "Bad"); + done = 1; + } + + int main(int argc, char **argv) + { + char *devfilename; + int fd; + int rc; + struct sigaction act; + struct usb_ctrlrequest *req; + void *ptr; + char buf[80]; + + if (argc != 2) { + fprintf(stderr, "Usage: usbsig device-file-name\n"); + return 1; + } + + devfilename = argv[1]; + fd = open(devfilename, O_RDWR); + if (fd == -1) { + perror("Error opening device file"); + return 1; + } + + act.sa_sigaction = urb_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + + rc = sigaction(SIGUSR1, &act, NULL); + if (rc == -1) { + perror("Error in sigaction"); + return 1; + } + + act.sa_sigaction = ds_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + + rc = sigaction(SIGUSR2, &act, NULL); + if (rc == -1) { + perror("Error in sigaction"); + return 1; + } + + memset(&urb, 0, sizeof(urb)); + urb.type = USBDEVFS_URB_TYPE_CONTROL; + urb.endpoint = USB_DIR_IN | 0; + urb.buffer = buf; + urb.buffer_length = sizeof(buf); + urb.signr = SIGUSR1; + + req = (struct usb_ctrlrequest *) buf; + req->bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; + req->bRequest = USB_REQ_GET_DESCRIPTOR; + req->wValue = htole16(USB_DT_DEVICE << 8); + req->wIndex = htole16(0); + req->wLength = htole16(sizeof(buf) - sizeof(*req)); + + rc = ioctl(fd, USBDEVFS_SUBMITURB, &urb); + if (rc == -1) { + perror("Error in SUBMITURB ioctl"); + return 1; + } + + rc = ioctl(fd, USBDEVFS_REAPURB, &ptr); + if (rc == -1) { + perror("Error in REAPURB ioctl"); + return 1; + } + + memset(&ds, 0, sizeof(ds)); + ds.signr = SIGUSR2; + ds.context = &ds; + rc = ioctl(fd, USBDEVFS_DISCSIGNAL, &ds); + if (rc == -1) { + perror("Error in DISCSIGNAL ioctl"); + return 1; + } + + printf("Waiting for usb disconnect\n"); + while (!done) { + sleep(1); + } + + close(fd); + return 0; + } + +Cc: Greg Kroah-Hartman +Cc: linux-usb@vger.kernel.org +Cc: Alan Stern +Cc: Oliver Neukum +Fixes: v2.3.39 +Cc: stable@vger.kernel.org +Acked-by: Alan Stern +Signed-off-by: "Eric W. Biederman" +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/core/devio.c | 48 ++++++++++++++--------------- + include/linux/sched/signal.h | 2 - + kernel/signal.c | 69 ++++++++++++++++++++++++++++++++++++++----- + 3 files changed, 86 insertions(+), 33 deletions(-) + +--- a/drivers/usb/core/devio.c ++++ b/drivers/usb/core/devio.c +@@ -63,7 +63,7 @@ struct usb_dev_state { + unsigned int discsignr; + struct pid *disc_pid; + const struct cred *cred; +- void __user *disccontext; ++ sigval_t disccontext; + unsigned long ifclaimed; + u32 disabled_bulk_eps; + bool privileges_dropped; +@@ -90,6 +90,7 @@ struct async { + unsigned int ifnum; + void __user *userbuffer; + void __user *userurb; ++ sigval_t userurb_sigval; + struct urb *urb; + struct usb_memory *usbm; + unsigned int mem_usage; +@@ -582,22 +583,19 @@ static void async_completed(struct urb * + { + struct async *as = urb->context; + struct usb_dev_state *ps = as->ps; +- struct kernel_siginfo sinfo; + struct pid *pid = NULL; + const struct cred *cred = NULL; + unsigned long flags; +- int signr; ++ sigval_t addr; ++ int signr, errno; + + spin_lock_irqsave(&ps->lock, flags); + list_move_tail(&as->asynclist, &ps->async_completed); + as->status = urb->status; + signr = as->signr; + if (signr) { +- clear_siginfo(&sinfo); +- sinfo.si_signo = as->signr; +- sinfo.si_errno = as->status; +- sinfo.si_code = SI_ASYNCIO; +- sinfo.si_addr = as->userurb; ++ errno = as->status; ++ addr = as->userurb_sigval; + pid = get_pid(as->pid); + cred = get_cred(as->cred); + } +@@ -615,7 +613,7 @@ static void async_completed(struct urb * + spin_unlock_irqrestore(&ps->lock, flags); + + if (signr) { +- kill_pid_info_as_cred(sinfo.si_signo, &sinfo, pid, cred); ++ kill_pid_usb_asyncio(signr, errno, addr, pid, cred); + put_pid(pid); + put_cred(cred); + } +@@ -1427,7 +1425,7 @@ find_memory_area(struct usb_dev_state *p + + static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb, + struct usbdevfs_iso_packet_desc __user *iso_frame_desc, +- void __user *arg) ++ void __user *arg, sigval_t userurb_sigval) + { + struct usbdevfs_iso_packet_desc *isopkt = NULL; + struct usb_host_endpoint *ep; +@@ -1727,6 +1725,7 @@ static int proc_do_submiturb(struct usb_ + isopkt = NULL; + as->ps = ps; + as->userurb = arg; ++ as->userurb_sigval = userurb_sigval; + if (as->usbm) { + unsigned long uurb_start = (unsigned long)uurb->buffer; + +@@ -1801,13 +1800,17 @@ static int proc_do_submiturb(struct usb_ + static int proc_submiturb(struct usb_dev_state *ps, void __user *arg) + { + struct usbdevfs_urb uurb; ++ sigval_t userurb_sigval; + + if (copy_from_user(&uurb, arg, sizeof(uurb))) + return -EFAULT; + ++ memset(&userurb_sigval, 0, sizeof(userurb_sigval)); ++ userurb_sigval.sival_ptr = arg; ++ + return proc_do_submiturb(ps, &uurb, + (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), +- arg); ++ arg, userurb_sigval); + } + + static int proc_unlinkurb(struct usb_dev_state *ps, void __user *arg) +@@ -1977,7 +1980,7 @@ static int proc_disconnectsignal_compat( + if (copy_from_user(&ds, arg, sizeof(ds))) + return -EFAULT; + ps->discsignr = ds.signr; +- ps->disccontext = compat_ptr(ds.context); ++ ps->disccontext.sival_int = ds.context; + return 0; + } + +@@ -2005,13 +2008,17 @@ static int get_urb32(struct usbdevfs_urb + static int proc_submiturb_compat(struct usb_dev_state *ps, void __user *arg) + { + struct usbdevfs_urb uurb; ++ sigval_t userurb_sigval; + + if (get_urb32(&uurb, (struct usbdevfs_urb32 __user *)arg)) + return -EFAULT; + ++ memset(&userurb_sigval, 0, sizeof(userurb_sigval)); ++ userurb_sigval.sival_int = ptr_to_compat(arg); ++ + return proc_do_submiturb(ps, &uurb, + ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, +- arg); ++ arg, userurb_sigval); + } + + static int processcompl_compat(struct async *as, void __user * __user *arg) +@@ -2092,7 +2099,7 @@ static int proc_disconnectsignal(struct + if (copy_from_user(&ds, arg, sizeof(ds))) + return -EFAULT; + ps->discsignr = ds.signr; +- ps->disccontext = ds.context; ++ ps->disccontext.sival_ptr = ds.context; + return 0; + } + +@@ -2614,22 +2621,15 @@ const struct file_operations usbdev_file + static void usbdev_remove(struct usb_device *udev) + { + struct usb_dev_state *ps; +- struct kernel_siginfo sinfo; + + while (!list_empty(&udev->filelist)) { + ps = list_entry(udev->filelist.next, struct usb_dev_state, list); + destroy_all_async(ps); + wake_up_all(&ps->wait); + list_del_init(&ps->list); +- if (ps->discsignr) { +- clear_siginfo(&sinfo); +- sinfo.si_signo = ps->discsignr; +- sinfo.si_errno = EPIPE; +- sinfo.si_code = SI_ASYNCIO; +- sinfo.si_addr = ps->disccontext; +- kill_pid_info_as_cred(ps->discsignr, &sinfo, +- ps->disc_pid, ps->cred); +- } ++ if (ps->discsignr) ++ kill_pid_usb_asyncio(ps->discsignr, EPIPE, ps->disccontext, ++ ps->disc_pid, ps->cred); + } + } + +--- a/include/linux/sched/signal.h ++++ b/include/linux/sched/signal.h +@@ -329,7 +329,7 @@ extern void force_sigsegv(int sig, struc + extern int force_sig_info(int, struct kernel_siginfo *, struct task_struct *); + extern int __kill_pgrp_info(int sig, struct kernel_siginfo *info, struct pid *pgrp); + extern int kill_pid_info(int sig, struct kernel_siginfo *info, struct pid *pid); +-extern int kill_pid_info_as_cred(int, struct kernel_siginfo *, struct pid *, ++extern int kill_pid_usb_asyncio(int sig, int errno, sigval_t addr, struct pid *, + const struct cred *); + extern int kill_pgrp(struct pid *pid, int sig, int priv); + extern int kill_pid(struct pid *pid, int sig, int priv); +--- a/kernel/signal.c ++++ b/kernel/signal.c +@@ -1440,13 +1440,44 @@ static inline bool kill_as_cred_perm(con + uid_eq(cred->uid, pcred->uid); + } + +-/* like kill_pid_info(), but doesn't use uid/euid of "current" */ +-int kill_pid_info_as_cred(int sig, struct kernel_siginfo *info, struct pid *pid, +- const struct cred *cred) ++/* ++ * The usb asyncio usage of siginfo is wrong. The glibc support ++ * for asyncio which uses SI_ASYNCIO assumes the layout is SIL_RT. ++ * AKA after the generic fields: ++ * kernel_pid_t si_pid; ++ * kernel_uid32_t si_uid; ++ * sigval_t si_value; ++ * ++ * Unfortunately when usb generates SI_ASYNCIO it assumes the layout ++ * after the generic fields is: ++ * void __user *si_addr; ++ * ++ * This is a practical problem when there is a 64bit big endian kernel ++ * and a 32bit userspace. As the 32bit address will encoded in the low ++ * 32bits of the pointer. Those low 32bits will be stored at higher ++ * address than appear in a 32 bit pointer. So userspace will not ++ * see the address it was expecting for it's completions. ++ * ++ * There is nothing in the encoding that can allow ++ * copy_siginfo_to_user32 to detect this confusion of formats, so ++ * handle this by requiring the caller of kill_pid_usb_asyncio to ++ * notice when this situration takes place and to store the 32bit ++ * pointer in sival_int, instead of sival_addr of the sigval_t addr ++ * parameter. ++ */ ++int kill_pid_usb_asyncio(int sig, int errno, sigval_t addr, ++ struct pid *pid, const struct cred *cred) + { +- int ret = -EINVAL; ++ struct kernel_siginfo info; + struct task_struct *p; + unsigned long flags; ++ int ret = -EINVAL; ++ ++ clear_siginfo(&info); ++ info.si_signo = sig; ++ info.si_errno = errno; ++ info.si_code = SI_ASYNCIO; ++ *((sigval_t *)&info.si_pid) = addr; + + if (!valid_signal(sig)) + return ret; +@@ -1457,17 +1488,17 @@ int kill_pid_info_as_cred(int sig, struc + ret = -ESRCH; + goto out_unlock; + } +- if (si_fromuser(info) && !kill_as_cred_perm(cred, p)) { ++ if (!kill_as_cred_perm(cred, p)) { + ret = -EPERM; + goto out_unlock; + } +- ret = security_task_kill(p, info, sig, cred); ++ ret = security_task_kill(p, &info, sig, cred); + if (ret) + goto out_unlock; + + if (sig) { + if (lock_task_sighand(p, &flags)) { +- ret = __send_signal(sig, info, p, PIDTYPE_TGID, 0); ++ ret = __send_signal(sig, &info, p, PIDTYPE_TGID, 0); + unlock_task_sighand(p, &flags); + } else + ret = -ESRCH; +@@ -1476,7 +1507,7 @@ out_unlock: + rcu_read_unlock(); + return ret; + } +-EXPORT_SYMBOL_GPL(kill_pid_info_as_cred); ++EXPORT_SYMBOL_GPL(kill_pid_usb_asyncio); + + /* + * kill_something_info() interprets pid in interesting ways just like kill(2). +@@ -4477,6 +4508,28 @@ static inline void siginfo_buildtime_che + CHECK_OFFSET(si_syscall); + CHECK_OFFSET(si_arch); + #undef CHECK_OFFSET ++ ++ /* usb asyncio */ ++ BUILD_BUG_ON(offsetof(struct siginfo, si_pid) != ++ offsetof(struct siginfo, si_addr)); ++ if (sizeof(int) == sizeof(void __user *)) { ++ BUILD_BUG_ON(sizeof_field(struct siginfo, si_pid) != ++ sizeof(void __user *)); ++ } else { ++ BUILD_BUG_ON((sizeof_field(struct siginfo, si_pid) + ++ sizeof_field(struct siginfo, si_uid)) != ++ sizeof(void __user *)); ++ BUILD_BUG_ON(offsetofend(struct siginfo, si_pid) != ++ offsetof(struct siginfo, si_uid)); ++ } ++#ifdef CONFIG_COMPAT ++ BUILD_BUG_ON(offsetof(struct compat_siginfo, si_pid) != ++ offsetof(struct compat_siginfo, si_addr)); ++ BUILD_BUG_ON(sizeof_field(struct compat_siginfo, si_pid) != ++ sizeof(compat_uptr_t)); ++ BUILD_BUG_ON(sizeof_field(struct compat_siginfo, si_pid) != ++ sizeof_field(struct siginfo, si_pid)); ++#endif + } + + void __init signals_init(void)