Commit f3029ce0 authored by Ranjan Kumar's avatar Ranjan Kumar Committed by Chen Ridong
Browse files

scsi: mpi3mr: Fix corrupt config pages PHY state is switched in sysfs

mainline inclusion
from mainline-v6.13-rc2
commit 711201a8b8334a397440ac0b859df0054e174bc9
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBIDGN
CVE: CVE-2024-57804

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=711201a8b8334a397440ac0b859df0054e174bc9



----------------------------------------------------------------------

The driver, through the SAS transport, exposes a sysfs interface to
enable/disable PHYs in a controller/expander setup.  When multiple PHYs
are disabled and enabled in rapid succession, the persistent and current
config pages related to SAS IO unit/SAS Expander pages could get
corrupted.

Use separate memory for each config request.

Signed-off-by: default avatarPrayas Patel <prayas.patel@broadcom.com>
Signed-off-by: default avatarRanjan Kumar <ranjan.kumar@broadcom.com>
Link: https://lore.kernel.org/r/20241110194405.10108-3-ranjan.kumar@broadcom.com


Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>

Conflicts:
	drivers/scsi/mpi3mr/mpi3mr_fw.c
[context is mispatched]
Signed-off-by: default avatarChen Ridong <chenridong@huawei.com>
parent 6eb132ae
Loading
Loading
Loading
Loading
+0 −9
Original line number Diff line number Diff line
@@ -131,8 +131,6 @@ extern atomic64_t event_counter;

#define MPI3MR_WATCHDOG_INTERVAL		1000 /* in milli seconds */

#define MPI3MR_DEFAULT_CFG_PAGE_SZ		1024 /* in bytes */

#define MPI3MR_RESET_TOPOLOGY_SETTLE_TIME	10

#define MPI3MR_SCMD_TIMEOUT    (60 * HZ)
@@ -1031,9 +1029,6 @@ struct scmd_priv {
 * @io_throttle_low: I/O size to stop throttle in 512b blocks
 * @num_io_throttle_group: Maximum number of throttle groups
 * @throttle_groups: Pointer to throttle group info structures
 * @cfg_page: Default memory for configuration pages
 * @cfg_page_dma: Configuration page DMA address
 * @cfg_page_sz: Default configuration page memory size
 * @sas_transport_enabled: SAS transport enabled or not
 * @scsi_device_channel: Channel ID for SCSI devices
 * @transport_cmds: Command tracker for SAS transport commands
@@ -1215,10 +1210,6 @@ struct mpi3mr_ioc {
	u16 num_io_throttle_group;
	struct mpi3mr_throttle_group_info *throttle_groups;

	void *cfg_page;
	dma_addr_t cfg_page_dma;
	u16 cfg_page_sz;

	u8 sas_transport_enabled;
	u8 scsi_device_channel;
	struct mpi3mr_drv_cmd transport_cmds;
+13 −68
Original line number Diff line number Diff line
@@ -3860,17 +3860,6 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc)

	mpi3mr_print_ioc_info(mrioc);

	if (!mrioc->cfg_page) {
		dprint_init(mrioc, "allocating config page buffers\n");
		mrioc->cfg_page_sz = MPI3MR_DEFAULT_CFG_PAGE_SZ;
		mrioc->cfg_page = dma_alloc_coherent(&mrioc->pdev->dev,
		    mrioc->cfg_page_sz, &mrioc->cfg_page_dma, GFP_KERNEL);
		if (!mrioc->cfg_page) {
			retval = -1;
			goto out_failed_noretry;
		}
	}

	if (!mrioc->init_cmds.reply) {
		retval = mpi3mr_alloc_reply_sense_bufs(mrioc);
		if (retval) {
@@ -4410,11 +4399,7 @@ void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc)
		    mrioc->admin_req_base, mrioc->admin_req_dma);
		mrioc->admin_req_base = NULL;
	}
	if (mrioc->cfg_page) {
		dma_free_coherent(&mrioc->pdev->dev, mrioc->cfg_page_sz,
		    mrioc->cfg_page, mrioc->cfg_page_dma);
		mrioc->cfg_page = NULL;
	}

	if (mrioc->pel_seqnum_virt) {
		dma_free_coherent(&mrioc->pdev->dev, mrioc->pel_seqnum_sz,
		    mrioc->pel_seqnum_virt, mrioc->pel_seqnum_dma);
@@ -4999,55 +4984,6 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
	return retval;
}


/**
 * mpi3mr_free_config_dma_memory - free memory for config page
 * @mrioc: Adapter instance reference
 * @mem_desc: memory descriptor structure
 *
 * Check whether the size of the buffer specified by the memory
 * descriptor is greater than the default page size if so then
 * free the memory pointed by the descriptor.
 *
 * Return: Nothing.
 */
static void mpi3mr_free_config_dma_memory(struct mpi3mr_ioc *mrioc,
	struct dma_memory_desc *mem_desc)
{
	if ((mem_desc->size > mrioc->cfg_page_sz) && mem_desc->addr) {
		dma_free_coherent(&mrioc->pdev->dev, mem_desc->size,
		    mem_desc->addr, mem_desc->dma_addr);
		mem_desc->addr = NULL;
	}
}

/**
 * mpi3mr_alloc_config_dma_memory - Alloc memory for config page
 * @mrioc: Adapter instance reference
 * @mem_desc: Memory descriptor to hold dma memory info
 *
 * This function allocates new dmaable memory or provides the
 * default config page dmaable memory based on the memory size
 * described by the descriptor.
 *
 * Return: 0 on success, non-zero on failure.
 */
static int mpi3mr_alloc_config_dma_memory(struct mpi3mr_ioc *mrioc,
	struct dma_memory_desc *mem_desc)
{
	if (mem_desc->size > mrioc->cfg_page_sz) {
		mem_desc->addr = dma_alloc_coherent(&mrioc->pdev->dev,
		    mem_desc->size, &mem_desc->dma_addr, GFP_KERNEL);
		if (!mem_desc->addr)
			return -ENOMEM;
	} else {
		mem_desc->addr = mrioc->cfg_page;
		mem_desc->dma_addr = mrioc->cfg_page_dma;
		memset(mem_desc->addr, 0, mrioc->cfg_page_sz);
	}
	return 0;
}

/**
 * mpi3mr_post_cfg_req - Issue config requests and wait
 * @mrioc: Adapter instance reference
@@ -5203,8 +5139,12 @@ static int mpi3mr_process_cfg_req(struct mpi3mr_ioc *mrioc,
		cfg_req->page_length = cfg_hdr->page_length;
		cfg_req->page_version = cfg_hdr->page_version;
	}
	if (mpi3mr_alloc_config_dma_memory(mrioc, &mem_desc))
		goto out;

	mem_desc.addr = dma_alloc_coherent(&mrioc->pdev->dev,
		mem_desc.size, &mem_desc.dma_addr, GFP_KERNEL);

	if (!mem_desc.addr)
		return retval;

	mpi3mr_add_sg_single(&cfg_req->sgl, sgl_flags, mem_desc.size,
	    mem_desc.dma_addr);
@@ -5233,7 +5173,12 @@ static int mpi3mr_process_cfg_req(struct mpi3mr_ioc *mrioc,
	}

out:
	mpi3mr_free_config_dma_memory(mrioc, &mem_desc);
	if (mem_desc.addr) {
		dma_free_coherent(&mrioc->pdev->dev, mem_desc.size,
			mem_desc.addr, mem_desc.dma_addr);
		mem_desc.addr = NULL;
	}

	return retval;
}