Re: [PATCH v2] watchdog: take all OF aliases into account when assigning id

[email protected] Tue, 14 Jul 2026 11:05:44 +0000
Newsgroups org.kernel.vger.linux-watchdog
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

New issues:
- [Medium] The fallback ID allocation for legacy watchdog modules bypasses the new alias-aware logic, potentially stealing an ID reserved by a DT alias.

Pre-existing issues:
- [High] A pre-existing flaw in deferred watchdog registration ignores failures, leaving dangling pointers that trigger Use-After-Free and Double Free vulnerabilities when the device is subsequently unbound.
--

--- Patch [1]: [PATCH v2] watchdog: take all OF aliases into account when assigning id ---
commit 723b5098283b03dc095379b11c599fe692046472
Author: Rasmus Villemoes <[email protected]>

watchdog: take all OF aliases into account when assigning id

Ensure that ids for devices without a device tree alias are allocated
from among those where no watchdogX alias exists.

> diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c
> --- a/drivers/watchdog/watchdog_core.c
> +++ b/drivers/watchdog/watchdog_core.c

[ ... ]

> @@ -265,8 +267,26 @@ static int ___watchdog_register_device(struct watchdog_device *wdd)
>  					     GFP_KERNEL);
>  	}
>  
> -	if (id < 0)
> -		id = ida_alloc_max(&watchdog_ida, MAX_DOGS - 1, GFP_KERNEL);
> +	/*
> +	 * Find an id which is not pre-assigned via a DT alias to some
> +	 * other, possibly not yet probed, watchdog device.
> +	 */
> +	if (id < 0) {
> +		np = of_find_node_by_path("/aliases");
> +
> +		for (min_id = 0; ; min_id = id + 1) {
> +			id = ida_alloc_range(&watchdog_ida, min_id, MAX_DOGS - 1,
> +					     GFP_KERNEL);
> +			if (!np || id < 0)
> +				break;
> +
> +			snprintf(alias, sizeof(alias), "watchdog%d", id);
> +			if (!of_get_property(np, alias, NULL))
> +				break;
> +			ida_free(&watchdog_ida, id);
> +		}
> +		of_node_put(np);
> +	}
>  
>  	if (id < 0)
>  		return id;
>  	wdd->id = id;
>  
>  	ret = watchdog_dev_register(wdd);
>  	if (ret) {
>  		ida_free(&watchdog_ida, id);
>  		if (!(id == 0 && ret == -EBUSY))
>  			return ret;
>  
>  		/* Retry in case a legacy watchdog module exists */
>  		id = ida_alloc_range(&watchdog_ida, 1, MAX_DOGS - 1,
>  				     GFP_KERNEL);

[Severity: Medium]
Does this fallback allocation for legacy modules need to validate against
DT aliases as well?

Because this path calls ida_alloc_range() directly, it bypasses the newly
introduced alias validation loop. If a legacy watchdog module causes a
retry, could this allocation steal an ID that is actively reserved for
another unprobed device via a DT alias?

[Severity: High]
This is a pre-existing issue, but I noticed a potential flaw in how
watchdog_deferred_registration() handles failures. 

If the registration fails, the return value is ignored:

drivers/watchdog/watchdog_core.c:watchdog_deferred_registration() {
    ...
    __watchdog_register_device(wdd);
    ...
}

During the failed registration attempt, watchdog_cdev_register() assigns
wdd->wd_data, but never clears it on the error path:

drivers/watchdog/watchdog_dev.c:watchdog_cdev_register() {
    ...
    wd_data->wdd = wdd;
    wdd->wd_data = wd_data;
    ...
}

If this fails, the device is left in a partially initialized state but
remains registered in devres. When the device is subsequently unbound or
the module removed, __watchdog_unregister_device() executes on the failed
device:

drivers/watchdog/watchdog_core.c:__watchdog_unregister_device() {
    ...
    watchdog_dev_unregister(wdd);
    ida_free(&watchdog_ida, wdd->id);
    ...
}

Could this trigger a use-after-free or NULL pointer dereference inside
watchdog_dev_unregister(), as well as a double-free on the IDA since the
ID was already freed during the initial registration failure?

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=1