Linux SCSI subsystem development
 help / color / mirror / Atom feed
* [BUG] drivers/message/fusion/mptctl: heap buffer overflow in kbuf_alloc_2_sgl
@ 2026-10-25  4:05 Maholi Tumanggor
  2026-10-25  6:13 ` Greg KH
  0 siblings, 1 reply; 3+ messages in thread
From: Maholi Tumanggor @ 2026-10-25  4:05 UTC (permalink / raw)
  To: linux-scsi, security

Reported-by: Maholi Tumanggor [maholitumanggor@gmail.com]

AFFECTED FILE
=============
drivers/message/fusion/mptctl.c
Verified identical in mainline (84738 bytes):
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/drivers/message/fusion/mptctl.c

Tested on: Linux 6.12.38+kali-amd64, mptctl driver version 3.04.20
Hardware:  LSI 53c1030 PCI-X Fusion-MPT (VirtualBox emulated)


DESCRIPTION
===========
Function kbuf_alloc_2_sgl() in mptctl.c allocates a buflist array of
74 bytes via kzalloc(MAX_SGL_BYTES / 8), then writes struct buflist
entries (16 bytes each on 64-bit: u8 pointer + int + padding) into it
without any bounds check on the index buflist_ent.

This gives a maximum of 4 safe entries (74 / 16 = 4). Each entry
corresponds to one 128KB DMA chunk (MAX_KMALLOC_SZ). When the
MPTFWDOWNLOAD ioctl is called with fwlen greater than 524288 bytes
(4 x 128KB), buflist_ent reaches 4 and subsequent iterations write
past the end of the heap allocation.

Relevant code (around line 1031):

    i = MAX_SGL_BYTES / 8;           /* = 74 bytes */
    buflist = kzalloc(i, GFP_USER);  /* max 4 entries on 64-bit */
    ...
    while (bytes_allocd < bytes) {
        buflist[buflist_ent].len  = this_alloc;        /* NO BOUNDS CHECK */
        buflist[buflist_ent].kptr = dma_alloc_coherent(...);
        buflist_ent++;
    }


REPRODUCER
==========
Trigger condition:
- Root privileges required
- /dev/mptctl accessible (mknod /dev/mptctl c 10 220)
- CONFIG_FUSION_CTL enabled
- MPTFWDOWNLOAD ioctl with fwlen = 524289 (512KB + 1 byte)

Minimal C reproducer (available on maintainer request per guidelines):

    struct mpt_fw_xfer {
        unsigned int iocnum;
        unsigned int fwlen;
        void *bufp;
    };
    #define MPTFWDOWNLOAD _IOWR('m', 15, struct mpt_fw_xfer)

    char *buf = calloc(1, 524289);
    struct mpt_fw_xfer req = { .iocnum=0, .fwlen=524289, .bufp=buf };
    int fd = open("/dev/mptctl", O_RDWR);
    ioctl(fd, MPTFWDOWNLOAD, &req);


OBSERVED BEHAVIOR (dmesg on live system)
=========================================
    mptctl: ioc0: WARNING - -SG: No can do - Chain required!
    mptctl: WARNING - (freeing 11 frags)

11 iterations confirm 7 out-of-bounds writes past the 74-byte
buflist allocation. No kernel crash was observed, indicating silent
heap corruption. Each OOB write places a DMA address (8 bytes) and
buffer length (4 bytes) into adjacent kernel heap memory.


PROPOSED FIX
============
Add a bounds check before each buflist[] access in kbuf_alloc_2_sgl():

--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -1028,6 +1028,7 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset,
        int              sg_spill = MAX_FRAGS_SPILL1;
        int              dir;
+       int              max_buflist_ent = (MAX_SGL_BYTES / 8) /
+                                          sizeof(struct buflist);

        if (bytes < 0)
                return NULL;
@@ -1063,6 +1063,10 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset,
        while (bytes_allocd < bytes) {
                this_alloc = min(alloc_sz, bytes-bytes_allocd);
+               if (buflist_ent >= max_buflist_ent) {
+                       printk(KERN_ERR "mptctl: buflist overflow\n");
+                       goto free_and_fail;
+               }
                buflist[buflist_ent].len = this_alloc;
                buflist[buflist_ent].kptr = dma_alloc_coherent(
                        &ioc->pcidev->dev,


CONDITIONS
==========
- Root access to /dev/mptctl required
- LSI Fusion MPT hardware or compatible emulation
- CONFIG_FUSION_CTL=y or =m
- 64-bit kernel (32-bit has different struct buflist size,
  threshold is higher but same bug exists)


IMPACT
======
Silent kernel heap corruption. The corrupted region receives DMA
addresses and lengths from dma_alloc_coherent(). No crash observed
on tested system, meaning corruption goes undetected and may affect
adjacent heap objects depending on kernel heap layout.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [BUG] drivers/message/fusion/mptctl: heap buffer overflow in kbuf_alloc_2_sgl
       [not found] <CAELScTa0EePsq_Aivwb2rukQL_vNprumuH8jdwk2ST6rio=dgw@mail.gmail.com>
@ 2026-10-25  5:33 ` Willy Tarreau
  0 siblings, 0 replies; 3+ messages in thread
