--- /dev/null
+From bd82d4bd21880b7c4d5f5756be435095d6ae07b5 Mon Sep 17 00:00:00 2001
+From: Julien Thierry <julien.thierry@arm.com>
+Date: Tue, 11 Jun 2019 10:38:10 +0100
+Subject: arm64: Fix incorrect irqflag restore for priority masking
+
+From: Julien Thierry <julien.thierry@arm.com>
+
+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 (<pmr_value> |
+GIC_PRIO_PSR_I_SET) does not mask more interrupts than <pmr_value> 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: <stable@vger.kernel.org> # 5.1.x-
+Reported-by: Zenghui Yu <yuzenghui@huawei.com>
+Cc: Steven Rostedt <rostedt@goodmis.org>
+Cc: Wei Li <liwei391@huawei.com>
+Cc: Will Deacon <will.deacon@arm.com>
+Cc: Christoffer Dall <christoffer.dall@arm.com>
+Cc: James Morse <james.morse@arm.com>
+Cc: Suzuki K Pouloze <suzuki.poulose@arm.com>
+Cc: Oleg Nesterov <oleg@redhat.com>
+Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
+Signed-off-by: Julien Thierry <julien.thierry@arm.com>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 <linux/irqflags.h>
+
++#include <asm/arch_gicv3.h>
+ #include <asm/cpufeature.h>
+
+ #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);
+ }
+
--- /dev/null
+From f57065782f245ca96f1472209a485073bbc11247 Mon Sep 17 00:00:00 2001
+From: Julien Thierry <julien.thierry@arm.com>
+Date: Tue, 11 Jun 2019 10:38:08 +0100
+Subject: arm64: irqflags: Add condition flags to inline asm clobber list
+
+From: Julien Thierry <julien.thierry@arm.com>
+
+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: <stable@vger.kernel.org> # 5.1.x-
+Suggested-by: Marc Zyngier <marc.zyngier@arm.com>
+Cc: Will Deacon <will.deacon@arm.com>
+Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
+Acked-by: Mark Rutland <mark.rutland@arm.com>
+Signed-off-by: Julien Thierry <julien.thierry@arm.com>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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;
+ }
--- /dev/null
+From ba24eee6686f6ed3738602b54d959253316a9541 Mon Sep 17 00:00:00 2001
+From: Jon Hunter <jonathanh@nvidia.com>
+Date: Thu, 20 Jun 2019 09:17:00 +0100
+Subject: arm64: tegra: Fix AGIC register range
+
+From: Jon Hunter <jonathanh@nvidia.com>
+
+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 <jonathanh@nvidia.com>
+Fixes: bcdbde433542 ("arm64: tegra: Add AGIC node for Tegra210")
+Signed-off-by: Thierry Reding <treding@nvidia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 = <GIC_SPI 102 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+ clocks = <&tegra_car TEGRA210_CLK_APE>;
--- /dev/null
+From 5ec27ec735ba0477d48c80561cc5e856f0c5dfaf Mon Sep 17 00:00:00 2001
+From: Radoslaw Burny <rburny@google.com>
+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 <rburny@google.com>
+
+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 <rburny@google.com>
+Acked-by: Luis Chamberlain <mcgrof@kernel.org>
+Cc: Kees Cook <keescook@chromium.org>
+Cc: "Eric W . Biederman" <ebiederm@xmission.com>
+Cc: Seth Forshee <seth.forshee@canonical.com>
+Cc: John Sperbeck <jsperbeck@google.com>
+Cc: Alexey Dobriyan <adobriyan@gmail.com>
+Cc: <stable@vger.kernel.org> [4.8+]
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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;
+ }
--- /dev/null
+From ecc8fb54bd443bf69996d9d5ddb8d90a50f14936 Mon Sep 17 00:00:00 2001
+From: Vitor Soares <Vitor.Soares@synopsys.com>
+Date: Wed, 19 Jun 2019 20:36:31 +0200
+Subject: i3c: fix i2c and i3c scl rate by bus mode
+
+From: Vitor Soares <Vitor.Soares@synopsys.com>
+
+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 <vitor.soares@synopsys.com>
+Cc: Boris Brezillon <bbrezillon@kernel.org>
+Cc: <stable@vger.kernel.org>
+Cc: <linux-kernel@vger.kernel.org>
+Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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;
+
--- /dev/null
+From b96fb368b08f1637cbf780a6b83e36c2c5ed4ff5 Mon Sep 17 00:00:00 2001
+From: Shaokun Zhang <zhangshaokun@hisilicon.com>
+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 <zhangshaokun@hisilicon.com>
+
+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 <alexander.shishkin@linux.intel.com>
+Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
+Fixes: ba39bd8306057 ("intel_th: msu: Switch over to scatterlist")
+Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
+Cc: stable <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/20190621161930.60785-2-alexander.shishkin@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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);
+
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
--- /dev/null
+From 7a0cf094944e2540758b7f957eb6846d5126f535 Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Wed, 15 May 2019 22:54:56 -0500
+Subject: signal: Correct namespace fixups of si_pid and si_uid
+
+From: Eric W. Biederman <ebiederm@xmission.com>
+
+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" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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);
+ }
+
--- /dev/null
+From 70f1b0d34bdf03065fe869e93cc17cad1ea20c4a Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+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 <ebiederm@xmission.com>
+
+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 <stdio.h>
+ #include <fcntl.h>
+ #include <signal.h>
+ #include <string.h>
+ #include <sys/ioctl.h>
+ #include <unistd.h>
+ #include <endian.h>
+ #include <linux/usb/ch9.h>
+ #include <linux/usbdevice_fs.h>
+
+ 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 <gregkh@linuxfoundation.org>
+Cc: linux-usb@vger.kernel.org
+Cc: Alan Stern <stern@rowland.harvard.edu>
+Cc: Oliver Neukum <oneukum@suse.com>
+Fixes: v2.3.39
+Cc: stable@vger.kernel.org
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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)