]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: brcmfmac: initialize SDIO data work before cleanup
authorRunyu Xiao <runyu.xiao@seu.edu.cn>
Fri, 19 Jun 2026 06:44:01 +0000 (14:44 +0800)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 7 Jul 2026 08:10:40 +0000 (10:10 +0200)
brcmf_sdio_probe() stores the newly allocated bus in sdiodev->bus before
allocating the ordered workqueue. If that allocation fails, the function
jumps to fail and calls brcmf_sdio_remove().

brcmf_sdio_remove() unconditionally cancels bus->datawork. Initialize the
work item before the first failure path that can reach brcmf_sdio_remove(),
so the cleanup path always observes a valid work object.

This issue was found by our static analysis tool and then confirmed by
manual review of the probe error path and the remove-time work drain. The
problem pattern is an early setup failure that reaches a cleanup helper
which cancels an embedded work item before its initializer has run.

A QEMU PoC forced alloc_ordered_workqueue() to fail at the same point in
brcmf_sdio_probe(), before INIT_WORK(&bus->datawork) is reached. The
resulting fail path calls brcmf_sdio_remove(), and DEBUG_OBJECTS reports
the invalid work drain with brcmf_sdio_probe() and brcmf_sdio_remove() in
the stack.

Fixes: 9982464379e8 ("brcmfmac: make sdio suspend wait for threads to freeze")
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
Link: https://patch.msgid.link/20260619064401.1048976-1-runyu.xiao@seu.edu.cn
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c

index 8fb595733b9c3603f5a12184c0b6cfdc9af0027b..b725c64e5b5c63a6531f10654cb7dddd8628c0c9 100644 (file)
@@ -4465,6 +4465,7 @@ int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
        bus->sdiodev = sdiodev;
        sdiodev->bus = bus;
        skb_queue_head_init(&bus->glom);
+       INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
        bus->txbound = BRCMF_TXBOUND;
        bus->rxbound = BRCMF_RXBOUND;
        bus->txminmax = BRCMF_TXMINMAX;
@@ -4479,7 +4480,6 @@ int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
                goto fail;
        }
        brcmf_sdiod_freezer_count(sdiodev);
-       INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
        bus->brcmf_wq = wq;
 
        /* attempt to attach to the dongle */