linux-rdma.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [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

* [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

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

On 2021-07-05 11:23, Dan Carpenter wrote:
> [ 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.

FWIW back in those days it wasn't really well defined whether 
iommu_map() was callable from non-sleeping contexts (the arch/arm DMA 
API code relied on it, for instance). It was only formalised 2 years ago 
by 781ca2de89ba ("iommu: Add gfp parameter to iommu_ops::map") which 
introduced the might_sleep() check that's firing there. I guess these 
calls want to be updated to iommu_map_atomic() now.

Robin.

>     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
> _______________________________________________
> iommu mailing list
> iommu@lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/iommu
> 

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

* Re: [bug report] IB/usnic: Add Cisco VIC low-level hardware driver
  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
  0 siblings, 2 replies; 7+ messages in thread
From: Jason Gunthorpe @ 2021-07-05 15:21 UTC (permalink / raw)
  To: Robin Murphy, Christian Benvenuti, Nelson Escobar
  Cc: Dan Carpenter, umalhi, linux-rdma, iommu

On Mon, Jul 05, 2021 at 02:47:36PM +0100, Robin Murphy wrote:
> On 2021-07-05 11:23, Dan Carpenter wrote:
> > [ 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.
> 
> FWIW back in those days it wasn't really well defined whether iommu_map()
> was callable from non-sleeping contexts (the arch/arm DMA API code relied on
> it, for instance). It was only formalised 2 years ago by 781ca2de89ba
> ("iommu: Add gfp parameter to iommu_ops::map") which introduced the
> might_sleep() check that's firing there. I guess these calls want to be
> updated to iommu_map_atomic() now.

Does this mean this driver doesn't work at all upstream? I would be
quite interested to delete it.

Jason

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

* Re: [bug report] IB/usnic: Add Cisco VIC low-level hardware driver
  2021-07-05 15:21   ` Jason Gunthorpe
@ 2021-07-05 15:39     ` Robin Murphy
  2021-07-05 15:45     ` Dan Carpenter
  1 sibling, 0 replies; 7+ messages in thread
From: Robin Murphy @ 2021-07-05 15:39 UTC (permalink / raw)
  To: Jason Gunthorpe, Christian Benvenuti, Nelson Escobar
  Cc: Dan Carpenter, umalhi, linux-rdma, iommu

On 2021-07-05 16:21, Jason Gunthorpe wrote:
> On Mon, Jul 05, 2021 at 02:47:36PM +0100, Robin Murphy wrote:
>> On 2021-07-05 11:23, Dan Carpenter wrote:
>>> [ 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.
>>
>> FWIW back in those days it wasn't really well defined whether iommu_map()
>> was callable from non-sleeping contexts (the arch/arm DMA API code relied on
>> it, for instance). It was only formalised 2 years ago by 781ca2de89ba
>> ("iommu: Add gfp parameter to iommu_ops::map") which introduced the
>> might_sleep() check that's firing there. I guess these calls want to be
>> updated to iommu_map_atomic() now.
> 
> Does this mean this driver doesn't work at all upstream? I would be
> quite interested to delete it.

I think the only time it's actually in trouble is on AMD hardware if one 
of those iommu_map() calls has to allocate a new pagetable page and that 
allocation has to go down whichever reclaim path actually sleeps. 
Historically all the other IOMMU drivers it might have come into contact 
with already used GFP_ATOMIC for their internal allocations anyway (AMD 
was the only one using a mutex instead of a spinlock internally), and 
some like intel-iommu still haven't relaxed that even now.

Robin.

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

* Re: [bug report] IB/usnic: Add Cisco VIC low-level hardware driver
  2021-07-05 15:21   ` Jason Gunthorpe
  2021-07-05 15:39     ` Robin Murphy
@ 2021-07-05 15:45     ` Dan Carpenter
  1 sibling, 0 replies; 7+ messages in thread
From: Dan Carpenter @ 2021-07-05 15:45 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Robin Murphy, Christian Benvenuti, Nelson Escobar, umalhi,
	linux-rdma, iommu

On Mon, Jul 05, 2021 at 12:21:38PM -0300, Jason Gunthorpe wrote:
> On Mon, Jul 05, 2021 at 02:47:36PM +0100, Robin Murphy wrote:
> > On 2021-07-05 11:23, Dan Carpenter wrote:
> > > [ 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.
> > 
> > FWIW back in those days it wasn't really well defined whether iommu_map()
> > was callable from non-sleeping contexts (the arch/arm DMA API code relied on
> > it, for instance). It was only formalised 2 years ago by 781ca2de89ba
> > ("iommu: Add gfp parameter to iommu_ops::map") which introduced the
> > might_sleep() check that's firing there. I guess these calls want to be
> > updated to iommu_map_atomic() now.
> 
> Does this mean this driver doesn't work at all upstream? I would be
> quite interested to delete it.

It just means it hasn't been used with CONFIG_DEBUG_ATOMIC_SLEEP enabled
within the past two years.

regards,
dan carpenter


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

* [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

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-07-05 10:23 [bug report] IB/usnic: Add Cisco VIC low-level hardware driver 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
  -- strict thread matches above, loose matches on Subject: below --
2021-08-04  9:08 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;
as well as URLs for NNTP newsgroup(s).