Linux SCSI subsystem development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Ivy Lopez" <skunkolee@gmail.com>
Cc: linux-scsi@vger.kernel.org
Subject: Re: [PATCH] scsi: aacraid: fix DMA mapping leak in aac_send_raw_srb()
Date: Sun, 09 Aug 2026 03:48:02 +0000	[thread overview]
Message-ID: <20260809034803.058D01F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260809033449.286233-1-skunkolee@gmail.com>

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:

New issues:
- [High] DMA buffers are read by the CPU before they are unmapped, causing stale data to be copied to user space on non-coherent architectures.
- [Medium] The driver uses 0 as a sentinel value to track unmapped DMA addresses, permanently leaking valid mappings at address 0.

Pre-existing issues:
- [High] The driver does not check the return value of `dma_map_single()`, causing invalid error addresses to be improperly unmapped.
- [High] Permanent leak of heap memory and DMA mappings when the operation is interrupted by a signal.
- [High] Uninitialized stack variables are passed to `copy_to_user()` when `sg.count == 0`.
- [High] The driver leaks uninitialized kernel heap memory to user space when the hardware transfers less data than requested.
- [High] Use-After-Free in sync_mode when `wait_for_completion_interruptible` is interrupted by a signal.
--

--- Patch [1]: [PATCH] scsi: aacraid: fix DMA mapping leak in aac_send_raw_srb() ---
commit 863e921c48579ca39e3e4f977e819659b4711e60
Author: Ivy Lopez <skunkolee@gmail.com>

scsi: aacraid: fix DMA mapping leak in aac_send_raw_srb()

aac_send_raw_srb() maps each scatter/gather entry for DMA via
dma_map_single() across five separate code paths, depending on the
adapter type and SG format. This commit introduces tracking for DMA
addresses in a new sg_addr[] array and unmaps them in the cleanup
path to prevent permanent resource exhaustion.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=220504

> diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
> index bd82aeb679aed..d4dffd6f8af0b 100644
> --- a/drivers/scsi/aacraid/commctrl.c
> +++ b/drivers/scsi/aacraid/commctrl.c
> @@ -492,6 +492,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
>  	u32 data_dir;
>  	void __user *sg_user[HBA_MAX_SG_EMBEDDED];
>  	void *sg_list[HBA_MAX_SG_EMBEDDED];
> +	dma_addr_t sg_addr[HBA_MAX_SG_EMBEDDED];
>  	u32 sg_count[HBA_MAX_SG_EMBEDDED];
>  	u32 sg_indx = 0;
[ ... ]
> @@ -517,6 +518,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
>  	}
>  
>  	memset(sg_list, 0, sizeof(sg_list)); /* cleanup may take issue */
> +	memset(sg_addr, 0, sizeof(sg_addr)); /* mark all entries unmapped */

[Severity: Medium]
Is it safe to use 0 as a sentinel value here?

On many platforms and IOMMUs, 0 is a valid DMA address. If dma_map_single()
successfully returns 0, the cleanup loop's check of if (sg_addr[i]) will
evaluate to false, skipping dma_unmap_single() and leaking that mapping.

>  	if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){
[ ... ]
> @@ -690,6 +692,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
>  			}
>  			addr = dma_map_single(&dev->pdev->dev, p, sg_count[i],
>  					      data_dir);
> +			sg_addr[i] = addr;

[Severity: High]
This is a pre-existing issue, but does this code properly validate the DMA
mapping?

If dma_map_single() fails (e.g., due to IOMMU space exhaustion), it typically
returns an error address. Since this is never checked using
dma_mapping_error(), this non-zero error address is saved and later passed
directly to dma_unmap_single() during cleanup.

>  			hbacmd->sge[i].addr_hi = cpu_to_le32((u32)(addr>>32));
[ ... ]
> @@ -986,8 +989,12 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)

[Severity: High]
This is a pre-existing issue, but does aac_send_raw_srb() leak uninitialized
kernel heap memory to user space before reaching the cleanup path?

The scatter-gather buffers are allocated via kmalloc() without __GFP_ZERO.
These buffers may remain uninitialized if SRB_DataOut is not set. If the
hardware completes the command but transfers less data than requested, the
subsequent copy_to_user() will unconditionally copy the remaining
uninitialized bytes to user space.

[Severity: High]
This is also a pre-existing issue, but if sg.count is 0 and flags & SRB_DataIn
is set, does the copy loop read uninitialized stack memory?

When sg.count is 0, the buffer allocation loops are skipped, leaving sg_indx
as 0, and both the sg_user and sg_count arrays uninitialized. Because the
copy loop right before this cleanup block iterates with i <= sg_indx, it
executes once for i=0 and calls copy_to_user() with stack garbage.

>  cleanup:
>  	kfree(user_srbcmd);
>  	if (rcode != -ERESTARTSYS) {

[Severity: High]
This is a pre-existing issue, but does skipping this block on -ERESTARTSYS
cause a permanent memory and DMA mapping leak?

Since sg_list and sg_addr are local stack variables, they are destroyed
when the function returns. If aac_fib_send() is interrupted by a signal,
the memory and mappings are left stranded with no way to free them when
the hardware eventually completes the command.

> -		for (i = 0; i <= sg_indx; i++)
> +		for (i = 0; i <= sg_indx; i++) {
> +			if (sg_addr[i])
> +				dma_unmap_single(&dev->pdev->dev, sg_addr[i],
> +						 sg_count[i], data_dir);

[Severity: High]
Can this result in stale data being copied to user space on non-coherent
architectures?

The CPU reads from the DMA buffers earlier during copy_to_user(). Because
dma_unmap_single() performs cache invalidation on non-coherent architectures,
placing it here in the cleanup block means it executes after the CPU has
already read the data, returning stale data to user space.

>  			kfree(sg_list[i]);
> +		}
>  		aac_fib_complete(srbfib);
>  		aac_fib_free(srbfib);

[Severity: High]
This is a pre-existing issue, but is there a use-after-free risk here if
aac_fib_send() operates in sync_mode and is interrupted by a signal?

If wait_for_completion_interruptible() returns -EFAULT on a signal, rcode
won't equal -ERESTARTSYS, causing aac_fib_free() to run here. However,
dev->sync_fib might still point to this freed fib, which
aac_src_intr_message() could later attempt to access when the hardware
completes the synchronous command.

>  	}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260809033449.286233-1-skunkolee@gmail.com?part=1

  reply	other threads:[~2026-08-09  3:48 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-09  3:34 [PATCH] scsi: aacraid: fix DMA mapping leak in aac_send_raw_srb() Ivy Lopez
2026-08-09  3:48 ` sashiko-bot [this message]
2026-08-10 22:27 ` [PATCH v2] " Ivy Lopez

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260809034803.058D01F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=skunkolee@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox