* [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 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 --
[not found] <CAELScTa0EePsq_Aivwb2rukQL_vNprumuH8jdwk2ST6rio=dgw@mail.gmail.com>
2026-10-25 5:33 ` [BUG] drivers/message/fusion/mptctl: heap buffer overflow in kbuf_alloc_2_sgl Willy Tarreau
2026-10-25 4:05 Maholi Tumanggor
2026-10-25 6:13 ` Greg KH
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox