Re: [PATCH 3/3] selinux: require EXECMEM or PTRACE for FOLL_FORCE introspection
Jann Horn <[email protected]>
| Newsgroups | org.kvack.linux-mm,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-security-module,org.kernel.vger.selinux |
|---|---|
| Message-ID | <CAG48ez05-BOK_SZCKimPuiP_WRB1dFrzvcL2bHmOR-bChEu+Cw@mail.gmail.com> |
On Fri, Aug 21, 2026 at 8:56 PM Lorenzo Stoakes (ARM) <[email protected]> wrote: > On Tue, Aug 18, 2026 at 09:51:07PM +0200, Jann Horn wrote: > > On systems configured with PROC_MEM_FORCE_ALWAYS, ensure that a process can > > only create anonymous executable memory via /proc/self/mem if it has one > > of: > > > > - EXECMEM (like for other methods of creating anonymous executable pages) > > - PTRACE (like when using /proc/$pid/mem of another process) > > > > This closes a hole in EXECMEM enforcement that Project Zero has used in a > > remote Android exploit chain: > > It was possible to use a memory corruption bug in a service without EXECMEM > > permission to overwrite executable code via /proc/self/mem, which made it > > possible to load and run shellcode with a kernel exploit. > > > > Signed-off-by: Jann Horn <[email protected]> > > --- > > security/selinux/hooks.c | 27 +++++++++++++++++++++++++++ > > 1 file changed, 27 insertions(+) > > > > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c > > index 18dd28b2bb13..905137c47321 100644 > > --- a/security/selinux/hooks.c > > +++ b/security/selinux/hooks.c > > @@ -2157,6 +2157,32 @@ static int selinux_ptrace_traceme(struct task_struct *parent) > > SECCLASS_PROCESS, PROCESS__PTRACE, NULL); > > } > > > > +/* > > + * Decide whether it should be possible to read non-readable VMAs and write > > + * non-writable VMAs via /proc/self/mem. > > + * This only applies to systems configured with PROC_MEM_FORCE_ALWAYS, and only > > + * triggers on accesses that are not visible to selinux_ptrace_access_check(). > > It might be worth mentioning may_access_mm() here, and obviously propagate the > suggested name change introspection -> opened_by_owner or fd_from_order maybe > even? Ack, makes sense to mention may_access_mm() here. Ack, I'll rename this to selinux_mem_foll_force_opened_by_owner(). > > + * > > + * This allows a process to overwrite read-only code in its own address space. > > + * > > + * Creating an audit record on denial doesn't make sense here, since we can't > > + * tell whether FOLL_FORCE matters for the accessed VMAs. > > + */ > > +static int selinux_introspect_mem_foll_force(const struct cred *subject) > > +{ > > + struct av_decision avd; > > + int rc; > > + u32 sid = cred_sid(subject); > > + > > + /* Allow if the process is generally allowed to have executable anonymous memory. */ > > + rc = avc_has_perm_noaudit(sid, sid, SECCLASS_PROCESS, PROCESS__EXECMEM, 0, &avd); > > But does it make sense for the shared-by-fd case? In that case you're now > updating execmem for another process's memory right? Since the existing check for PROCESS__PTRACE happens on open(), I figured it would make sense to also check against the open()-time credentials here. (I will be changing this to check just for PROCESS__PTRACE based on Stephen's feedback.) > > + > > + /* Also allow if selinux_ptrace_access_check() would allow it. */ > > + if (rc) > > + rc = avc_has_perm_noaudit(sid, sid, SECCLASS_PROCESS, PROCESS__PTRACE, 0, &avd); > > + return rc; > > +}