USB: ene_usb6250: fix DMA to the stack
authorAlan Stern <stern@rowland.harvard.edu>
Tue, 16 May 2017 15:47:29 +0000 (11:47 -0400)
committerBen Hutchings <ben@decadent.org.uk>
Fri, 15 Sep 2017 17:30:42 +0000 (18:30 +0100)
commit 628c2893d44876ddd11602400c70606ade62e129 upstream.

The ene_usb6250 sub-driver in usb-storage does USB I/O to buffers on
the stack, which doesn't work with vmapped stacks.  This patch fixes
the problem by allocating a separate 512-byte buffer at probe time and
using it for all of the offending I/O operations.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Reported-and-tested-by: Andreas Hartmann <andihartmann@01019freenet.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
drivers/usb/storage/ene_ub6250.c

index 9fbe742..8f6fa2d 100644 (file)
@@ -431,6 +431,10 @@ struct ms_lib_ctrl {
 #define SD_BLOCK_LEN  9
 
 struct ene_ub6250_info {
+
+       /* I/O bounce buffer */
+       u8              *bbuf;
+
        /* for 6250 code */
        struct SD_STATUS        SD_Status;
        struct MS_STATUS        MS_Status;
@@ -478,8 +482,11 @@ static int ene_load_bincode(struct us_data *us, unsigned char flag);
 
 static void ene_ub6250_info_destructor(void *extra)
 {
+       struct ene_ub6250_info *info = (struct ene_ub6250_info *) extra;
+
        if (!extra)
                return;
+       kfree(info->bbuf);
 }
 
 static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
@@ -843,8 +850,9 @@ static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr,
                u8 PageNum, u32 *PageBuf, struct ms_lib_type_extdat *ExtraDat)
 {
        struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+       struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+       u8 *bbuf = info->bbuf;
        int result;
-       u8 ExtBuf[4];
        u32 bn = PhyBlockAddr * 0x20 + PageNum;
 
        /* printk(KERN_INFO "MS --- MS_ReaderReadPage,
@@ -887,7 +895,7 @@ static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr,
        bcb->CDB[2]     = (unsigned char)(PhyBlockAddr>>16);
        bcb->CDB[6]     = 0x01;
 
-       result = ene_send_scsi_cmd(us, FDIR_READ, &ExtBuf, 0);
+       result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
        if (result != USB_STOR_XFER_GOOD)
                return USB_STOR_TRANSPORT_ERROR;
 
@@ -896,9 +904,9 @@ static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr,
        ExtraDat->status0  = 0x10;  /* Not yet,fireware support */
 
        ExtraDat->status1  = 0x00;  /* Not yet,fireware support */
-       ExtraDat->ovrflg   = ExtBuf[0];
-       ExtraDat->mngflg   = ExtBuf[1];
-       ExtraDat->logadr   = memstick_logaddr(ExtBuf[2], ExtBuf[3]);
+       ExtraDat->ovrflg   = bbuf[0];
+       ExtraDat->mngflg   = bbuf[1];
+       ExtraDat->logadr   = memstick_logaddr(bbuf[2], bbuf[3]);
 
        return USB_STOR_TRANSPORT_GOOD;
 }
@@ -1324,8 +1332,9 @@ static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock,
                                u8 PageNum, struct ms_lib_type_extdat *ExtraDat)
 {
        struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+       struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+       u8 *bbuf = info->bbuf;
        int result;
-       u8 ExtBuf[4];
 
        /* printk("MS_LibReadExtra --- PhyBlock = %x, PageNum = %x\n", PhyBlock, PageNum); */
        memset(bcb, 0, sizeof(struct bulk_cb_wrap));
@@ -1340,7 +1349,7 @@ static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock,
        bcb->CDB[2]     = (unsigned char)(PhyBlock>>16);
        bcb->CDB[6]     = 0x01;
 
-       result = ene_send_scsi_cmd(us, FDIR_READ, &ExtBuf, 0);
+       result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
        if (result != USB_STOR_XFER_GOOD)
                return USB_STOR_TRANSPORT_ERROR;
 
@@ -1348,9 +1357,9 @@ static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock,
        ExtraDat->intr     = 0x80;  /* Not yet, waiting for fireware support */
        ExtraDat->status0  = 0x10;  /* Not yet, waiting for fireware support */
        ExtraDat->status1  = 0x00;  /* Not yet, waiting for fireware support */
-       ExtraDat->ovrflg   = ExtBuf[0];
-       ExtraDat->mngflg   = ExtBuf[1];
-       ExtraDat->logadr   = memstick_logaddr(ExtBuf[2], ExtBuf[3]);
+       ExtraDat->ovrflg   = bbuf[0];
+       ExtraDat->mngflg   = bbuf[1];
+       ExtraDat->logadr   = memstick_logaddr(bbuf[2], bbuf[3]);
 
        return USB_STOR_TRANSPORT_GOOD;
 }
@@ -1554,9 +1563,9 @@ static int ms_lib_scan_logicalblocknumber(struct us_data *us, u16 btBlk1st)
        u16 PhyBlock, newblk, i;
        u16 LogStart, LogEnde;
        struct ms_lib_type_extdat extdat;
-       u8 buf[0x200];
        u32 count = 0, index = 0;
        struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+       u8 *bbuf = info->bbuf;
 
        for (PhyBlock = 0; PhyBlock < info->MS_Lib.NumberOfPhyBlock;) {
                ms_lib_phy_to_log_range(PhyBlock, &LogStart, &LogEnde);
@@ -1570,14 +1579,16 @@ static int ms_lib_scan_logicalblocknumber(struct us_data *us, u16 btBlk1st)
                        }
 
                        if (count == PhyBlock) {
-                               ms_lib_read_extrablock(us, PhyBlock, 0, 0x80, &buf);
+                               ms_lib_read_extrablock(us, PhyBlock, 0, 0x80,
+                                               bbuf);
                                count += 0x80;
                        }
                        index = (PhyBlock % 0x80) * 4;
 
-                       extdat.ovrflg = buf[index];
-                       extdat.mngflg = buf[index+1];
-                       extdat.logadr = memstick_logaddr(buf[index+2], buf[index+3]);
+                       extdat.ovrflg = bbuf[index];
+                       extdat.mngflg = bbuf[index+1];
+                       extdat.logadr = memstick_logaddr(bbuf[index+2],
+                                       bbuf[index+3]);
 
                        if ((extdat.ovrflg & MS_REG_OVR_BKST) != MS_REG_OVR_BKST_OK) {
                                ms_lib_setacquired_errorblock(us, PhyBlock);
@@ -2066,9 +2077,9 @@ static int ene_ms_init(struct us_data *us)
 {
        struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
        int result;
-       u8 buf[0x200];
        u16 MSP_BlockSize, MSP_UserAreaBlocks;
        struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+       u8 *bbuf = info->bbuf;
 
        printk(KERN_INFO "transport --- ENE_MSInit\n");
 
@@ -2087,13 +2098,13 @@ static int ene_ms_init(struct us_data *us)
        bcb->CDB[0]     = 0xF1;
        bcb->CDB[1]     = 0x01;
 
-       result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0);
+       result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
        if (result != USB_STOR_XFER_GOOD) {
                printk(KERN_ERR "Execution MS Init Code Fail !!\n");
                return USB_STOR_TRANSPORT_ERROR;
        }
        /* the same part to test ENE */
-       info->MS_Status = *(struct MS_STATUS *)&buf[0];
+       info->MS_Status = *(struct MS_STATUS *) bbuf;
 
        if (info->MS_Status.Insert && info->MS_Status.Ready) {
                printk(KERN_INFO "Insert     = %x\n", info->MS_Status.Insert);
@@ -2102,15 +2113,15 @@ static int ene_ms_init(struct us_data *us)
                printk(KERN_INFO "IsMSPHG    = %x\n", info->MS_Status.IsMSPHG);
                printk(KERN_INFO "WtP= %x\n", info->MS_Status.WtP);
                if (info->MS_Status.IsMSPro) {
-                       MSP_BlockSize      = (buf[6] << 8) | buf[7];
-                       MSP_UserAreaBlocks = (buf[10] << 8) | buf[11];
+                       MSP_BlockSize      = (bbuf[6] << 8) | bbuf[7];
+                       MSP_UserAreaBlocks = (bbuf[10] << 8) | bbuf[11];
                        info->MSP_TotalBlock = MSP_BlockSize * MSP_UserAreaBlocks;
                } else {
                        ms_card_init(us); /* Card is MS (to ms.c)*/
                }
                US_DEBUGP("MS Init Code OK !!\n");
        } else {
-               US_DEBUGP("MS Card Not Ready --- %x\n", buf[0]);
+               US_DEBUGP("MS Card Not Ready --- %x\n", bbuf[0]);
                return USB_STOR_TRANSPORT_ERROR;
        }
 
@@ -2120,9 +2131,9 @@ static int ene_ms_init(struct us_data *us)
 static int ene_sd_init(struct us_data *us)
 {
        int result;
-       u8  buf[0x200];
        struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
        struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+       u8 *bbuf = info->bbuf;
 
        US_DEBUGP("transport --- ENE_SDInit\n");
        /* SD Init Part-1 */
@@ -2156,15 +2167,15 @@ static int ene_sd_init(struct us_data *us)
        bcb->Flags              = 0x80;
        bcb->CDB[0]             = 0xF1;
 
-       result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0);
+       result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
        if (result != USB_STOR_XFER_GOOD) {
                US_DEBUGP("Execution SD Init Code Fail !!\n");
                return USB_STOR_TRANSPORT_ERROR;
        }
 
-       info->SD_Status =  *(struct SD_STATUS *)&buf[0];
+       info->SD_Status =  *(struct SD_STATUS *) bbuf;
        if (info->SD_Status.Insert && info->SD_Status.Ready) {
-               ene_get_card_status(us, (unsigned char *)&buf);
+               ene_get_card_status(us, bbuf);
                US_DEBUGP("Insert     = %x\n", info->SD_Status.Insert);
                US_DEBUGP("Ready      = %x\n", info->SD_Status.Ready);
                US_DEBUGP("IsMMC      = %x\n", info->SD_Status.IsMMC);
@@ -2172,7 +2183,7 @@ static int ene_sd_init(struct us_data *us)
                US_DEBUGP("HiSpeed    = %x\n", info->SD_Status.HiSpeed);
                US_DEBUGP("WtP        = %x\n", info->SD_Status.WtP);
        } else {
-               US_DEBUGP("SD Card Not Ready --- %x\n", buf[0]);
+               US_DEBUGP("SD Card Not Ready --- %x\n", bbuf[0]);
                return USB_STOR_TRANSPORT_ERROR;
        }
        return USB_STOR_TRANSPORT_GOOD;
@@ -2182,13 +2193,15 @@ static int ene_sd_init(struct us_data *us)
 static int ene_init(struct us_data *us)
 {
        int result;
-       u8  misc_reg03 = 0;
+       u8  misc_reg03;
        struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
+       u8 *bbuf = info->bbuf;
 
-       result = ene_get_card_type(us, REG_CARD_STATUS, &misc_reg03);
+       result = ene_get_card_type(us, REG_CARD_STATUS, bbuf);
        if (result != USB_STOR_XFER_GOOD)
                return USB_STOR_TRANSPORT_ERROR;
 
+       misc_reg03 = bbuf[0];
        if (misc_reg03 & 0x01) {
                if (!info->SD_Status.Ready) {
                        result = ene_sd_init(us);
@@ -2304,8 +2317,9 @@ static int ene_ub6250_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
 {
        int result;
-       u8  misc_reg03 = 0;
+       u8  misc_reg03;
        struct us_data *us;
+       struct ene_ub6250_info *info;
 
        result = usb_stor_probe1(&us, intf, id,
                   (id - ene_ub6250_usb_ids) + ene_ub6250_unusual_dev_list);
@@ -2313,11 +2327,16 @@ static int ene_ub6250_probe(struct usb_interface *intf,
                return result;
 
        /* FIXME: where should the code alloc extra buf ? */
-       if (!us->extra) {
-               us->extra = kzalloc(sizeof(struct ene_ub6250_info), GFP_KERNEL);
-               if (!us->extra)
-                       return -ENOMEM;
-               us->extra_destructor = ene_ub6250_info_destructor;
+       us->extra = kzalloc(sizeof(struct ene_ub6250_info), GFP_KERNEL);
+       if (!us->extra)
+               return -ENOMEM;
+       us->extra_destructor = ene_ub6250_info_destructor;
+
+       info = (struct ene_ub6250_info *)(us->extra);
+       info->bbuf = kmalloc(512, GFP_KERNEL);
+       if (!info->bbuf) {
+               kfree(us->extra);
+               return -ENOMEM;
        }
 
        us->transport_name = "ene_ub6250";
@@ -2329,12 +2348,13 @@ static int ene_ub6250_probe(struct usb_interface *intf,
                return result;
 
        /* probe card type */
-       result = ene_get_card_type(us, REG_CARD_STATUS, &misc_reg03);
+       result = ene_get_card_type(us, REG_CARD_STATUS, info->bbuf);
        if (result != USB_STOR_XFER_GOOD) {
                usb_stor_disconnect(intf);
                return USB_STOR_TRANSPORT_ERROR;
        }
 
+       misc_reg03 = info->bbuf[0];
        if (!(misc_reg03 & 0x01)) {
                pr_info("ums_eneub6250: The driver only supports SD/MS card. "
                        "To use SM card, please build driver/staging/keucr\n");