]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
ltq-adsl-mei: check status register before reading mailbox messages 19385/head
authorJan Hoffmann <jan@3e8.eu>
Fri, 11 Jul 2025 18:31:29 +0000 (20:31 +0200)
committerHauke Mehrtens <hauke@hauke-m.de>
Thu, 17 Jul 2025 19:10:37 +0000 (21:10 +0200)
The interrupt handler reads from the mailbox if no other reason for the
interrupt is known. If a spurious interrupt is received just after a
mailbox message has been sent, this means that the response to the
previous message is read again and returned by DSL_BSP_SendCMV instead
of the actual response.

To fix this, check the status register before reading from the mailbox
in the interrupt handler.

Tested on Fritzbox 7320. Without this change, there is occasionally a
kernel panic due to an out-of-bounds memory access in the ltq-adsl
driver (in DSL_DRV_DEV_G997_SnrAllocationNscGet), as a result of an
incorrect value returned by DSL_DRV_DANUBE_CmvRead. This is reproducible
by calling "dsl_cpe_pipe.sh g997dsnrg 1 1" multiple times.

Signed-off-by: Jan Hoffmann <jan@3e8.eu>
Link: https://github.com/openwrt/openwrt/pull/19385
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
package/kernel/lantiq/ltq-adsl-mei/src/drv_mei_cpe.c

index 2680e1fa8666370ea2c8707ba4f841bbf700bbff..c0fb66c5e33149cad27d94367afa6d9400bdd719 100644 (file)
@@ -1787,6 +1787,7 @@ extern void ifx_usb_enable_afe_oc(void);
  */
 static irqreturn_t IFX_MEI_IrqHandle (int int1, void *void0)
 {
+       u32 stat;
        u32 scratch;
        DSL_DEV_Device_t *pDev = (DSL_DEV_Device_t *) void0;
 #if defined(CONFIG_LTQ_MEI_FW_LOOPBACK) && defined(DFE_PING_TEST)
@@ -1820,6 +1821,12 @@ static irqreturn_t IFX_MEI_IrqHandle (int int1, void *void0)
                 if (dsl_bsp_event_callback[event].function)
                         (*dsl_bsp_event_callback[event].function)(pDev, event, dsl_bsp_event_callback[event].pData);
         } else { // normal message
+                IFX_MEI_LongWordReadOffset (pDev, (u32) ME_ARC2ME_STAT, &stat);
+                if (!(stat & ARC_TO_MEI_MSGAV)) {
+                        // status register indicates there is no message
+                        return IRQ_NONE;
+                }
+
                 IFX_MEI_MailboxRead (pDev, DSL_DEV_PRIVATE(pDev)->CMV_RxMsg, MSG_LENGTH);
                 if (DSL_DEV_PRIVATE(pDev)-> cmv_waiting == 1) {
                         DSL_DEV_PRIVATE(pDev)-> arcmsgav = 1;