diff options
| author | Niklas Cassel <cassel@kernel.org> | 2026-09-15 10:41:29 +0200 |
|---|---|---|
| committer | Niklas Cassel <cassel@kernel.org> | 2026-09-15 11:54:30 +0200 |
| commit | 70b1196740d61aabda13b2ad0e9c1dfa2ef9cfa3 (patch) | |
| tree | cf39a822d7ce1bf591b2b08f7c3e533c08f8ba65 | |
| parent | 91e0a7452d7a81e924a499b23f30f3bf85fddbd2 (diff) | |
| download | linux-next-70b1196740d61aabda13b2ad0e9c1dfa2ef9cfa3.tar.gz linux-next-70b1196740d61aabda13b2ad0e9c1dfa2ef9cfa3.zip | |
ata: sata_fsl: Fix use-after-free of host_priv on probe() failure
sata_fsl_host_stop() releases hcr_base and host_priv:
static void sata_fsl_host_stop(struct ata_host *host)
{
struct sata_fsl_host_priv *host_priv = host->private_data;
iounmap(host_priv->hcr_base);
kfree(host_priv);
}
->host_stop() is called by the driver core through the ata_host_stop()
devres action which ata_host_start() registers, so it is called both when
the device is unbound and when probe() fails after the host has been
started.
The error_exit_with_cleanup label of sata_fsl_probe() releases hcr_base
and host_priv as well, and it is reachable from the two
device_create_file() calls which are done after the host has been
activated. In that case sata_fsl_host_stop() runs on an already freed
host_priv, resulting in a use-after-free and a double iounmap()/kfree().
Add a separate error label for the failures happening after the host has
been activated, which only detaches the host and leaves hcr_base and
host_priv to sata_fsl_host_stop().
Note that ata_host_detach() is dropped from error_exit_with_cleanup, as
that label is now only reachable while host is still NULL.
Fixes: 6c8ad7e8cf29 ("sata_fsl: fix UAF in sata_fsl_port_stop when rmmod sata_fsl")
Cc: stable@vger.kernel.org
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Link: https://lore.kernel.org/r/20260915084127.692494-11-cassel@kernel.org
Signed-off-by: Niklas Cassel <cassel@kernel.org>
| -rw-r--r-- | drivers/ata/sata_fsl.c | 18 |
1 files changed, 13 insertions, 5 deletions
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 70b210afd291..c6df55886fe1 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -1500,7 +1500,7 @@ static int sata_fsl_probe(struct platform_device *ofdev) host_priv->intr_coalescing.attr.mode = S_IRUGO | S_IWUSR; retval = device_create_file(host->dev, &host_priv->intr_coalescing); if (retval) - goto error_exit_with_cleanup; + goto error_exit_detach; host_priv->rx_watermark.show = fsl_sata_rx_watermark_show; host_priv->rx_watermark.store = fsl_sata_rx_watermark_store; @@ -1510,16 +1510,24 @@ static int sata_fsl_probe(struct platform_device *ofdev) retval = device_create_file(host->dev, &host_priv->rx_watermark); if (retval) { device_remove_file(&ofdev->dev, &host_priv->intr_coalescing); - goto error_exit_with_cleanup; + goto error_exit_detach; } return 0; -error_exit_with_cleanup: +error_exit_detach: + /* + * Once the host has been activated, hcr_base and host_priv are + * released by sata_fsl_host_stop(), which is called by the driver core + * through the ata_host_stop() devres action registered by + * ata_host_start(). Releasing them here as well would result in a + * double iounmap() and a use-after-free. + */ + ata_host_detach(host); - if (host) - ata_host_detach(host); + return retval; +error_exit_with_cleanup: if (hcr_base) iounmap(hcr_base); kfree(host_priv); |
