uhdlc_open() starts the UCC, IRQ and NAPI before it calls hdlc_open(). If no HDLC protocol has been attached, hdlc_open() returns -ENOSYS. The error path then calls uhdlc_close(), which calls hdlc_close() and dereferences hdlc->proto even though it is NULL. Bringing up a freshly registered interface before an IF_PROTO ioctl can therefore trigger a NULL pointer dereference. Call hdlc_open() before enabling the hardware. Balance a successful protocol open with hdlc_close() if requesting the IRQ then fails. This matches peer HDLC drivers and avoids running teardown for a protocol that never opened. Fixes: a59addacf899 ("drivers/net: process the result of hdlc_open() and add call of hdlc_close() in uhdlc_close()") Cc: stable@vger.kernel.org Reported-by: Jakub Kicinski Link: https://lore.kernel.org/r/20260806020541.2011936-2-kuba@kernel.org Co-developed-by: Ijae Kim Signed-off-by: Ijae Kim Signed-off-by: Myeonghun Pak --- drivers/net/wan/fsl_ucc_hdlc.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 809f21fb93f56..82796452e54a2 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -34,8 +34,6 @@ #define TDM_PPPOHT_SLIC_MAXIN #define RX_BD_ERRORS (R_CD_S | R_OV_S | R_CR_S | R_AB_S | R_NO_S | R_LG_S) -static int uhdlc_close(struct net_device *dev); - static struct ucc_tdm_info utdm_primary_info = { .uf_info = { .tsa = 0, @@ -705,12 +703,18 @@ static int uhdlc_open(struct net_device *dev) hdlc_device *hdlc = dev_to_hdlc(dev); struct ucc_hdlc_private *priv = hdlc->priv; struct ucc_tdm *utdm = priv->utdm; - int rc = 0; + int rc; if (priv->hdlc_busy != 1) { + rc = hdlc_open(dev); + if (rc) + return rc; + if (request_irq(priv->ut_info->uf_info.irq, - ucc_hdlc_irq_handler, 0, "hdlc", priv)) + ucc_hdlc_irq_handler, 0, "hdlc", priv)) { + hdlc_close(dev); return -ENODEV; + } cecr_subblock = ucc_fast_get_qe_cr_subblock( priv->ut_info->uf_info.ucc_num); @@ -729,13 +733,9 @@ static int uhdlc_open(struct net_device *dev) napi_enable(&priv->napi); netdev_reset_queue(dev); netif_start_queue(dev); - - rc = hdlc_open(dev); - if (rc) - uhdlc_close(dev); } - return rc; + return 0; } static void uhdlc_memclean(struct ucc_hdlc_private *priv) -- 2.47.1