All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: ZDI-CAN-17016: New Vulnerability Report
       [not found] <DM5PR0102MB34776506CDCC1E2FFCF78C4580E09@DM5PR0102MB3477.prod.exchangelabs.com>
@ 2022-04-04  9:12 ` Dan Carpenter
  2022-04-05  5:53   ` Christoph Hellwig
  0 siblings, 1 reply; 2+ messages in thread
From: Dan Carpenter @ 2022-04-04  9:12 UTC (permalink / raw)
  To: zdi-disclosures
  Cc: security, Christoph Hellwig, Martin K. Petersen,
	Christophe JAILLET, Adaptec OEM Raid Solutions, linux-scsi

This is a valid double copy bug.  I think/hope that /dev/dpt_i2o can
only be opened by root so I'm going to CC the public lists.

Last week we deleted the PMCRAID_PASSTHROUGH_IOCTL ioctl in commit
f16aa285e618 ("scsi: pmcraid: Remove the PMCRAID_PASSTHROUGH_IOCTL ioctl
implementation").  The temptation is to delete I2OUSRCMD as well.

regards,
dan carpenter

On Fri, Apr 01, 2022 at 01:11:18PM +0000, zdi-disclosures@trendmicro.com wrote:
> ZDI-CAN-17016: Linux Kernel DPT I2O Controller Time-Of-Check Time-Of-Use Information Disclosure Vulnerability
> 
> -- CVSS -----------------------------------------
> 
> 6.7: AV:L/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:L
> 
> -- ABSTRACT -------------------------------------
> 
> Trend Micro's Zero Day Initiative has identified a vulnerability affecting the following products:
> Linux - Kernel
> 
> -- VULNERABILITY DETAILS ------------------------
> * Version tested:5.16.14
> * Installer file:linux-5.16.14.tar.xz
> * Platform tested:ubuntu 21.10 amd64
> 
> ---
> 
> ### Analysis
> 
> ```
> double fetch bug exist in the function adpt_i2o_passthru of DPT I2O controller
> it leads to copy the OOB memory to ring3
> ps. we didn't have the real hardware for testing, the POC is written based on modified DPT I2O controller
> ```
> 
> ~~~C++
> static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
> {
> ...
>         /* Copy in the user's I2O command */
>         if(copy_from_user(msg, user_msg, size)) {
>                 return -EFAULT;
>         }
> ...
>         sg_offset = (msg[0]>>4)&0xf;
>         msg[2] = 0x40000000; // IOCTL context
>         msg[3] = adpt_ioctl_to_context(pHba, reply);
>         if (msg[3] == (u32)-1) {
>                 rcode = -EBUSY;
>                 goto free;
>         }
> ...
>         if(sg_offset) {
>                 // TODO add 64 bit API
>                 struct sg_simple_element *sg =  (struct sg_simple_element*) (msg+sg_offset);
>                 sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element);
>                 if (sg_count > pHba->sg_tablesize){
>                         printk(KERN_DEBUG"%s:IOCTL SG List too large (%u)\n", pHba->name,sg_count);
>                         rcode = -EINVAL;
>                         goto free;
>                 }
> 
>                 for(i = 0; i < sg_count; i++) {
>                         int sg_size;
> 
>                         if (!(sg[i].flag_count & 0x10000000 /*I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT*/)) {
>                                 printk(KERN_DEBUG"%s:Bad SG element %d - not simple (%x)\n",pHba->name,i,  sg[i].flag_count);
>                                 rcode = -EINVAL;
>                                 goto cleanup;
>                         }
>                         sg_size = sg[i].flag_count & 0xffffff;
>                         /* Allocate memory for the transfer */
>                         p = dma_alloc_coherent(&pHba->pDev->dev, sg_size, &addr, GFP_KERNEL);                                   <--- (1) allocate buffer with the 1st fetched size
>                         if(!p) {
>                                 printk(KERN_DEBUG"%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
>                                                 pHba->name,sg_size,i,sg_count);
>                                 rcode = -ENOMEM;
>                                 goto cleanup;
>                         }
>                         sg_list[sg_index++] = p; // sglist indexed with input frame, not our internal frame.
>                         /* Copy in the user's SG buffer if necessary */
>                         if(sg[i].flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR*/) {
>                                 // sg_simple_element API is 32 bit
>                                 if (copy_from_user(p,(void __user *)(ulong)sg[i].addr_bus, sg_size)) {
>                                         printk(KERN_DEBUG"%s: Could not copy SG buf %d FROM user\n",pHba->name,i);
>                                         rcode = -EFAULT;
>                                         goto cleanup;
>                                 }
>                         }
>                         /* sg_simple_element API is 32 bit, but addr < 4GB */
>                         sg[i].addr_bus = addr;
>                 }
>         }
> ...
> 
>         if(sg_offset) {
> ...
>                 /* Copy in the user's I2O command */
>                 if (copy_from_user (msg, user_msg, size)) {
>                         rcode = -EFAULT;
>                         goto cleanup;
>                 }
>                 sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element);
> 
>                 // TODO add 64 bit API
>                 sg       = (struct sg_simple_element*)(msg + sg_offset);
>                 for (j = 0; j < sg_count; j++) {
>                         /* Copy out the SG list to user's buffer if necessary */
>                         if(! (sg[j].flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR*/)) {
>                                 sg_size = sg[j].flag_count & 0xffffff;
>                                 // sg_simple_element API is 32 bit
>                                 if (copy_to_user((void __user *)(ulong)sg[j].addr_bus,sg_list[j], sg_size)) {           <--- (2) copy with the 2nd fetched size
>                                         printk(KERN_WARNING"%s: Could not copy %p TO user %x\n",pHba->name, sg_list[j], sg[j].addr_bus);
>                                         rcode = -EFAULT;
>                                         goto cleanup;
>                                 }
>                         }
>                 }
>         }
> ...
> }
> ~~~
> 
> 
> 
> debug log
> ```
> (gdb) u drivers/scsi/dpt_i2o.c:1748
> adpt_i2o_passthru (pHba=<optimized out>, arg=<optimized out>) at drivers/scsi/dpt_i2o.c:1748
> 1748                            if(sg[i].flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR*/) {
> (gdb) p/x sg[i].flag_count
> $4 = 0x14000010
> (gdb) p/x sg_size
> $5 = 0x10
> (gdb) l
> 1743                                    rcode = -ENOMEM;
> 1744                                    goto cleanup;
> 1745                            }
> 1746                            sg_list[sg_index++] = p; // sglist indexed with input frame, not our internal frame.
> 1747                            /* Copy in the user's SG buffer if necessary */
> 1748                            if(sg[i].flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR*/) {
> 1749                                    // sg_simple_element API is 32 bit
> 1750                                    if (copy_from_user(p,(void __user *)(ulong)sg[i].addr_bus, sg_size)) {
> 1751                                            printk(KERN_DEBUG"%s: Could not copy SG buf %d FROM user\n",pHba->name,i);
> 1752                                            rcode = -EFAULT;
> (gdb) bt
> #0  adpt_i2o_passthru (pHba=<optimized out>, arg=<optimized out>) at drivers/scsi/dpt_i2o.c:1748
> #1  0xffffffffc00045c8 in adpt_ioctl (cmd=17484, arg=94117499510944, file=<optimized out>, inode=<optimized out>, inode=<optimized out>) at drivers/scsi/dpt_i2o.c:2006
> #2  0xffffffffc00053ce in adpt_unlocked_ioctl (file=<optimized out>, cmd=17484, arg=94117499510944) at drivers/scsi/dpt_i2o.c:2066
> #3  0xffffffff816207a2 in ?? ()
> #4  0x0000000000000000 in ?? ()
> (gdb) u drivers/scsi/dpt_i2o.c:1815
> adpt_i2o_passthru (pHba=<optimized out>, arg=<optimized out>) at drivers/scsi/dpt_i2o.c:1815
> 1815                            if(! (sg[j].flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR*/)) {
> (gdb) l
> 1810
> 1811                    // TODO add 64 bit API
> 1812                    sg       = (struct sg_simple_element*)(msg + sg_offset);
> 1813                    for (j = 0; j < sg_count; j++) {
> 1814                            /* Copy out the SG list to user's buffer if necessary */
> 1815                            if(! (sg[j].flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR*/)) {
> 1816                                    sg_size = sg[j].flag_count & 0xffffff;
> 1817                                    // sg_simple_element API is 32 bit
> 1818                                    if (copy_to_user((void __user *)(ulong)sg[j].addr_bus,sg_list[j], sg_size)) {
> 1819                                            printk(KERN_WARNING"%s: Could not copy %p TO user %x\n",pHba->name, sg_list[j], sg[j].addr_bus);
> (gdb) p/x sg[j].flag_count
> $6 = 0x10002000
> (gdb) u drivers/scsi/dpt_i2o.c:1816
> adpt_i2o_passthru (pHba=<optimized out>, arg=<optimized out>) at drivers/scsi/dpt_i2o.c:1818
> 1818                                    if (copy_to_user((void __user *)(ulong)sg[j].addr_bus,sg_list[j], sg_size)) {
> (gdb) p/x sg_size
> $7 = 0x2000
> (gdb) x/10xg sg_list[j]
> 0xffff8880066d6560:     0x4141414141414141      0x4141414141414141                      // OOB read 0x2000-0x10 bytes
> 0xffff8880066d6570:     0xb000007000000122      0x0000000000000000
> 0xffff8880066d6580:     0xffff888006798000      0xffff8880066d6540
> 0xffff8880066d6590:     0xe020000700000001      0x0000000000000000
> 0xffff8880066d65a0:     0xffff88800e6dc400      0xa180005900000120
> (gdb) bt
> #0  adpt_i2o_passthru (pHba=<optimized out>, arg=<optimized out>) at drivers/scsi/dpt_i2o.c:1818
> #1  0xffffffffc00045c8 in adpt_ioctl (cmd=17484, arg=94117499510944, file=<optimized out>, inode=<optimized out>, inode=<optimized out>) at drivers/scsi/dpt_i2o.c:2006
> #2  0xffffffffc00053ce in adpt_unlocked_ioctl (file=<optimized out>, cmd=17484, arg=94117499510944) at drivers/scsi/dpt_i2o.c:2066
> #3  0xffffffff816207a2 in ?? ()
> #4  0x0000000000000000 in ?? ()
> (gdb)
> ```
> 
> 
> -- CREDIT ---------------------------------------
> This vulnerability was discovered by:
> Lucas Leong (@_wmliang_) and Reno Robert of Trend Micro Zero Day Initiative
> 
> -- FURTHER DETAILS ------------------------------
> 
> If supporting files were contained with this report they are provided within a password protected ZIP file. The password is the ZDI candidate number in the form: ZDI-CAN-XXXX where XXXX is the ID number.
> 
> Please confirm receipt of this report. We expect all vendors to remediate ZDI vulnerabilities within 120 days of the reported date. If you are ready to release a patch at any point leading up to the deadline, please coordinate with us so that we may release our advisory detailing the issue. If the 120-day deadline is reached and no patch has been made available we will release a limited public advisory with our own mitigations, so that the public can protect themselves in the absence of a patch. Please keep us updated regarding the status of this issue and feel free to contact us at any time:
> 
> Zero Day Initiative
> zdi-disclosures@trendmicro.com
> 
> The PGP key used for all ZDI vendor communications is available from:
> 
>   http://www.zerodayinitiative.com/documents/disclosures-pgp-key.asc 
> 
> -- INFORMATION ABOUT THE ZDI --------------------
> Established by TippingPoint and acquired by Trend Micro, the Zero Day Initiative (ZDI) neither re-sells vulnerability details nor exploit code. Instead, upon notifying the affected product vendor, the ZDI provides its Trend Micro TippingPoint customers with zero day protection through its intrusion prevention technology. Explicit details regarding the specifics of the vulnerability are not exposed to any parties until an official vendor patch is publicly available.
> 
> Please contact us for further details or refer to:
> 
>   http://www.zerodayinitiative.com 
> 
> -- DISCLOSURE POLICY ----------------------------
> 
> Our vulnerability disclosure policy is available online at:
> 
>   http://www.zerodayinitiative.com/advisories/disclosure_policy/ 
> 
> TREND MICRO EMAIL NOTICE
> 
> The information contained in this email and any attachments is confidential and may be subject to copyright or other intellectual property protection. If you are not the intended recipient, you are not authorized to use or disclose this information, and we request that you notify us by reply mail or telephone and delete the original message from your mail system.
> 
> For details about what personal information we collect and why, please see our Privacy Notice on our website at: Read privacy policy<http://www.trendmicro.com/privacy >

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

