On Tue, Aug 25, 2026 at 12:50:57PM +0200, David Hildenbrand (Arm) wrote:
> On 8/22/26 21:14, Lorenzo Stoakes (ARM) wrote:
> > secretmem has a relatively laissez-faire attitude to accounting the folios
> > it allocates.
> >
> > The intention is that the memory is treated as if it were mlock()'d and
> > thus is limited by the RLIMIT_MEMLOCK limit if the CAP_IPC_LOCK capability
> > is not in place (which broadly allows unlimited ranges of mlock()'d
> > memory).
> >
> > The lifecycle for memfd accounting against this limit is - account on map,
> > unaccount on unmap but the lifecycle of memfd folios is allocate on fault,
> > deallocate on inode eviction.
> >
> > This mismatch is problematic because the folios are unevictable and remain
> > so until the inode is evicted (set using mapping_set_unevictable()).
> >
> > This is problematic as it eliminates usual mlock() semantics - mapping
> > folios then unmapping them does not clear their unevictable state, since it
> > depends on AS_UNEVICTABLE, not PG_mlocked.
> >
> > A user can therefore easily work around the RLIMIT_MEMLOCK limit - simply
> > map then unmap and VmLck no longer counts the secretmem range (or more
> > involved - fork which also achieves the same thing).
> >
> > Worse - they are not accounted in the process's RSS even if mapped again,
> > meaning the OOM killer won't know to kill the process.
> >
> > A user without the CAP_IPC_LOCK capability can therefore repeatedly
> > map/unmap (or map/fork) and consume all available system memory with
> > unevictable folios and cause system instability.
> >
> > A secretmem fd can be passed between processes and over fork so a
> > per-process limit simply does not make sense.
> >
> > So follow the precedent set by io_uring, perf, skbuff, iommufd and xdp -
> > track the number of locked pages in user_struct->locked_vm.
> >
> > Since the scope tracked is actually inode lifetime, the RLIMIT_MEMLOCK
> > applies per-user not per-process. Also given the change in scope it doesn't
> > make sense to bypass for users with CAP_IPC_LOCK, so remove it.
> >
> > There is simply no reason to carry on marking the mapping as mlock()'d
> > since it's misleading and the lifecycle is now correctly handled, so remove
> > this too.
> >
> > Additionally, fix the selftest which checks the limit as this now must
> > assert SIGBUS on limit violation on fault-in.
> >
> > __secretmem_account_pages() is more or less a duplicate of the code that
> > io_uring etc. use, but since this is a bug fix that needs backporting,
> > defer any de-duplication efforts to a follow-up.
> >
> > Reported-by: Daehyeon Ko <[email protected]>
> > Closes: 
> > https://lore.kernel.org/linux-mm/[email protected]/
> > Fixes: 1507f51255c9 ("mm: introduce memfd_secret system call to create 
> > "secret" memory areas")
> > Cc: [email protected]
> > Signed-off-by: Lorenzo Stoakes (ARM) <[email protected]>
>
> Can we split off the selftest changes? This stable patch is already pretty 
> big.

Yeah I can do! I seem to recall people wanting tests backported too hence
the change.

>
> I'd assume the changes to the selftests are not required just to get if fixed,
> because the changes should not be breaking existing user space (and 
> cosnequently
> existing selftests).

Yup confirmed locally that the changes don't break the tests.

>
> [...]
>
> > v1:
> > https://patch.msgid.link/[email protected]
> >
> > To: Andrew Morton <[email protected]>
> > To: Mike Rapoport <[email protected]>
> > To: David Hildenbrand <[email protected]>
> > To: "Liam R. Howlett" <[email protected]>
> > To: Vlastimil Babka <[email protected]>
> > To: Suren Baghdasaryan <[email protected]>
> > To: Michal Hocko <[email protected]>
> > To: Shuah Khan <[email protected]>
> > To: Alexei Starovoitov <[email protected]>
> > To: Daniel Borkmann <[email protected]>
> > To: "David S. Miller" <[email protected]>
> > To: Jakub Kicinski <[email protected]>
> > To: Jesper Dangaard Brouer <[email protected]>
> > To: John Fastabend <[email protected]>
> > To: Stanislav Fomichev <[email protected]>
> > To: James Bottomley <[email protected]>
> > To: Hagen Paul Pfeifer <[email protected]>
> > Cc: [email protected]
> > Cc: [email protected]
> > Cc: [email protected]
> > Cc: [email protected]
> > Cc: [email protected]
> > Cc: [email protected]
> > ---
>
> [...]
>
> > +
> > +static bool secretmem_account_folio(struct secretmem_inode_state *state,
> > +           const struct folio *folio)
> > +{
> > +   unsigned long nr_pages;
>
> Nit:
>
> const unsinged long nr_pages = folio_nr_pages(folio);

Ack

>
> > +
> > +   nr_pages = folio_nr_pages(folio);
> > +   if (!__secretmem_account_pages(state->user, nr_pages))
> > +           return false;
> > +
> > +   atomic_long_add(nr_pages, &state->nr_pages_accounted);
> > +   return true;
> > +}
> > +
> > +static void __secretmem_unaccount_pages(struct secretmem_inode_state 
> > *state,
> > +           unsigned long nr_pages)
> > +{
> > +   atomic_long_sub(nr_pages, &state->user->locked_vm);
> > +   atomic_long_sub(nr_pages, &state->nr_pages_accounted);
> > +}
> > +
> > +static void secretmem_unaccount_folio(struct secretmem_inode_state *state,
> > +           struct folio *folio)
> > +{
> > +   __secretmem_unaccount_pages(state, folio_nr_pages(folio));
> > +}
> > +
> > +static void secretmem_unaccount_all_folios(struct secretmem_inode_state 
> > *state)
> > +{
> > +   unsigned long nr_pages_accounted;
> > +
> > +   nr_pages_accounted = atomic_long_read(&state->nr_pages_accounted);
> > +   __secretmem_unaccount_pages(state, nr_pages_accounted);
> > +}
> > +
> >  static vm_fault_t secretmem_fault(struct vm_fault *vmf)
> >  {
> >     struct address_space *mapping = vmf->vma->vm_file->f_mapping;
> >     struct inode *inode = file_inode(vmf->vma->vm_file);
> > +   struct secretmem_inode_state *state = inode->i_private;
> >     pgoff_t offset = vmf->pgoff;
> >     gfp_t gfp = vmf->gfp_mask;
> >     unsigned long addr;
> > @@ -72,8 +134,15 @@ static vm_fault_t secretmem_fault(struct vm_fault *vmf)
> >                     goto out;
> >             }
> >
> > +           if (!secretmem_account_folio(state, folio)) {
> > +                   folio_put(folio);
> > +                   ret = VM_FAULT_SIGBUS;
> > +                   goto out;
> > +           }
> > +
> Okay, that works because secretmem does not support any form of truncate, in
> particular, no FALLOC_FL_PUNCH_HOLE.

Yeah exactly. I think I covered that off somewhere in my essay-length
commit msg but if not but yeah that is a thing that I noted.

>
> Overall, the idea sounds good to me. Nothing jumped at me.

Thanks! So in a way you kinda... Ack it right? :P If only there were a tag
for that 🤔 ;)

>
> --
> Cheers,
>
> David

--
Cheers, Lorenzo

Reply via email to