Hi, thanks for the patch!

On 31.08.26 08:00, Vivek Kasireddy wrote:
Since udmabuf allows users to pin pages in memory, which is a vital
resource, we need to ensure that unprivileged users cannot abuse
this feature to exhaust system memory. To address this, introduce
mlock accounting for udmabuf pages/folios. This change ensures that
the number of pages/folios pinned by udmabuf is tracked and limited
based on the user's mlock limits.

If an unprivileged user/process exceeds their mlock limit, no pages
are pinned and EPERM is returned to the user. Note that, privileged
users/processes (CAP_IPC_LOCK capable) are exempt from this limit,
allowing them to pin pages without any restriction.

Earlier, there was a 64 MB default limit on the size of udmabuf
allocations, but it was removed in commit 44e9eb5a7621
("dma-buf/udmabuf: Disable the size limit by default") which left
open the possibility that unpriviledged users could pin unbounded
amount of memory. This change makes the limit dynamic, by invoking
user_shm_lock() to check the mlock limit for unprivileged users.

I think this description is somewhat misleading: before commit 44e9eb5a7621 the same was already possible - it just needed multiple buffers/allocations. That's why that patch was accepted in the first place, without first landing a patch like this one (adding mlock accounting). I.e. the described problem is not new and just became easier to trigger.

Best regards

Robert


Signed-off-by: Vivek Kasireddy <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Cc: "Christian König" <[email protected]>
Cc: Robert Mader <[email protected]>
Cc: Xaver Hugl <[email protected]>
Fixes: 44e9eb5a7621 ("dma-buf/udmabuf: Disable the size limit by default")
---
  drivers/dma-buf/udmabuf.c | 16 +++++++++++++---
  1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c
index 7c4339130eff..e78947f01656 100644
--- a/drivers/dma-buf/udmabuf.c
+++ b/drivers/dma-buf/udmabuf.c
@@ -203,9 +203,10 @@ static __always_inline int init_udmabuf(struct udmabuf 
*ubuf, pgoff_t pgcnt)
        return 0;
  }
-static __always_inline void deinit_udmabuf(struct udmabuf *ubuf)
+static __always_inline void deinit_udmabuf(struct udmabuf *ubuf, pgoff_t pgcnt)
  {
        unpin_all_folios(ubuf);
+       user_shm_unlock(pgcnt << PAGE_SHIFT, current_ucounts());
        kvfree(ubuf->pages);
  }
@@ -217,7 +218,7 @@ static void release_udmabuf(struct dma_buf *buf)
        if (ubuf->sg)
                put_sg_table(dev, ubuf->sg, ubuf->sg_dir);
- deinit_udmabuf(ubuf);
+       deinit_udmabuf(ubuf, ubuf->pagecount);
        kfree(ubuf);
  }
@@ -385,6 +386,15 @@ static long udmabuf_create(struct miscdevice *device,
        if (!pgcnt)
                goto err_noinit;
+ if (!user_shm_lock(pgcnt << PAGE_SHIFT, current_ucounts())) {
+               pr_warn_once("%s: User not permitted to pin more than %lu KB "
+                            "of memory, either increase ulimits -l, or "
+                            "obtain CAP_IPC_LOCK capability\n", current->comm,
+                            rlimit(RLIMIT_MEMLOCK) >> 10);
+               ret = -EPERM;
+               goto err_noinit;
+       }
+
        ret = init_udmabuf(ubuf, pgcnt);
        if (ret)
                goto err;
@@ -441,7 +451,7 @@ static long udmabuf_create(struct miscdevice *device,
        return ret;
err:
-       deinit_udmabuf(ubuf);
+       deinit_udmabuf(ubuf, pgcnt);
  err_noinit:
        kfree(ubuf);
        kvfree(folios);

Reply via email to