* Re: ZDI-CAN-17016: New Vulnerability Report
  2022-04-04  9:12 ` ZDI-CAN-17016: New Vulnerability Report Dan Carpenter
@ 2022-04-05  5:53   ` Christoph Hellwig
  0 siblings, 0 replies; 2+ messages in thread
From: Christoph Hellwig @ 2022-04-05  5:53 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: zdi-disclosures, security, Christoph Hellwig, Martin K. Petersen,
	Christophe JAILLET, Adaptec OEM Raid Solutions, linux-scsi

On Mon, Apr 04, 2022 at 12:12:11PM +0300, Dan Carpenter wrote:
> This is a valid double copy bug.  I think/hope that /dev/dpt_i2o can
> only be opened by root so I'm going to CC the public lists.
> 
> Last week we deleted the PMCRAID_PASSTHROUGH_IOCTL ioctl in commit
> f16aa285e618 ("scsi: pmcraid: Remove the PMCRAID_PASSTHROUGH_IOCTL ioctl
> implementation").  The temptation is to delete I2OUSRCMD as well.

I'm all for it.  In fact given how bad the driver is I would not be
sad to see it gone, but last time this came up about 5 years ago there
still were users.

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

end of thread, other threads:[~2022-04-05  5:53 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <DM5PR0102MB34776506CDCC1E2FFCF78C4580E09@DM5PR0102MB3477.prod.exchangelabs.com>
2022-04-04  9:12 ` ZDI-CAN-17016: New Vulnerability Report Dan Carpenter
2022-04-05  5:53   ` Christoph Hellwig

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.