public inbox for linux-rdma@vger.kernel.org
 help / color / mirror / Atom feed
* [bug report] IB/usnic: Add Cisco VIC low-level hardware driver
@ 2021-08-04  9:08 Dan Carpenter
  0 siblings, 0 replies; 7+ messages in thread
From: Dan Carpenter @ 2021-08-04  9:08 UTC (permalink / raw)
  To: umalhi; +Cc: linux-rdma

[ This is an ancient bug, but the bug is clear to see, but unfortunately
  it's probably less easy to fix.  - dan ]

Hello Upinder Malhi,

The patch e3cf00d0a87f: "IB/usnic: Add Cisco VIC low-level hardware
driver" from Sep 10, 2013, leads to the following static checker
warning:

	fs/kernfs/dir.c:476 kernfs_drain()
	warn: sleeping in atomic context

drivers/infiniband/hw/usnic/usnic_ib_verbs.c
   190          if (usnic_ib_share_vf) {
   191                  /* Try to find resouces on a used vf which is in pd */
   192                  dev_list = usnic_uiom_get_dev_list(pd->umem_pd);
   193                  if (IS_ERR(dev_list))
   194                          return ERR_CAST(dev_list);
   195                  for (i = 0; dev_list[i]; i++) {
   196                          dev = dev_list[i];
   197                          vf = dev_get_drvdata(dev);
   198                          spin_lock(&vf->lock);
                                ^^^^^^^^^^^^^^^^^^^^^
We're holding a spin lock.

   199                          vnic = vf->vnic;
   200                          if (!usnic_vnic_check_room(vnic, res_spec)) {
   201                                  usnic_dbg("Found used vnic %s from %s\n",
   202                                                  dev_name(&us_ibdev->ib_dev.dev),
   203                                                  pci_name(usnic_vnic_get_pdev(
   204                                                                          vnic)));
   205                                  qp_grp = usnic_ib_qp_grp_create(us_ibdev->ufdev,
                                                 ^^^^^^^^^^^^^^^^^^^^^^
The create function calls usnic_ib_sysfs_qpn_add() which does a
kobject_init_and_add().  Unfortunately kobject allocations have many
sleeps inside them so it can't be done while holding a spinlock.

Same thing for the other usnic_ib_qp_grp_create() later on in the same
function.

   206                                                                  vf, pd,
   207                                                                  res_spec,
   208                                                                  trans_spec);
   209  
   210                                  spin_unlock(&vf->lock);
   211                                  goto qp_grp_check;
   212                          }
   213                          spin_unlock(&vf->lock);
   214  
   215                  }
   216                  usnic_uiom_free_dev_list(dev_list);
   217                  dev_list = NULL;
   218          }

regards,
dan carpenter


^ permalink raw reply	[flat|nested] 7+ messages in thread
* [bug report] IB/usnic: Add Cisco VIC low-level hardware driver
@ 2021-07-05 10:23 Dan Carpenter
  2021-07-05 13:47 ` Robin Murphy
  0 siblings, 1 reply; 7+ messages in thread
From: Dan Carpenter @ 2021-07-05 10:23 UTC (permalink / raw)
  To: umalhi; +Cc: iommu, linux-rdma

[ Ancient code, but the bug seems real enough still.  -dan ]

Hello Upinder Malhi,

The patch e3cf00d0a87f: "IB/usnic: Add Cisco VIC low-level hardware
driver" from Sep 10, 2013, leads to the following static checker
warning:

	drivers/iommu/iommu.c:2482 iommu_map()
	warn: sleeping in atomic context

drivers/infiniband/hw/usnic/usnic_uiom.c
   244  static int usnic_uiom_map_sorted_intervals(struct list_head *intervals,
   245                                                  struct usnic_uiom_reg *uiomr)

This function is always called from usnic_uiom_reg_get() which is holding
spin_lock(&pd->lock); so it can't sleep.

   246  {
   247          int i, err;
   248          size_t size;
   249          struct usnic_uiom_chunk *chunk;
   250          struct usnic_uiom_interval_node *interval_node;
   251          dma_addr_t pa;
   252          dma_addr_t pa_start = 0;
   253          dma_addr_t pa_end = 0;
   254          long int va_start = -EINVAL;
   255          struct usnic_uiom_pd *pd = uiomr->pd;
   256          long int va = uiomr->va & PAGE_MASK;
   257          int flags = IOMMU_READ | IOMMU_CACHE;
   258  
   259          flags |= (uiomr->writable) ? IOMMU_WRITE : 0;
   260          chunk = list_first_entry(&uiomr->chunk_list, struct usnic_uiom_chunk,
   261                                                                          list);
   262          list_for_each_entry(interval_node, intervals, link) {
   263  iter_chunk:
   264                  for (i = 0; i < chunk->nents; i++, va += PAGE_SIZE) {
   265                          pa = sg_phys(&chunk->page_list[i]);
   266                          if ((va >> PAGE_SHIFT) < interval_node->start)
   267                                  continue;
   268  
   269                          if ((va >> PAGE_SHIFT) == interval_node->start) {
   270                                  /* First page of the interval */
   271                                  va_start = va;
   272                                  pa_start = pa;
   273                                  pa_end = pa;
   274                          }
   275  
   276                          WARN_ON(va_start == -EINVAL);
   277  
   278                          if ((pa_end + PAGE_SIZE != pa) &&
   279                                          (pa != pa_start)) {
   280                                  /* PAs are not contiguous */
   281                                  size = pa_end - pa_start + PAGE_SIZE;
   282                                  usnic_dbg("va 0x%lx pa %pa size 0x%zx flags 0x%x",
   283                                          va_start, &pa_start, size, flags);
   284                                  err = iommu_map(pd->domain, va_start, pa_start,
   285                                                          size, flags);

The iommu_map() function sleeps.

   286                                  if (err) {
   287                                          usnic_err("Failed to map va 0x%lx pa %pa size 0x%zx with err %d\n",
   288                                                  va_start, &pa_start, size, err);
   289                                          goto err_out;
   290                                  }
   291                                  va_start = va;
   292                                  pa_start = pa;
   293                                  pa_end = pa;
   294                          }
   295  
   296                          if ((va >> PAGE_SHIFT) == interval_node->last) {
   297                                  /* Last page of the interval */
   298                                  size = pa - pa_start + PAGE_SIZE;
   299                                  usnic_dbg("va 0x%lx pa %pa size 0x%zx flags 0x%x\n",
   300                                          va_start, &pa_start, size, flags);
   301                                  err = iommu_map(pd->domain, va_start, pa_start,
   302                                                  size, flags);

iommu_map() again.

   303                                  if (err) {
   304                                          usnic_err("Failed to map va 0x%lx pa %pa size 0x%zx with err %d\n",
   305                                                  va_start, &pa_start, size, err);
   306                                          goto err_out;
   307                                  }
   308                                  break;
   309                          }
   310  
   311                          if (pa != pa_start)
   312                                  pa_end += PAGE_SIZE;
   313                  }
   314  
   315                  if (i == chunk->nents) {
   316                          /*
   317                           * Hit last entry of the chunk,
   318                           * hence advance to next chunk
   319                           */
   320                          chunk = list_first_entry(&chunk->list,
   321                                                          struct usnic_uiom_chunk,
   322                                                          list);
   323                          goto iter_chunk;
   324                  }
   325          }
   326  
   327          return 0;
   328  
   329  err_out:
   330          usnic_uiom_unmap_sorted_intervals(intervals, pd);
   331          return err;
   332  }

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 7+ messages in thread
* [bug report] IB/usnic: Add Cisco VIC low-level hardware driver
@ 2017-10-12 12:57 Dan Carpenter
  0 siblings, 0 replies; 7+ messages in thread
From: Dan Carpenter @ 2017-10-12 12:57 UTC (permalink / raw)
  To: umalhi-FYB4Gu1CFyUAvxtiuMwx3w; +Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA

Hello Upinder Malhi,

The patch e3cf00d0a87f: "IB/usnic: Add Cisco VIC low-level hardware
driver" from Sep 10, 2013, leads to the following static checker
warning:

	drivers/infiniband/hw/usnic/usnic_uiom.c:366 usnic_uiom_reg_get()
	warn: overflowed symbol reused:  'size'

drivers/infiniband/hw/usnic/usnic_uiom.c
   335  struct usnic_uiom_reg *usnic_uiom_reg_get(struct usnic_uiom_pd *pd,
   336                                                  unsigned long addr, size_t size,
                                                                            ^^^^^^^^^^^
The size is comes from the user.  The call tree is:

  ib_uverbs_reg_mr() <-- does a copy_from_user()
    -> pd->device->reg_user_mr()
       -> usnic_ib_reg_mr()
          -> usnic_uiom_reg_get()

   337                                                  int writable, int dmasync)
   338  {
   339          struct usnic_uiom_reg *uiomr;
   340          unsigned long va_base, vpn_start, vpn_last;
   341          unsigned long npages;
   342          int offset, err;
   343          LIST_HEAD(sorted_diff_intervals);
   344  
   345          /*
   346           * Intel IOMMU map throws an error if a translation entry is
   347           * changed from read to write.  This module may not unmap
   348           * and then remap the entry after fixing the permission
   349           * b/c this open up a small windows where hw DMA may page fault
   350           * Hence, make all entries to be writable.
   351           */
   352          writable = 1;
   353  
   354          va_base = addr & PAGE_MASK;
   355          offset = addr & ~PAGE_MASK;
   356          npages = PAGE_ALIGN(size + offset) >> PAGE_SHIFT;
                         ^^^^^^^^^^^^^^^^^^^^^^^^^
size + offset can wrap and PAGE_ALIGN() has an addition as well.

   357          vpn_start = (addr & PAGE_MASK) >> PAGE_SHIFT;
   358          vpn_last = vpn_start + npages - 1;
   359  
   360          uiomr = kmalloc(sizeof(*uiomr), GFP_KERNEL);
   361          if (!uiomr)
   362                  return ERR_PTR(-ENOMEM);
   363  
   364          uiomr->va = va_base;
   365          uiomr->offset = offset;
   366          uiomr->length = size;
                                ^^^^
The test is trying to be a tiny bit smart by not immediately complaining
about the user controlled integer overflow but instead waiting to see if
we use "size" again.  I don't know if this code has a real bug.  I'm
casting about trying to find a heuristic which is easy enough for static
analysis but doesn't have too many false positives.

   367          uiomr->writable = writable;
   368          uiomr->pd = pd;
   369  
   370          err = usnic_uiom_get_pages(addr, size, writable, dmasync,
   371                                          &uiomr->chunk_list);
   372          if (err) {
   373                  usnic_err("Failed get_pages vpn [0x%lx,0x%lx] err %d\n",
   374                                  vpn_start, vpn_last, err);
   375                  goto out_free_uiomr;
   376          }

regards,
dan carpenter
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

end of thread, other threads:[~2021-08-04  9:08 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-08-04  9:08 [bug report] IB/usnic: Add Cisco VIC low-level hardware driver Dan Carpenter
  -- strict thread matches above, loose matches on Subject: below --
2021-07-05 10:23 Dan Carpenter
2021-07-05 13:47 ` Robin Murphy
2021-07-05 15:21   ` Jason Gunthorpe
2021-07-05 15:39     ` Robin Murphy
2021-07-05 15:45     ` Dan Carpenter
2017-10-12 12:57 Dan Carpenter

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