On 9/22/26 15:40, Robert Mader wrote:
> Hi,
> 
> On 22.09.26 09:33, Christian König wrote:
>> On 9/22/26 07:19, Kasireddy, Vivek wrote:
>>> Hi Christian,
>>>
>>>> Subject: Re: [PATCH v1 2/2] udmabuf: Add mlock accounting for
>>>> udmabuf pages/folios
>>>>
>>>> On 8/31/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.
>>>> That makes no sense at all and would create a massive problems.
>>>>
>>>> The mlock limit is per process, but udmabuf is represented by a file
>>>> descriptor which can move between processes.
>>>>
>>>> So this here can be trivially abused to account the allocation to one
>>>> process while accounting the free to another process and overflowing
>>>> the mlock housekeeping.
>>> The goal is to have the mlock accounting be tied to the exporters since they
>>> are the ones that pin the pages/folios. As Sashiko identified, this patch 
>>> doesn't
>>> quite do that but once fixed, both alloc and free accounting would be 
>>> attributed
>>> to the exporter. Would this idea not work?
>> Most likely not, no.
>>
>> First of all this is trivially circumvent-able, you just need to create a 
>> child process which allocates and exports the memory and then gives the fd 
>> back to the parent and dies.
>>
>> The result would be that you have accounted to the mlock limit of the child 
>> process (which is now dead) and then a dangling reference to the cred 
>> structure of a dead process. Both are most likely no-gos for this.
>>
>> Then the second problem is that you often have processes which allocates the 
>> memory on behalves of another process (display servers for example do that).
>>
>> The fundamental issue is that Linux doesn't have a way to track file 
>> descriptors as they move from process to process and so if your file 
>> descriptor represents more than just a standard file on a file system you 
>> run into tons of trouble with resource management.
>>
>> Regards,
>> Christian.
> 
> I'd like to quickly chime in on what we IMHO would optimally want (from a 
> userspace perspective). Some context:
> 
> 1. Unprivileged users by default don't have access to /dev/udmabuf

If we have the normal DRM render node group that would be ok for me, but could 
be that others object.
> 2. Since https://github.com/systemd/systemd/pull/33738 systemd grants uaccess 
> to graphical users - i.e. if I'm not mistaken only the users currently owning 
> drm master should be able to use udmabuf (or something similar)

No, that is not correct. If I'm not completely mistaken everybody can access 
/dev/udmabuf at the moment.

> 3. When owning drm master one can probably already DDoS the system in various 
> ways - so probably not really worth to try to hard to defend against.

Well without cgroups even regular users can trivially cause a local deny of 
service on Linux.

Just try the following code:

char buffer[1024];
int fd;

fd = memfd_create("Test", 0);
while (1)
        write(fd, buffer, 1024);

The OOM killer will kill every process in the system except for the offending 
one. Background is that the OOM killer can't see resources locked up in file 
descriptors.

> 4. An exception here would be sandboxed apps - e.g. flatpaks. Such apps get 
> udabuf access if they also have dri device access 
> (https://github.com/flatpak/flatpak/pull/6158). Preventing these apps from 
> pinning unlimited amounts of memory would be great - however I guess this 
> would require mlock accounting on the level of cgroups. Is that realistic to 
> have by any means?

I don't think that this will work. Pinning memory is as far as I know not seen 
as something problematic.

Regards,
Christian.

> 
> Best regards,
> 
> Robert
> 
>>> Thanks,
>>> Vivek
>>>
>>>> What could potentially work is to grab a reference to the cred structure
>>>> of the allocating task, but that is also not the nicest thing to do.
>>>>
>>>> Regards,
>>>> Christian.
>>>>
>>>>> 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