From: Greg Kroah-Hartman Date: Mon, 16 May 2022 12:51:22 +0000 (+0200) Subject: 5.4-stable patches X-Git-Tag: v4.9.315~18 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=38f8557783c096cd02897329c350d4d077858cea;p=thirdparty%2Fkernel%2Fstable-queue.git 5.4-stable patches added patches: arm-memremap-don-t-abuse-pfn_valid-to-ensure-presence-of-linear-map.patch net-phy-fix-race-condition-on-link-status-change.patch --- diff --git a/queue-5.4/arm-memremap-don-t-abuse-pfn_valid-to-ensure-presence-of-linear-map.patch b/queue-5.4/arm-memremap-don-t-abuse-pfn_valid-to-ensure-presence-of-linear-map.patch new file mode 100644 index 00000000000..65ab50bff8e --- /dev/null +++ b/queue-5.4/arm-memremap-don-t-abuse-pfn_valid-to-ensure-presence-of-linear-map.patch @@ -0,0 +1,126 @@ +From 260364d112bc822005224667c0c9b1b17a53eafd Mon Sep 17 00:00:00 2001 +From: Mike Rapoport +Date: Mon, 9 May 2022 17:34:28 -0700 +Subject: arm[64]/memremap: don't abuse pfn_valid() to ensure presence of linear map + +From: Mike Rapoport + +commit 260364d112bc822005224667c0c9b1b17a53eafd upstream. + +The semantics of pfn_valid() is to check presence of the memory map for a +PFN and not whether a PFN is covered by the linear map. The memory map +may be present for NOMAP memory regions, but they won't be mapped in the +linear mapping. Accessing such regions via __va() when they are +memremap()'ed will cause a crash. + +On v5.4.y the crash happens on qemu-arm with UEFI [1]: + +<1>[ 0.084476] 8<--- cut here --- +<1>[ 0.084595] Unable to handle kernel paging request at virtual address dfb76000 +<1>[ 0.084938] pgd = (ptrval) +<1>[ 0.085038] [dfb76000] *pgd=5f7fe801, *pte=00000000, *ppte=00000000 + +... + +<4>[ 0.093923] [] (memcpy) from [] (dmi_setup+0x60/0x418) +<4>[ 0.094204] [] (dmi_setup) from [] (arm_dmi_init+0x8/0x10) +<4>[ 0.094408] [] (arm_dmi_init) from [] (do_one_initcall+0x50/0x228) +<4>[ 0.094619] [] (do_one_initcall) from [] (kernel_init_freeable+0x15c/0x1f8) +<4>[ 0.094841] [] (kernel_init_freeable) from [] (kernel_init+0x8/0x10c) +<4>[ 0.095057] [] (kernel_init) from [] (ret_from_fork+0x14/0x2c) + +On kernels v5.10.y and newer the same crash won't reproduce on ARM because +commit b10d6bca8720 ("arch, drivers: replace for_each_membock() with +for_each_mem_range()") changed the way memory regions are registered in +the resource tree, but that merely covers up the problem. + +On ARM64 memory resources registered in yet another way and there the +issue of wrong usage of pfn_valid() to ensure availability of the linear +map is also covered. + +Implement arch_memremap_can_ram_remap() on ARM and ARM64 to prevent access +to NOMAP regions via the linear mapping in memremap(). + +Link: https://lore.kernel.org/all/Yl65zxGgFzF1Okac@sirena.org.uk +Link: https://lkml.kernel.org/r/20220426060107.7618-1-rppt@kernel.org +Signed-off-by: Mike Rapoport +Reported-by: "kernelci.org bot" +Tested-by: Mark Brown +Reviewed-by: Ard Biesheuvel +Acked-by: Catalin Marinas +Cc: Greg Kroah-Hartman +Cc: Mark Brown +Cc: Mark-PK Tsai +Cc: Russell King +Cc: Tony Lindgren +Cc: Will Deacon +Cc: [5.4+] +Signed-off-by: Andrew Morton +Signed-off-by: Mike Rapoport +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm/include/asm/io.h | 3 +++ + arch/arm/mm/ioremap.c | 8 ++++++++ + arch/arm64/include/asm/io.h | 4 ++++ + arch/arm64/mm/ioremap.c | 9 +++++++++ + 4 files changed, 24 insertions(+) + +--- a/arch/arm/include/asm/io.h ++++ b/arch/arm/include/asm/io.h +@@ -457,6 +457,9 @@ extern void pci_iounmap(struct pci_dev * + extern int valid_phys_addr_range(phys_addr_t addr, size_t size); + extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size); + extern int devmem_is_allowed(unsigned long pfn); ++extern bool arch_memremap_can_ram_remap(resource_size_t offset, size_t size, ++ unsigned long flags); ++#define arch_memremap_can_ram_remap arch_memremap_can_ram_remap + #endif + + /* +--- a/arch/arm/mm/ioremap.c ++++ b/arch/arm/mm/ioremap.c +@@ -500,3 +500,11 @@ void __init early_ioremap_init(void) + { + early_ioremap_setup(); + } ++ ++bool arch_memremap_can_ram_remap(resource_size_t offset, size_t size, ++ unsigned long flags) ++{ ++ unsigned long pfn = PHYS_PFN(offset); ++ ++ return memblock_is_map_memory(pfn); ++} +--- a/arch/arm64/include/asm/io.h ++++ b/arch/arm64/include/asm/io.h +@@ -204,4 +204,8 @@ extern int valid_mmap_phys_addr_range(un + + extern int devmem_is_allowed(unsigned long pfn); + ++extern bool arch_memremap_can_ram_remap(resource_size_t offset, size_t size, ++ unsigned long flags); ++#define arch_memremap_can_ram_remap arch_memremap_can_ram_remap ++ + #endif /* __ASM_IO_H */ +--- a/arch/arm64/mm/ioremap.c ++++ b/arch/arm64/mm/ioremap.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -100,3 +101,11 @@ void __init early_ioremap_init(void) + { + early_ioremap_setup(); + } ++ ++bool arch_memremap_can_ram_remap(resource_size_t offset, size_t size, ++ unsigned long flags) ++{ ++ unsigned long pfn = PHYS_PFN(offset); ++ ++ return memblock_is_map_memory(pfn); ++} diff --git a/queue-5.4/net-phy-fix-race-condition-on-link-status-change.patch b/queue-5.4/net-phy-fix-race-condition-on-link-status-change.patch new file mode 100644 index 00000000000..596ddef8b40 --- /dev/null +++ b/queue-5.4/net-phy-fix-race-condition-on-link-status-change.patch @@ -0,0 +1,157 @@ +From 91a7cda1f4b8bdf770000a3b60640576dafe0cec Mon Sep 17 00:00:00 2001 +From: Francesco Dolcini +Date: Fri, 6 May 2022 08:08:15 +0200 +Subject: net: phy: Fix race condition on link status change + +From: Francesco Dolcini + +commit 91a7cda1f4b8bdf770000a3b60640576dafe0cec upstream. + +This fixes the following error caused by a race condition between +phydev->adjust_link() and a MDIO transaction in the phy interrupt +handler. The issue was reproduced with the ethernet FEC driver and a +micrel KSZ9031 phy. + +[ 146.195696] fec 2188000.ethernet eth0: MDIO read timeout +[ 146.201779] ------------[ cut here ]------------ +[ 146.206671] WARNING: CPU: 0 PID: 571 at drivers/net/phy/phy.c:942 phy_error+0x24/0x6c +[ 146.214744] Modules linked in: bnep imx_vdoa imx_sdma evbug +[ 146.220640] CPU: 0 PID: 571 Comm: irq/128-2188000 Not tainted 5.18.0-rc3-00080-gd569e86915b7 #9 +[ 146.229563] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree) +[ 146.236257] unwind_backtrace from show_stack+0x10/0x14 +[ 146.241640] show_stack from dump_stack_lvl+0x58/0x70 +[ 146.246841] dump_stack_lvl from __warn+0xb4/0x24c +[ 146.251772] __warn from warn_slowpath_fmt+0x5c/0xd4 +[ 146.256873] warn_slowpath_fmt from phy_error+0x24/0x6c +[ 146.262249] phy_error from kszphy_handle_interrupt+0x40/0x48 +[ 146.268159] kszphy_handle_interrupt from irq_thread_fn+0x1c/0x78 +[ 146.274417] irq_thread_fn from irq_thread+0xf0/0x1dc +[ 146.279605] irq_thread from kthread+0xe4/0x104 +[ 146.284267] kthread from ret_from_fork+0x14/0x28 +[ 146.289164] Exception stack(0xe6fa1fb0 to 0xe6fa1ff8) +[ 146.294448] 1fa0: 00000000 00000000 00000000 00000000 +[ 146.302842] 1fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +[ 146.311281] 1fe0: 00000000 00000000 00000000 00000000 00000013 00000000 +[ 146.318262] irq event stamp: 12325 +[ 146.321780] hardirqs last enabled at (12333): [] __up_console_sem+0x50/0x60 +[ 146.330013] hardirqs last disabled at (12342): [] __up_console_sem+0x3c/0x60 +[ 146.338259] softirqs last enabled at (12324): [] __do_softirq+0x2c0/0x624 +[ 146.346311] softirqs last disabled at (12319): [] __irq_exit_rcu+0x138/0x178 +[ 146.354447] ---[ end trace 0000000000000000 ]--- + +With the FEC driver phydev->adjust_link() calls fec_enet_adjust_link() +calls fec_stop()/fec_restart() and both these function reset and +temporary disable the FEC disrupting any MII transaction that +could be happening at the same time. + +fec_enet_adjust_link() and phy_read() can be running at the same time +when we have one additional interrupt before the phy_state_machine() is +able to terminate. + +Thread 1 (phylib WQ) | Thread 2 (phy interrupt) + | + | phy_interrupt() <-- PHY IRQ + | handle_interrupt() + | phy_read() + | phy_trigger_machine() + | --> schedule phylib WQ + | + | +phy_state_machine() | + phy_check_link_status() | + phy_link_change() | + phydev->adjust_link() | + fec_enet_adjust_link() | + --> FEC reset | phy_interrupt() <-- PHY IRQ + | phy_read() + | + +Fix this by acquiring the phydev lock in phy_interrupt(). + +Link: https://lore.kernel.org/all/20220422152612.GA510015@francesco-nb.int.toradex.com/ +Fixes: c974bdbc3e77 ("net: phy: Use threaded IRQ, to allow IRQ from sleeping devices") +cc: +Signed-off-by: Francesco Dolcini +Reviewed-by: Andrew Lunn +Link: https://lore.kernel.org/r/20220506060815.327382-1-francesco.dolcini@toradex.com +Signed-off-by: Jakub Kicinski +[fd: backport: adapt locking before did_interrupt()/ack_interrupt() + callbacks removal ] +Signed-off-by: Francesco Dolcini +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/phy/phy.c | 45 ++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 40 insertions(+), 5 deletions(-) + +--- a/drivers/net/phy/phy.c ++++ b/drivers/net/phy/phy.c +@@ -116,10 +116,15 @@ EXPORT_SYMBOL(phy_print_status); + */ + static int phy_clear_interrupt(struct phy_device *phydev) + { +- if (phydev->drv->ack_interrupt) +- return phydev->drv->ack_interrupt(phydev); ++ int ret = 0; + +- return 0; ++ if (phydev->drv->ack_interrupt) { ++ mutex_lock(&phydev->lock); ++ ret = phydev->drv->ack_interrupt(phydev); ++ mutex_unlock(&phydev->lock); ++ } ++ ++ return ret; + } + + /** +@@ -761,6 +766,36 @@ static int phy_disable_interrupts(struct + } + + /** ++ * phy_did_interrupt - Checks if the PHY generated an interrupt ++ * @phydev: target phy_device struct ++ */ ++static int phy_did_interrupt(struct phy_device *phydev) ++{ ++ int ret; ++ ++ mutex_lock(&phydev->lock); ++ ret = phydev->drv->did_interrupt(phydev); ++ mutex_unlock(&phydev->lock); ++ ++ return ret; ++} ++ ++/** ++ * phy_handle_interrupt - PHY specific interrupt handler ++ * @phydev: target phy_device struct ++ */ ++static int phy_handle_interrupt(struct phy_device *phydev) ++{ ++ int ret; ++ ++ mutex_lock(&phydev->lock); ++ ret = phydev->drv->handle_interrupt(phydev); ++ mutex_unlock(&phydev->lock); ++ ++ return ret; ++} ++ ++/** + * phy_interrupt - PHY interrupt handler + * @irq: interrupt line + * @phy_dat: phy_device pointer +@@ -771,11 +806,11 @@ static irqreturn_t phy_interrupt(int irq + { + struct phy_device *phydev = phy_dat; + +- if (phydev->drv->did_interrupt && !phydev->drv->did_interrupt(phydev)) ++ if (phydev->drv->did_interrupt && !phy_did_interrupt(phydev)) + return IRQ_NONE; + + if (phydev->drv->handle_interrupt) { +- if (phydev->drv->handle_interrupt(phydev)) ++ if (phy_handle_interrupt(phydev)) + goto phy_err; + } else { + /* reschedule state queue work to run as soon as possible */ diff --git a/queue-5.4/series b/queue-5.4/series index d10a7fdbd5d..f1a67e01d6e 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -37,3 +37,5 @@ i40e-i40e_main-fix-a-missing-check-on-list-iterator.patch cgroup-cpuset-remove-cpus_allowed-mems_allowed-setup-in-cpuset_init_smp.patch drm-vmwgfx-initialize-drm_mode_fb_cmd2.patch mips-fix-build-with-gcc-12.patch +net-phy-fix-race-condition-on-link-status-change.patch +arm-memremap-don-t-abuse-pfn_valid-to-ensure-presence-of-linear-map.patch