From: Willy Tarreau @ 2026-10-25  5:33 UTC (permalink / raw)
  To: Maholi Tumanggor
  Cc: linux-scsi, ranjan.kumar, sathya.prakash, sreekanth.reddy,
	suganath-prabu.subramani

Hello,

Thanks for your report. The maintainers have been added in Cc. Please
don't forget to add them next time, as per
Documentation/process/security-bugs.rst. Also there's no need to Cc
security@k.o when reporting to public lists (now moved to Bcc).
Regardless, a few comments below.

On Sun, 25 Oct 2026 11:01:44 +0700, maholitumanggor@gmail.com wrote:
> Reported-by: *Maholi Tumanggor* [maholitumanggor@gmail.com]
>
>
> *AFFECTED FILE*=============
> drivers/message/fusion/mptctl.c
> Verified identical in mainline (84738 bytes):
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/drivers/message/fusion/mptctl.c
>
> Tested on: Linux 6.12.38+kali-amd64, mptctl driver version 3.04.20
> Hardware:  LSI 53c1030 PCI-X Fusion-MPT (VirtualBox emulated)
>
>
> *DESCRIPTION*
> ===========
> Function kbuf_alloc_2_sgl() in mptctl.c allocates a buflist array of
> 74 bytes via kzalloc(MAX_SGL_BYTES / 8), then writes struct buflist
> entries (16 bytes each on 64-bit: u8 pointer + int + padding) into it
> without any bounds check on the index buflist_ent.
>
> This gives a maximum of 4 safe entries (74 / 16 = 4). Each entry
> corresponds to one 128KB DMA chunk (MAX_KMALLOC_SZ). When the
> MPTFWDOWNLOAD ioctl is called with fwlen greater than 524288 bytes
> (4 x 128KB), buflist_ent reaches 4 and subsequent iterations write
> past the end of the heap allocation.
>
> Relevant code (around line 1031):
>
>     i = MAX_SGL_BYTES / 8;           /* = 74 bytes */
>     buflist = kzalloc(i, GFP_USER);  /* max 4 entries on 64-bit */
>     ...
>     while (bytes_allocd < bytes) {
>         buflist[buflist_ent].len  = this_alloc;        /* NO BOUNDS CHECK */
>         buflist[buflist_ent].kptr = dma_alloc_coherent(...);
>         buflist_ent++;
>     }
>
>
>
> *REPRODUCER*==========
> Trigger condition:
> - Root privileges required
> - /dev/mptctl accessible (mknod /dev/mptctl c 10 220)
> - CONFIG_FUSION_CTL enabled
> - MPTFWDOWNLOAD ioctl with fwlen = 524289 (512KB + 1 byte)
>
> Minimal C reproducer (available on maintainer request per guidelines):
>
>     struct mpt_fw_xfer {
>         unsigned int iocnum;
>         unsigned int fwlen;
>         void *bufp;
>     };
>     #define MPTFWDOWNLOAD _IOWR('m', 15, struct mpt_fw_xfer)
>
>     char *buf = calloc(1, 524289);
>     struct mpt_fw_xfer req = { .iocnum=0, .fwlen=524289, .bufp=buf };
>     int fd = open("/dev/mptctl", O_RDWR);
>     ioctl(fd, MPTFWDOWNLOAD, &req);
>
>
>
> *OBSERVED BEHAVIOR (dmesg on live system)*
> =========================================
>     mptctl: ioc0: WARNING - -SG: No can do - Chain required!
>     mptctl: WARNING - (freeing 11 frags)
>
> 11 iterations confirm 7 out-of-bounds writes past the 74-byte
> buflist allocation. No kernel crash was observed, indicating silent
> heap corruption. Each OOB write places a DMA address (8 bytes) and
> buffer length (4 bytes) into adjacent kernel heap memory.
>
>
>
> *PROPOSED FIX*============
> Add a bounds check before each buflist[] access in kbuf_alloc_2_sgl():
>
> --- a/drivers/message/fusion/mptctl.c
> +++ b/drivers/message/fusion/mptctl.c
> @@ -1028,6 +1028,7 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset,
>         int              sg_spill = MAX_FRAGS_SPILL1;
>         int              dir;
> +       int              max_buflist_ent = (MAX_SGL_BYTES / 8) /
> +                                          sizeof(struct buflist);
>
>         if (bytes < 0)
>                 return NULL;
> @@ -1063,6 +1063,10 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int
> sge_offset,
>         while (bytes_allocd < bytes) {
>                 this_alloc = min(alloc_sz, bytes-bytes_allocd);
> +               if (buflist_ent >= max_buflist_ent) {
> +                       printk(KERN_ERR "mptctl: buflist overflow\n");
> +                       goto free_and_fail;
> +               }
>                 buflist[buflist_ent].len = this_alloc;
>                 buflist[buflist_ent].kptr = dma_alloc_coherent(
>                         &ioc->pcidev->dev,

Could you please turn your fix into a patch that can directly be applied ?
This would save some maintainers' time and if accepted, you'd get full
credit for finding and fixing this bug. For guidance on how to write
patches, please see Documentation/process/submitting-patches.rst.

Also please note that your mailer turned tabs into spaces so you'll also
need to check Documentation/process/email-clients.rst for instructions
on how to fix it.

> *CONDITIONS*
> ==========
> - Root access to /dev/mptctl required

So this is just a regular bug, not a security issue.

> - LSI Fusion MPT hardware or compatible emulation
> - CONFIG_FUSION_CTL=y or =m
> - 64-bit kernel (32-bit has different struct buflist size,
>   threshold is higher but same bug exists)
>
>
> *IMPACT*
> ======
> Silent kernel heap corruption. The corrupted region receives DMA
> addresses and lengths from dma_alloc_coherent(). No crash observed
> on tested system, meaning corruption goes undetected and may affect
> adjacent heap objects depending on kernel heap layout.
>

Thanks,
Willy

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [BUG] drivers/message/fusion/mptctl: heap buffer overflow in kbuf_alloc_2_sgl
  2026-10-25  4:05 [BUG] drivers/message/fusion/mptctl: heap buffer overflow in kbuf_alloc_2_sgl Maholi Tumanggor
@ 2026-10-25  6:13 ` Greg KH
  0 siblings, 0 replies; 3+ messages in thread
From: Greg KH @ 2026-10-25  6:13 UTC (permalink / raw)
  To: Maholi Tumanggor; +Cc: linux-scsi, security

On Sun, Oct 25, 2026 at 11:05:38AM +0700, Maholi Tumanggor wrote:
> PROPOSED FIX
> ============
> Add a bounds check before each buflist[] access in kbuf_alloc_2_sgl():

Please just turn this into a real patch that can be applied if you wish
to see this resolved.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-10-25  6:13 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-25  4:05 [BUG] drivers/message/fusion/mptctl: heap buffer overflow in kbuf_alloc_2_sgl Maholi Tumanggor
2026-10-25  6:13 ` Greg KH
     [not found] <CAELScTa0EePsq_Aivwb2rukQL_vNprumuH8jdwk2ST6rio=dgw@mail.gmail.com>
2026-10-25  5:33 ` Willy Tarreau

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox