[bug report] scsi: snic: Fix possible memory leak if device_add() fails

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello Zhu Wang,

The patch 41320b18a0e0: "scsi: snic: Fix possible memory leak if
device_add() fails" from Aug 1, 2023 (linux-next), leads to the
following Smatch static checker warning:

	drivers/scsi/snic/snic_disc.c:311 snic_tgt_create()
	warn: freeing device managed memory (UAF): 'tgt'

drivers/scsi/snic/snic_disc.c
    234 static struct snic_tgt *
    235 snic_tgt_create(struct snic *snic, struct snic_tgt_id *tgtid)
    236 {
    237         struct snic_tgt *tgt = NULL;
    238         unsigned long flags;
    239         int ret;
    240 
    241         tgt = snic_tgt_lookup(snic, tgtid);
    242         if (tgt) {
    243                 /* update the information if required */
    244                 return tgt;
    245         }
    246 
    247         tgt = kzalloc(sizeof(*tgt), GFP_KERNEL);
    248         if (!tgt) {
    249                 SNIC_HOST_ERR(snic->shost, "Failure to allocate snic_tgt.\n");
    250                 ret = -ENOMEM;
    251 
    252                 return tgt;
    253         }
    254 
    255         INIT_LIST_HEAD(&tgt->list);
    256         tgt->id = le32_to_cpu(tgtid->tgt_id);
    257         tgt->channel = 0;
    258 
    259         SNIC_BUG_ON(le16_to_cpu(tgtid->tgt_type) > SNIC_TGT_SAN);
    260         tgt->tdata.typ = le16_to_cpu(tgtid->tgt_type);
    261 
    262         /*
    263          * Plugging into SML Device Tree
    264          */
    265         tgt->tdata.disc_id = 0;
    266         tgt->state = SNIC_TGT_STAT_INIT;
    267         device_initialize(&tgt->dev);
    268         tgt->dev.parent = get_device(&snic->shost->shost_gendev);
    269         tgt->dev.release = snic_tgt_dev_release;
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is a similar bug to the one I reported earlier.

    270         INIT_WORK(&tgt->scan_work, snic_scsi_scan_tgt);
    271         INIT_WORK(&tgt->del_work, snic_tgt_del);
    272         switch (tgt->tdata.typ) {
    273         case SNIC_TGT_DAS:
    274                 dev_set_name(&tgt->dev, "snic_das_tgt:%d:%d-%d",
    275                              snic->shost->host_no, tgt->channel, tgt->id);
    276                 break;
    277 
    278         case SNIC_TGT_SAN:
    279                 dev_set_name(&tgt->dev, "snic_san_tgt:%d:%d-%d",
    280                              snic->shost->host_no, tgt->channel, tgt->id);
    281                 break;
    282 
    283         default:
    284                 SNIC_HOST_INFO(snic->shost, "Target type Unknown Detected.\n");
    285                 dev_set_name(&tgt->dev, "snic_das_tgt:%d:%d-%d",
    286                              snic->shost->host_no, tgt->channel, tgt->id);
    287                 break;
    288         }
    289 
    290         spin_lock_irqsave(snic->shost->host_lock, flags);
    291         list_add_tail(&tgt->list, &snic->disc.tgt_list);
    292         tgt->scsi_tgt_id = snic->disc.nxt_tgt_id++;
    293         tgt->state = SNIC_TGT_STAT_ONLINE;
    294         spin_unlock_irqrestore(snic->shost->host_lock, flags);
    295 
    296         SNIC_HOST_INFO(snic->shost,
    297                        "Tgt %d, type = %s detected. Adding..\n",
    298                        tgt->id, snic_tgt_type_to_str(tgt->tdata.typ));
    299 
    300         ret = device_add(&tgt->dev);
    301         if (ret) {
    302                 SNIC_HOST_ERR(snic->shost,
    303                               "Snic Tgt: device_add, with err = %d\n",
    304                               ret);
    305 
    306                 put_device(&tgt->dev);
                        ^^^^^^^^^^^^^^^^^^^^

The put_device() will free tgt.

    307                 put_device(&snic->shost->shost_gendev);
    308                 spin_lock_irqsave(snic->shost->host_lock, flags);
    309                 list_del(&tgt->list);

Use after free

    310                 spin_unlock_irqrestore(snic->shost->host_lock, flags);
--> 311                 kfree(tgt);

Double free.

    312                 tgt = NULL;
    313 
    314                 return tgt;
    315         }
    316 
    317         SNIC_HOST_INFO(snic->shost, "Scanning %s.\n", dev_name(&tgt->dev));
    318 
    319         scsi_queue_work(snic->shost, &tgt->scan_work);
    320 
    321         return tgt;
    322 } /* end of snic_tgt_create */

regards,
dan carpenter



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]

  Powered by Linux