Skip to content
Snippets Groups Projects
  • Wang Hai's avatar
    776c7501
    ata: ahci_platform: fix null-ptr-deref in ahci_platform_enable_regulators() · 776c7501
    Wang Hai authored
    
    I got a null-ptr-deref report:
    
    KASAN: null-ptr-deref in range [0x0000000000000090-0x0000000000000097]
    ...
    RIP: 0010:regulator_enable+0x84/0x260
    ...
    Call Trace:
     ahci_platform_enable_regulators+0xae/0x320
     ahci_platform_enable_resources+0x1a/0x120
     ahci_probe+0x4f/0x1b9
     platform_probe+0x10b/0x280
    ...
     entry_SYSCALL_64_after_hwframe+0x44/0xae
    
    If devm_regulator_get() in ahci_platform_get_resources() fails,
    hpriv->phy_regulator will point to NULL, when enabling or disabling it,
    null-ptr-deref will occur.
    
    ahci_probe()
    	ahci_platform_get_resources()
    		devm_regulator_get(, "phy") // failed, let phy_regulator = NULL
    	ahci_platform_enable_resources()
    		ahci_platform_enable_regulators()
    			regulator_enable(hpriv->phy_regulator) // null-ptr-deref
    
    commit 962399bb ("ata: libahci_platform: Fix regulator_get_optional()
    misuse") replaces devm_regulator_get_optional() with devm_regulator_get(),
    but PHY regulator omits to delete "hpriv->phy_regulator = NULL;" like AHCI.
    Delete it like AHCI regulator to fix this bug.
    
    Fixes: commit 962399bb ("ata: libahci_platform: Fix regulator_get_optional() misuse")
    Reported-by: default avatarHulk Robot <hulkci@huawei.com>
    Signed-off-by: default avatarWang Hai <wanghai38@huawei.com>
    Reviewed-by: default avatarHans de Goede <hdegoede@redhat.com>
    Signed-off-by: default avatarDamien Le Moal <damien.lemoal@wdc.com>
    776c7501
    History
    ata: ahci_platform: fix null-ptr-deref in ahci_platform_enable_regulators()
    Wang Hai authored
    
    I got a null-ptr-deref report:
    
    KASAN: null-ptr-deref in range [0x0000000000000090-0x0000000000000097]
    ...
    RIP: 0010:regulator_enable+0x84/0x260
    ...
    Call Trace:
     ahci_platform_enable_regulators+0xae/0x320
     ahci_platform_enable_resources+0x1a/0x120
     ahci_probe+0x4f/0x1b9
     platform_probe+0x10b/0x280
    ...
     entry_SYSCALL_64_after_hwframe+0x44/0xae
    
    If devm_regulator_get() in ahci_platform_get_resources() fails,
    hpriv->phy_regulator will point to NULL, when enabling or disabling it,
    null-ptr-deref will occur.
    
    ahci_probe()
    	ahci_platform_get_resources()
    		devm_regulator_get(, "phy") // failed, let phy_regulator = NULL
    	ahci_platform_enable_resources()
    		ahci_platform_enable_regulators()
    			regulator_enable(hpriv->phy_regulator) // null-ptr-deref
    
    commit 962399bb ("ata: libahci_platform: Fix regulator_get_optional()
    misuse") replaces devm_regulator_get_optional() with devm_regulator_get(),
    but PHY regulator omits to delete "hpriv->phy_regulator = NULL;" like AHCI.
    Delete it like AHCI regulator to fix this bug.
    
    Fixes: commit 962399bb ("ata: libahci_platform: Fix regulator_get_optional() misuse")
    Reported-by: default avatarHulk Robot <hulkci@huawei.com>
    Signed-off-by: default avatarWang Hai <wanghai38@huawei.com>
    Reviewed-by: default avatarHans de Goede <hdegoede@redhat.com>
    Signed-off-by: default avatarDamien Le Moal <damien.lemoal@wdc.com>
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
libahci_platform.c 20.62 KiB
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * AHCI SATA platform library
 *
 * Copyright 2004-2005  Red Hat, Inc.
 *   Jeff Garzik <jgarzik@pobox.com>
 * Copyright 2010  MontaVista Software, LLC.
 *   Anton Vorontsov <avorontsov@ru.mvista.com>
 */

#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/gfp.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/libata.h>
#include <linux/ahci_platform.h>
#include <linux/phy/phy.h>
#include <linux/pm_runtime.h>
#include <linux/of_platform.h>
#include <linux/reset.h>
#include "ahci.h"

static void ahci_host_stop(struct ata_host *host);

struct ata_port_operations ahci_platform_ops = {
	.inherits	= &ahci_ops,
	.host_stop	= ahci_host_stop,
};
EXPORT_SYMBOL_GPL(ahci_platform_ops);

/**
 * ahci_platform_enable_phys - Enable PHYs
 * @hpriv: host private area to store config values
 *
 * This function enables all the PHYs found in hpriv->phys, if any.
 * If a PHY fails to be enabled, it disables all the PHYs already
 * enabled in reverse order and returns an error.
 *
 * RETURNS:
 * 0 on success otherwise a negative error code
 */
int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
{
	int rc, i;

	for (i = 0; i < hpriv->nports; i++) {
		rc = phy_init(hpriv->phys[i]);
		if (rc)
			goto disable_phys;

		rc = phy_set_mode(hpriv->phys[i], PHY_MODE_SATA);
		if (rc) {
			phy_exit(hpriv->phys[i]);
			goto disable_phys;
		}

		rc = phy_power_on(hpriv->phys[i]);
		if (rc && !(rc == -EOPNOTSUPP && (hpriv->flags & AHCI_HFLAG_IGN_NOTSUPP_POWER_ON))) {
			phy_exit(hpriv->phys[i]);
			goto disable_phys;
		}
	}

	return 0;

disable_phys: