* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-18 19:51 ` [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS) Jann Horn
@ 2026-08-18 20:00 ` sashiko-bot
2026-08-20 17:22 ` David Hildenbrand (Arm)
` (3 subsequent siblings)
4 siblings, 0 replies; 37+ messages in thread
From: sashiko-bot @ 2026-08-18 20:00 UTC (permalink / raw)
Cc: selinux
> If the system is running with PROC_MEM_FORCE_ALWAYS, LSMs currently have no
> good opportunity to block a process from overwriting read-only code in its
> own address space through FOLL_FORCE writes via /proc/self/mem.
> The security_ptrace_access_check() LSM hook is bypassed when a process
> opens /proc/self/mem because this is considered "introspection".
>
> This causes a hole in SELinux EXECMEM enforcement, which tries to ensure
> that a process cannot create executable anonymous pages.
>
> PROC_MEM_FORCE_PTRACE prevents that and ensures that such FOLL_FORCE
> accesses are only possible when the LSM allows ptrace() attachment; but it
> is unclear how quickly PROC_MEM_FORCE_PTRACE can be deployed in
> environments running lots of third-party code, such as Android.
>
> So, introduce a new LSM hook that can forbid FOLL_FORCE specifically for
> such "introspective" accesses.
>
> Signed-off-by: Jann Horn <jannh@google.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260818-selinux-pokemem-v1-0-90cd2357ee05@google.com?part=2
^ permalink raw reply [flat|nested] 37+ messages in thread* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-18 19:51 ` [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS) Jann Horn
2026-08-18 20:00 ` sashiko-bot
@ 2026-08-20 17:22 ` David Hildenbrand (Arm)
2026-08-20 18:44 ` Jann Horn
2026-08-21 19:00 ` Lorenzo Stoakes (ARM)
` (2 subsequent siblings)
4 siblings, 1 reply; 37+ messages in thread
From: David Hildenbrand (Arm) @ 2026-08-20 17:22 UTC (permalink / raw)
To: Jann Horn, Paul Moore, James Morris, Serge E. Hallyn,
Stephen Smalley, Jeff Xu, Thiébaud Weksteen
Cc: Alexander Viro, Christian Brauner, Jan Kara, linux-fsdevel,
linux-security-module, Ondrej Mosnacek, selinux, Andrew Morton,
Liam R. Howlett, Lorenzo Stoakes, Vlastimil Babka, Pedro Falcato,
linux-mm
On 8/18/26 21:51, Jann Horn wrote:
> If the system is running with PROC_MEM_FORCE_ALWAYS, LSMs currently have no
> good opportunity to block a process from overwriting read-only code in its
> own address space through FOLL_FORCE writes via /proc/self/mem.
> The security_ptrace_access_check() LSM hook is bypassed when a process
> opens /proc/self/mem because this is considered "introspection".
>
> This causes a hole in SELinux EXECMEM enforcement, which tries to ensure
> that a process cannot create executable anonymous pages.
>
> PROC_MEM_FORCE_PTRACE prevents that and ensures that such FOLL_FORCE
> accesses are only possible when the LSM allows ptrace() attachment; but it
> is unclear how quickly PROC_MEM_FORCE_PTRACE can be deployed in
> environments running lots of third-party code, such as Android.
>
> So, introduce a new LSM hook that can forbid FOLL_FORCE specifically for
> such "introspective" accesses.
>
> Signed-off-by: Jann Horn <jannh@google.com>
> ---
> fs/proc/base.c | 6 ++++++
> include/linux/lsm_hook_defs.h | 1 +
> include/linux/security.h | 6 ++++++
> security/security.c | 15 +++++++++++++++
> 4 files changed, 28 insertions(+)
>
> diff --git a/fs/proc/base.c b/fs/proc/base.c
> index bec6197329dc..3dfaef49bb70 100644
> --- a/fs/proc/base.c
> +++ b/fs/proc/base.c
> @@ -851,6 +851,8 @@ static int __mem_open(struct inode *inode, struct file *file, unsigned int mode)
> /* private_data for proc_mem_operations */
> struct mem_private {
> struct mm_struct *mm;
> + /* Was the ptrace access check bypassed due to introspection? */
> + bool introspection;
> };
>
> static int mem_open(struct inode *inode, struct file *file)
> @@ -864,12 +866,14 @@ static int mem_open(struct inode *inode, struct file *file)
> priv->mm = proc_mem_open(inode, PTRACE_MODE_ATTACH);
> if (IS_ERR_OR_NULL(priv->mm))
> return priv->mm ? PTR_ERR(priv->mm) : -ESRCH;
> + priv->introspection = priv->mm == current->mm;
Is the feat that the fd could be passed to someone else that would then not be
detected as introspection?
I'm just wondering why we cannot perform this check in proc_mem_foll_force() and
avoid rememebring "introspection".
--
Cheers,
David
^ permalink raw reply [flat|nested] 37+ messages in thread* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-20 17:22 ` David Hildenbrand (Arm)
@ 2026-08-20 18:44 ` Jann Horn
2026-08-21 14:18 ` David Hildenbrand (Arm)
0 siblings, 1 reply; 37+ messages in thread
From: Jann Horn @ 2026-08-20 18:44 UTC (permalink / raw)
To: David Hildenbrand (Arm)
Cc: Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
Jeff Xu, Thiébaud Weksteen, Alexander Viro,
Christian Brauner, Jan Kara, linux-fsdevel, linux-security-module,
Ondrej Mosnacek, selinux, Andrew Morton, Liam R. Howlett,
Lorenzo Stoakes, Vlastimil Babka, Pedro Falcato, linux-mm
On Thu, Aug 20, 2026 at 7:22 PM David Hildenbrand (Arm)
<david@kernel.org> wrote:
> On 8/18/26 21:51, Jann Horn wrote:
> > If the system is running with PROC_MEM_FORCE_ALWAYS, LSMs currently have no
> > good opportunity to block a process from overwriting read-only code in its
> > own address space through FOLL_FORCE writes via /proc/self/mem.
> > The security_ptrace_access_check() LSM hook is bypassed when a process
> > opens /proc/self/mem because this is considered "introspection".
> >
> > This causes a hole in SELinux EXECMEM enforcement, which tries to ensure
> > that a process cannot create executable anonymous pages.
> >
> > PROC_MEM_FORCE_PTRACE prevents that and ensures that such FOLL_FORCE
> > accesses are only possible when the LSM allows ptrace() attachment; but it
> > is unclear how quickly PROC_MEM_FORCE_PTRACE can be deployed in
> > environments running lots of third-party code, such as Android.
> >
> > So, introduce a new LSM hook that can forbid FOLL_FORCE specifically for
> > such "introspective" accesses.
> >
> > Signed-off-by: Jann Horn <jannh@google.com>
> > ---
> > fs/proc/base.c | 6 ++++++
> > include/linux/lsm_hook_defs.h | 1 +
> > include/linux/security.h | 6 ++++++
> > security/security.c | 15 +++++++++++++++
> > 4 files changed, 28 insertions(+)
> >
> > diff --git a/fs/proc/base.c b/fs/proc/base.c
> > index bec6197329dc..3dfaef49bb70 100644
> > --- a/fs/proc/base.c
> > +++ b/fs/proc/base.c
> > @@ -851,6 +851,8 @@ static int __mem_open(struct inode *inode, struct file *file, unsigned int mode)
> > /* private_data for proc_mem_operations */
> > struct mem_private {
> > struct mm_struct *mm;
> > + /* Was the ptrace access check bypassed due to introspection? */
> > + bool introspection;
> > };
> >
> > static int mem_open(struct inode *inode, struct file *file)
> > @@ -864,12 +866,14 @@ static int mem_open(struct inode *inode, struct file *file)
> > priv->mm = proc_mem_open(inode, PTRACE_MODE_ATTACH);
> > if (IS_ERR_OR_NULL(priv->mm))
> > return priv->mm ? PTR_ERR(priv->mm) : -ESRCH;
> > + priv->introspection = priv->mm == current->mm;
>
> Is the feat that the fd could be passed to someone else that would then not be
> detected as introspection?
Yes, exactly, that's the primary reason why I did it this way.
^ permalink raw reply [flat|nested] 37+ messages in thread* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-20 18:44 ` Jann Horn
@ 2026-08-21 14:18 ` David Hildenbrand (Arm)
2026-08-21 14:48 ` Jann Horn
0 siblings, 1 reply; 37+ messages in thread
From: David Hildenbrand (Arm) @ 2026-08-21 14:18 UTC (permalink / raw)
To: Jann Horn
Cc: Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
Jeff Xu, Thiébaud Weksteen, Alexander Viro,
Christian Brauner, Jan Kara, linux-fsdevel, linux-security-module,
Ondrej Mosnacek, selinux, Andrew Morton, Liam R. Howlett,
Lorenzo Stoakes, Vlastimil Babka, Pedro Falcato, linux-mm
On 8/20/26 20:44, Jann Horn wrote:
> On Thu, Aug 20, 2026 at 7:22 PM David Hildenbrand (Arm)
> <david@kernel.org> wrote:
>> On 8/18/26 21:51, Jann Horn wrote:
>>> If the system is running with PROC_MEM_FORCE_ALWAYS, LSMs currently have no
>>> good opportunity to block a process from overwriting read-only code in its
>>> own address space through FOLL_FORCE writes via /proc/self/mem.
>>> The security_ptrace_access_check() LSM hook is bypassed when a process
>>> opens /proc/self/mem because this is considered "introspection".
>>>
>>> This causes a hole in SELinux EXECMEM enforcement, which tries to ensure
>>> that a process cannot create executable anonymous pages.
>>>
>>> PROC_MEM_FORCE_PTRACE prevents that and ensures that such FOLL_FORCE
>>> accesses are only possible when the LSM allows ptrace() attachment; but it
>>> is unclear how quickly PROC_MEM_FORCE_PTRACE can be deployed in
>>> environments running lots of third-party code, such as Android.
>>>
>>> So, introduce a new LSM hook that can forbid FOLL_FORCE specifically for
>>> such "introspective" accesses.
>>>
>>> Signed-off-by: Jann Horn <jannh@google.com>
>>> ---
>>> fs/proc/base.c | 6 ++++++
>>> include/linux/lsm_hook_defs.h | 1 +
>>> include/linux/security.h | 6 ++++++
>>> security/security.c | 15 +++++++++++++++
>>> 4 files changed, 28 insertions(+)
>>>
>>> diff --git a/fs/proc/base.c b/fs/proc/base.c
>>> index bec6197329dc..3dfaef49bb70 100644
>>> --- a/fs/proc/base.c
>>> +++ b/fs/proc/base.c
>>> @@ -851,6 +851,8 @@ static int __mem_open(struct inode *inode, struct file *file, unsigned int mode)
>>> /* private_data for proc_mem_operations */
>>> struct mem_private {
>>> struct mm_struct *mm;
>>> + /* Was the ptrace access check bypassed due to introspection? */
>>> + bool introspection;
>>> };
>>>
>>> static int mem_open(struct inode *inode, struct file *file)
>>> @@ -864,12 +866,14 @@ static int mem_open(struct inode *inode, struct file *file)
>>> priv->mm = proc_mem_open(inode, PTRACE_MODE_ATTACH);
>>> if (IS_ERR_OR_NULL(priv->mm))
>>> return priv->mm ? PTR_ERR(priv->mm) : -ESRCH;
>>> + priv->introspection = priv->mm == current->mm;
>>
>> Is the feat that the fd could be passed to someone else that would then not be
>> detected as introspection?
>
> Yes, exactly, that's the primary reason why I did it this way.
Okay, would "opened_by_owner" or something like that be clearer? At least
"introspection" is less intuitive for me.
--
Cheers,
David
^ permalink raw reply [flat|nested] 37+ messages in thread* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-21 14:18 ` David Hildenbrand (Arm)
@ 2026-08-21 14:48 ` Jann Horn
2026-08-21 18:52 ` Lorenzo Stoakes (ARM)
0 siblings, 1 reply; 37+ messages in thread
From: Jann Horn @ 2026-08-21 14:48 UTC (permalink / raw)
To: David Hildenbrand (Arm)
Cc: Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
Jeff Xu, Thiébaud Weksteen, Alexander Viro,
Christian Brauner, Jan Kara, linux-fsdevel, linux-security-module,
Ondrej Mosnacek, selinux, Andrew Morton, Liam R. Howlett,
Lorenzo Stoakes, Vlastimil Babka, Pedro Falcato, linux-mm
On Fri, Aug 21, 2026 at 4:19 PM David Hildenbrand (Arm)
<david@kernel.org> wrote:
> On 8/20/26 20:44, Jann Horn wrote:
> > On Thu, Aug 20, 2026 at 7:22 PM David Hildenbrand (Arm)
> > <david@kernel.org> wrote:
> >> On 8/18/26 21:51, Jann Horn wrote:
> >>> If the system is running with PROC_MEM_FORCE_ALWAYS, LSMs currently have no
> >>> good opportunity to block a process from overwriting read-only code in its
> >>> own address space through FOLL_FORCE writes via /proc/self/mem.
> >>> The security_ptrace_access_check() LSM hook is bypassed when a process
> >>> opens /proc/self/mem because this is considered "introspection".
> >>>
> >>> This causes a hole in SELinux EXECMEM enforcement, which tries to ensure
> >>> that a process cannot create executable anonymous pages.
> >>>
> >>> PROC_MEM_FORCE_PTRACE prevents that and ensures that such FOLL_FORCE
> >>> accesses are only possible when the LSM allows ptrace() attachment; but it
> >>> is unclear how quickly PROC_MEM_FORCE_PTRACE can be deployed in
> >>> environments running lots of third-party code, such as Android.
> >>>
> >>> So, introduce a new LSM hook that can forbid FOLL_FORCE specifically for
> >>> such "introspective" accesses.
> >>>
> >>> Signed-off-by: Jann Horn <jannh@google.com>
> >>> ---
> >>> fs/proc/base.c | 6 ++++++
> >>> include/linux/lsm_hook_defs.h | 1 +
> >>> include/linux/security.h | 6 ++++++
> >>> security/security.c | 15 +++++++++++++++
> >>> 4 files changed, 28 insertions(+)
> >>>
> >>> diff --git a/fs/proc/base.c b/fs/proc/base.c
> >>> index bec6197329dc..3dfaef49bb70 100644
> >>> --- a/fs/proc/base.c
> >>> +++ b/fs/proc/base.c
> >>> @@ -851,6 +851,8 @@ static int __mem_open(struct inode *inode, struct file *file, unsigned int mode)
> >>> /* private_data for proc_mem_operations */
> >>> struct mem_private {
> >>> struct mm_struct *mm;
> >>> + /* Was the ptrace access check bypassed due to introspection? */
> >>> + bool introspection;
> >>> };
> >>>
> >>> static int mem_open(struct inode *inode, struct file *file)
> >>> @@ -864,12 +866,14 @@ static int mem_open(struct inode *inode, struct file *file)
> >>> priv->mm = proc_mem_open(inode, PTRACE_MODE_ATTACH);
> >>> if (IS_ERR_OR_NULL(priv->mm))
> >>> return priv->mm ? PTR_ERR(priv->mm) : -ESRCH;
> >>> + priv->introspection = priv->mm == current->mm;
> >>
> >> Is the feat that the fd could be passed to someone else that would then not be
> >> detected as introspection?
> >
> > Yes, exactly, that's the primary reason why I did it this way.
>
> Okay, would "opened_by_owner" or something like that be clearer? At least
> "introspection" is less intuitive for me.
Ack, I'll rename it to something like that for the next version.
^ permalink raw reply [flat|nested] 37+ messages in thread* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-21 14:48 ` Jann Horn
@ 2026-08-21 18:52 ` Lorenzo Stoakes (ARM)
2026-08-24 17:06 ` Jann Horn
0 siblings, 1 reply; 37+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-21 18:52 UTC (permalink / raw)
To: Jann Horn
Cc: David Hildenbrand (Arm), Paul Moore, James Morris,
Serge E. Hallyn, Stephen Smalley, Jeff Xu, Thiébaud Weksteen,
Alexander Viro, Christian Brauner, Jan Kara, linux-fsdevel,
linux-security-module, Ondrej Mosnacek, selinux, Andrew Morton,
Liam R. Howlett, Vlastimil Babka, Pedro Falcato, linux-mm
On Fri, Aug 21, 2026 at 04:48:32PM +0200, Jann Horn wrote:
> On Fri, Aug 21, 2026 at 4:19 PM David Hildenbrand (Arm)
> <david@kernel.org> wrote:
> > On 8/20/26 20:44, Jann Horn wrote:
> > > On Thu, Aug 20, 2026 at 7:22 PM David Hildenbrand (Arm)
> > > <david@kernel.org> wrote:
> > >> On 8/18/26 21:51, Jann Horn wrote:
> > >>> If the system is running with PROC_MEM_FORCE_ALWAYS, LSMs currently have no
> > >>> good opportunity to block a process from overwriting read-only code in its
> > >>> own address space through FOLL_FORCE writes via /proc/self/mem.
> > >>> The security_ptrace_access_check() LSM hook is bypassed when a process
> > >>> opens /proc/self/mem because this is considered "introspection".
> > >>>
> > >>> This causes a hole in SELinux EXECMEM enforcement, which tries to ensure
> > >>> that a process cannot create executable anonymous pages.
> > >>>
> > >>> PROC_MEM_FORCE_PTRACE prevents that and ensures that such FOLL_FORCE
> > >>> accesses are only possible when the LSM allows ptrace() attachment; but it
> > >>> is unclear how quickly PROC_MEM_FORCE_PTRACE can be deployed in
> > >>> environments running lots of third-party code, such as Android.
> > >>>
> > >>> So, introduce a new LSM hook that can forbid FOLL_FORCE specifically for
> > >>> such "introspective" accesses.
> > >>>
> > >>> Signed-off-by: Jann Horn <jannh@google.com>
> > >>> ---
> > >>> fs/proc/base.c | 6 ++++++
> > >>> include/linux/lsm_hook_defs.h | 1 +
> > >>> include/linux/security.h | 6 ++++++
> > >>> security/security.c | 15 +++++++++++++++
> > >>> 4 files changed, 28 insertions(+)
> > >>>
> > >>> diff --git a/fs/proc/base.c b/fs/proc/base.c
> > >>> index bec6197329dc..3dfaef49bb70 100644
> > >>> --- a/fs/proc/base.c
> > >>> +++ b/fs/proc/base.c
> > >>> @@ -851,6 +851,8 @@ static int __mem_open(struct inode *inode, struct file *file, unsigned int mode)
> > >>> /* private_data for proc_mem_operations */
> > >>> struct mem_private {
> > >>> struct mm_struct *mm;
> > >>> + /* Was the ptrace access check bypassed due to introspection? */
> > >>> + bool introspection;
> > >>> };
> > >>>
> > >>> static int mem_open(struct inode *inode, struct file *file)
> > >>> @@ -864,12 +866,14 @@ static int mem_open(struct inode *inode, struct file *file)
> > >>> priv->mm = proc_mem_open(inode, PTRACE_MODE_ATTACH);
> > >>> if (IS_ERR_OR_NULL(priv->mm))
> > >>> return priv->mm ? PTR_ERR(priv->mm) : -ESRCH;
> > >>> + priv->introspection = priv->mm == current->mm;
> > >>
> > >> Is the feat that the fd could be passed to someone else that would then not be
> > >> detected as introspection?
> > >
> > > Yes, exactly, that's the primary reason why I did it this way.
> >
> > Okay, would "opened_by_owner" or something like that be clearer? At least
> > "introspection" is less intuitive for me.
>
> Ack, I'll rename it to something like that for the next version.
I agree the naming is confusing.
OK so the whole thing is:
mem_open()
-> __mem_open()
-> proc_mem_open()
-> mm_access()
-> may_access_mm()
And:
static bool may_access_mm(struct mm_struct *mm, struct task_struct *task, unsigned int mode)
{
if (mm == current->mm)
return true;
...
}
And what this flag is carrying is 'hey the reason we allowed the _open_ is
because it's looking at its own address space'.
I did wonder if what you're protecting against is even a process updating
execmem _it_ owns, no fd shared anywhere, as something LSM might want to
prevent even so?
The sharing a /proc/mem fd seems like that's a pretty dumb thing to do in
general :) but I guess you have to protect against that.
But TL;DR I agree with David on the naming, opened_by_owner is probably the
least-worst way of saying it very plainly and covers both cases.
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 37+ messages in thread* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-21 18:52 ` Lorenzo Stoakes (ARM)
@ 2026-08-24 17:06 ` Jann Horn
2026-08-24 17:32 ` Lorenzo Stoakes (ARM)
0 siblings, 1 reply; 37+ messages in thread
From: Jann Horn @ 2026-08-24 17:06 UTC (permalink / raw)
To: Lorenzo Stoakes (ARM)
Cc: David Hildenbrand (Arm), Paul Moore, James Morris,
Serge E. Hallyn, Stephen Smalley, Jeff Xu, Thiébaud Weksteen,
Alexander Viro, Christian Brauner, Jan Kara, linux-fsdevel,
linux-security-module, Ondrej Mosnacek, selinux, Andrew Morton,
Liam R. Howlett, Vlastimil Babka, Pedro Falcato, linux-mm
On Fri, Aug 21, 2026 at 8:52 PM Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> OK so the whole thing is:
>
> mem_open()
> -> __mem_open()
> -> proc_mem_open()
> -> mm_access()
> -> may_access_mm()
>
> And:
>
> static bool may_access_mm(struct mm_struct *mm, struct task_struct *task, unsigned int mode)
> {
> if (mm == current->mm)
> return true;
> ...
> }
>
> And what this flag is carrying is 'hey the reason we allowed the _open_ is
> because it's looking at its own address space'.
Yes.
> I did wonder if what you're protecting against is even a process updating
> execmem _it_ owns, no fd shared anywhere, as something LSM might want to
> prevent even so?
Sorry, can you rephrase that? My goal with this series is to let LSMs
block a process that tries to modify its own non-writable executable
memory using /proc/self/mem; I'm not sure if that answers your
question.
For context: In this series, I'm using "execmem" to refer to the
SELinux permission PROCESS__EXECMEM, which essentially controls
whether a process is allowed to create writable+executable mappings
that can contain anonymous pages. Additionally, it blocks creating
executable mappings of S_PRIVATE inodes. There are other SELinux
permissions for things like making a VMA containing anonymous pages
executable (FILE__EXECMOD and others) or mapping files as executable
(FILE__EXECUTE). FILE__EXECUTE is granular, it can be granted based on
the security labels of the process and the file that is mapped.
> The sharing a /proc/mem fd seems like that's a pretty dumb thing to do in
> general :) but I guess you have to protect against that.
Yeah, it's a kinda weird thing to do...
^ permalink raw reply [flat|nested] 37+ messages in thread* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-24 17:06 ` Jann Horn
@ 2026-08-24 17:32 ` Lorenzo Stoakes (ARM)
2026-08-24 17:43 ` Jann Horn
0 siblings, 1 reply; 37+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-24 17:32 UTC (permalink / raw)
To: Jann Horn
Cc: David Hildenbrand (Arm), Paul Moore, James Morris,
Serge E. Hallyn, Stephen Smalley, Jeff Xu, Thiébaud Weksteen,
Alexander Viro, Christian Brauner, Jan Kara, linux-fsdevel,
linux-security-module, Ondrej Mosnacek, selinux, Andrew Morton,
Liam R. Howlett, Vlastimil Babka, Pedro Falcato, linux-mm
On Mon, Aug 24, 2026 at 07:06:04PM +0200, Jann Horn wrote:
> On Fri, Aug 21, 2026 at 8:52 PM Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> > OK so the whole thing is:
> >
> > mem_open()
> > -> __mem_open()
> > -> proc_mem_open()
> > -> mm_access()
> > -> may_access_mm()
> >
> > And:
> >
> > static bool may_access_mm(struct mm_struct *mm, struct task_struct *task, unsigned int mode)
> > {
> > if (mm == current->mm)
> > return true;
> > ...
> > }
> >
> > And what this flag is carrying is 'hey the reason we allowed the _open_ is
> > because it's looking at its own address space'.
>
> Yes.
OK cool. Obviously do agree with David that calling out the ownership aspect in
the name would be helpful!
>
> > I did wonder if what you're protecting against is even a process updating
> > execmem _it_ owns, no fd shared anywhere, as something LSM might want to
> > prevent even so?
>
> Sorry, can you rephrase that? My goal with this series is to let LSMs
> block a process that tries to modify its own non-writable executable
> memory using /proc/self/mem; I'm not sure if that answers your
> question.
Right, I guess my confusion comes from David's clarification about passing an
fd, perhaps I misunderstood that being somehow the _primary_ thing you were
protecting against.
>
> For context: In this series, I'm using "execmem" to refer to the
> SELinux permission PROCESS__EXECMEM, which essentially controls
> whether a process is allowed to create writable+executable mappings
> that can contain anonymous pages. Additionally, it blocks creating
> executable mappings of S_PRIVATE inodes. There are other SELinux
> permissions for things like making a VMA containing anonymous pages
> executable (FILE__EXECMOD and others) or mapping files as executable
> (FILE__EXECUTE). FILE__EXECUTE is granular, it can be granted based on
> the security labels of the process and the file that is mapped.
Ack thanks for the clarification.
>
> > The sharing a /proc/mem fd seems like that's a pretty dumb thing to do in
> > general :) but I guess you have to protect against that.
>
> Yeah, it's a kinda weird thing to do...
Yup :)) but I guess we have to account for people doing weird stuff...
In this case (I do mention it in a reply elsewhere I think) it does seem
like perhaps you should separately check for current->mm != mm of (what was
originally /proc/self/mm)?
Or at least it seems like a crazy thing to be able to get full access to
another process's memory (that it... gave you though).
Anyway perhaps overthinking it :)
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 37+ messages in thread* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-24 17:32 ` Lorenzo Stoakes (ARM)
@ 2026-08-24 17:43 ` Jann Horn
2026-08-25 13:42 ` Lorenzo Stoakes (ARM)
0 siblings, 1 reply; 37+ messages in thread
From: Jann Horn @ 2026-08-24 17:43 UTC (permalink / raw)
To: Lorenzo Stoakes (ARM)
Cc: David Hildenbrand (Arm), Paul Moore, James Morris,
Serge E. Hallyn, Stephen Smalley, Jeff Xu, Thiébaud Weksteen,
Alexander Viro, Christian Brauner, Jan Kara, linux-fsdevel,
linux-security-module, Ondrej Mosnacek, selinux, Andrew Morton,
Liam R. Howlett, Vlastimil Babka, Pedro Falcato, linux-mm
On Mon, Aug 24, 2026 at 7:33 PM Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> On Mon, Aug 24, 2026 at 07:06:04PM +0200, Jann Horn wrote:
> > On Fri, Aug 21, 2026 at 8:52 PM Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> > > The sharing a /proc/mem fd seems like that's a pretty dumb thing to do in
> > > general :) but I guess you have to protect against that.
> >
> > Yeah, it's a kinda weird thing to do...
>
> Yup :)) but I guess we have to account for people doing weird stuff...
>
> In this case (I do mention it in a reply elsewhere I think) it does seem
> like perhaps you should separately check for current->mm != mm of (what was
> originally /proc/self/mm)?
I wouldn't want to do it for this access check, since that could lead
to "confused deputy" problems.
> Or at least it seems like a crazy thing to be able to get full access to
> another process's memory (that it... gave you though).
>
> Anyway perhaps overthinking it :)
Hm, yes, though I guess that is kind of orthogonal.
For what it's worth, SELinux can prevent such things happening across
domain boundaries - it enforces that, in the SELinux ruleset, the
process calling read()/write() on an FD is granted FILE__READ /
FILE__WRITE permission to the file's inode.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-24 17:43 ` Jann Horn
@ 2026-08-25 13:42 ` Lorenzo Stoakes (ARM)
2026-08-25 14:08 ` Jann Horn
0 siblings, 1 reply; 37+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-25 13:42 UTC (permalink / raw)
To: Jann Horn
Cc: David Hildenbrand (Arm), Paul Moore, James Morris,
Serge E. Hallyn, Stephen Smalley, Jeff Xu, Thiébaud Weksteen,
Alexander Viro, Christian Brauner, Jan Kara, linux-fsdevel,
linux-security-module, Ondrej Mosnacek, selinux, Andrew Morton,
Liam R. Howlett, Vlastimil Babka, Pedro Falcato, linux-mm
On Mon, Aug 24, 2026 at 07:43:02PM +0200, Jann Horn wrote:
> On Mon, Aug 24, 2026 at 7:33 PM Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> > On Mon, Aug 24, 2026 at 07:06:04PM +0200, Jann Horn wrote:
> > > On Fri, Aug 21, 2026 at 8:52 PM Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> > > > The sharing a /proc/mem fd seems like that's a pretty dumb thing to do in
> > > > general :) but I guess you have to protect against that.
> > >
> > > Yeah, it's a kinda weird thing to do...
> >
> > Yup :)) but I guess we have to account for people doing weird stuff...
> >
> > In this case (I do mention it in a reply elsewhere I think) it does seem
> > like perhaps you should separately check for current->mm != mm of (what was
> > originally /proc/self/mm)?
>
> I wouldn't want to do it for this access check, since that could lead
> to "confused deputy" problems.
I guess if it got the decision wrong somehow that'd be a problem? Or wrongly
OK'd it on one level but then that led to the fd being passed on assumption it
was OK to do it or something?
>
> > Or at least it seems like a crazy thing to be able to get full access to
> > another process's memory (that it... gave you though).
> >
> > Anyway perhaps overthinking it :)
>
> Hm, yes, though I guess that is kind of orthogonal.
>
> For what it's worth, SELinux can prevent such things happening across
> domain boundaries - it enforces that, in the SELinux ruleset, the
> process calling read()/write() on an FD is granted FILE__READ /
> FILE__WRITE permission to the file's inode.
Ah OK that's good that it's at least possible to check for this class of problem
so the rest is moot then :)
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-25 13:42 ` Lorenzo Stoakes (ARM)
@ 2026-08-25 14:08 ` Jann Horn
2026-08-25 14:24 ` Lorenzo Stoakes (ARM)
0 siblings, 1 reply; 37+ messages in thread
From: Jann Horn @ 2026-08-25 14:08 UTC (permalink / raw)
To: Lorenzo Stoakes (ARM)
Cc: David Hildenbrand (Arm), Paul Moore, James Morris,
Serge E. Hallyn, Stephen Smalley, Jeff Xu, Thiébaud Weksteen,
Alexander Viro, Christian Brauner, Jan Kara, linux-fsdevel,
linux-security-module, Ondrej Mosnacek, selinux, Andrew Morton,
Liam R. Howlett, Vlastimil Babka, Pedro Falcato, linux-mm
On Tue, Aug 25, 2026 at 3:42 PM Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> On Mon, Aug 24, 2026 at 07:43:02PM +0200, Jann Horn wrote:
> > On Mon, Aug 24, 2026 at 7:33 PM Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> > > On Mon, Aug 24, 2026 at 07:06:04PM +0200, Jann Horn wrote:
> > > > On Fri, Aug 21, 2026 at 8:52 PM Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> > > > > The sharing a /proc/mem fd seems like that's a pretty dumb thing to do in
> > > > > general :) but I guess you have to protect against that.
> > > >
> > > > Yeah, it's a kinda weird thing to do...
> > >
> > > Yup :)) but I guess we have to account for people doing weird stuff...
> > >
> > > In this case (I do mention it in a reply elsewhere I think) it does seem
> > > like perhaps you should separately check for current->mm != mm of (what was
> > > originally /proc/self/mm)?
> >
> > I wouldn't want to do it for this access check, since that could lead
> > to "confused deputy" problems.
>
> I guess if it got the decision wrong somehow that'd be a problem? Or wrongly
> OK'd it on one level but then that led to the fd being passed on assumption it
> was OK to do it or something?
The problematic scenario would be something like:
1. process A opens fd1=open("/proc/self/mem",O_RDWR)
2. process A does lseek(fd1, <address of libc>, SEEK_SET)
3. A sends fd1 to privileged daemon B as a "log output" FD
4. privileged daemon B write()s into fd1
In this scenario, daemon B is just trying to write log output into a
file descriptor. If we checked the current credentials on write(), we
might enable FOLL_FORCE just because daemon B is generally permitted
to use ptrace.
This illustrates why, in general, the "ambient privilege" that a
process has must not influence write() access decisions.
For a similar historical example, see
https://project-zero.issues.chromium.org/issues/42450869 where we used
to do capability checks in the old expand_downwards() logic, which
could be reached by writing into /proc/$pid/mem. That made it possible
for an unprivileged process to map virtual address 0 by providing
/proc/$pid/mem as stderr to a setuid root binary.
^ permalink raw reply [flat|nested] 37+ messages in thread* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-25 14:08 ` Jann Horn
@ 2026-08-25 14:24 ` Lorenzo Stoakes (ARM)
2026-08-25 15:00 ` Jann Horn
0 siblings, 1 reply; 37+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-25 14:24 UTC (permalink / raw)
To: Jann Horn
Cc: David Hildenbrand (Arm), Paul Moore, James Morris,
Serge E. Hallyn, Stephen Smalley, Jeff Xu, Thiébaud Weksteen,
Alexander Viro, Christian Brauner, Jan Kara, linux-fsdevel,
linux-security-module, Ondrej Mosnacek, selinux, Andrew Morton,
Liam R. Howlett, Vlastimil Babka, Pedro Falcato, linux-mm
On Tue, Aug 25, 2026 at 04:08:42PM +0200, Jann Horn wrote:
> On Tue, Aug 25, 2026 at 3:42 PM Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> > On Mon, Aug 24, 2026 at 07:43:02PM +0200, Jann Horn wrote:
> > > On Mon, Aug 24, 2026 at 7:33 PM Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> > > > On Mon, Aug 24, 2026 at 07:06:04PM +0200, Jann Horn wrote:
> > > > > On Fri, Aug 21, 2026 at 8:52 PM Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> > > > > > The sharing a /proc/mem fd seems like that's a pretty dumb thing to do in
> > > > > > general :) but I guess you have to protect against that.
> > > > >
> > > > > Yeah, it's a kinda weird thing to do...
> > > >
> > > > Yup :)) but I guess we have to account for people doing weird stuff...
> > > >
> > > > In this case (I do mention it in a reply elsewhere I think) it does seem
> > > > like perhaps you should separately check for current->mm != mm of (what was
> > > > originally /proc/self/mm)?
> > >
> > > I wouldn't want to do it for this access check, since that could lead
> > > to "confused deputy" problems.
> >
> > I guess if it got the decision wrong somehow that'd be a problem? Or wrongly
> > OK'd it on one level but then that led to the fd being passed on assumption it
> > was OK to do it or something?
>
> The problematic scenario would be something like:
>
> 1. process A opens fd1=open("/proc/self/mem",O_RDWR)
> 2. process A does lseek(fd1, <address of libc>, SEEK_SET)
> 3. A sends fd1 to privileged daemon B as a "log output" FD
> 4. privileged daemon B write()s into fd1
>
> In this scenario, daemon B is just trying to write log output into a
> file descriptor. If we checked the current credentials on write(), we
> might enable FOLL_FORCE just because daemon B is generally permitted
> to use ptrace.
>
> This illustrates why, in general, the "ambient privilege" that a
> process has must not influence write() access decisions.
Ahh. That makes sense.
But I mean in this case the check would be that the mm is the one belonging to
the process in question so wouldn't you need in the first place to have obtained
a privileged mm anyway?
If the check is literally mm of /proc/$pid/mem == current->mm?
And wouldn't prilileged process -> fd to /proc/$pid/mem -> less privileged
process be a fail in itself?
>
> For a similar historical example, see
> https://project-zero.issues.chromium.org/issues/42450869 where we used
> to do capability checks in the old expand_downwards() logic, which
> could be reached by writing into /proc/$pid/mem. That made it possible
> for an unprivileged process to map virtual address 0 by providing
> /proc/$pid/mem as stderr to a setuid root binary.
This does raise questions about /proc/$pid/mm as a whole but I guess that ship
sailed long ago...
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 37+ messages in thread* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-25 14:24 ` Lorenzo Stoakes (ARM)
@ 2026-08-25 15:00 ` Jann Horn
0 siblings, 0 replies; 37+ messages in thread
From: Jann Horn @ 2026-08-25 15:00 UTC (permalink / raw)
To: Lorenzo Stoakes (ARM)
Cc: David Hildenbrand (Arm), Paul Moore, James Morris,
Serge E. Hallyn, Stephen Smalley, Jeff Xu, Thiébaud Weksteen,
Alexander Viro, Christian Brauner, Jan Kara, linux-fsdevel,
linux-security-module, Ondrej Mosnacek, selinux, Andrew Morton,
Liam R. Howlett, Vlastimil Babka, Pedro Falcato, linux-mm
On Tue, Aug 25, 2026 at 4:24 PM Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> On Tue, Aug 25, 2026 at 04:08:42PM +0200, Jann Horn wrote:
> > On Tue, Aug 25, 2026 at 3:42 PM Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> > > On Mon, Aug 24, 2026 at 07:43:02PM +0200, Jann Horn wrote:
> > > > On Mon, Aug 24, 2026 at 7:33 PM Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> > > > > On Mon, Aug 24, 2026 at 07:06:04PM +0200, Jann Horn wrote:
> > > > > > On Fri, Aug 21, 2026 at 8:52 PM Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> > > > > > > The sharing a /proc/mem fd seems like that's a pretty dumb thing to do in
> > > > > > > general :) but I guess you have to protect against that.
> > > > > >
> > > > > > Yeah, it's a kinda weird thing to do...
> > > > >
> > > > > Yup :)) but I guess we have to account for people doing weird stuff...
> > > > >
> > > > > In this case (I do mention it in a reply elsewhere I think) it does seem
> > > > > like perhaps you should separately check for current->mm != mm of (what was
> > > > > originally /proc/self/mm)?
> > > >
> > > > I wouldn't want to do it for this access check, since that could lead
> > > > to "confused deputy" problems.
> > >
> > > I guess if it got the decision wrong somehow that'd be a problem? Or wrongly
> > > OK'd it on one level but then that led to the fd being passed on assumption it
> > > was OK to do it or something?
> >
> > The problematic scenario would be something like:
> >
> > 1. process A opens fd1=open("/proc/self/mem",O_RDWR)
> > 2. process A does lseek(fd1, <address of libc>, SEEK_SET)
> > 3. A sends fd1 to privileged daemon B as a "log output" FD
> > 4. privileged daemon B write()s into fd1
> >
> > In this scenario, daemon B is just trying to write log output into a
> > file descriptor. If we checked the current credentials on write(), we
> > might enable FOLL_FORCE just because daemon B is generally permitted
> > to use ptrace.
> >
> > This illustrates why, in general, the "ambient privilege" that a
> > process has must not influence write() access decisions.
>
> Ahh. That makes sense.
>
> But I mean in this case the check would be that the mm is the one belonging to
> the process in question so wouldn't you need in the first place to have obtained
> a privileged mm anyway?
>
> If the check is literally mm of /proc/$pid/mem == current->mm?
Ah, right, true.
Still, I think I want to generally avoid looking at the current
process in write(). If I did add such a check, and the check failed,
I'm also not sure what I'd do with this information.
> And wouldn't prilileged process -> fd to /proc/$pid/mem -> less privileged
> process be a fail in itself?
Yes, true.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-18 19:51 ` [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS) Jann Horn
2026-08-18 20:00 ` sashiko-bot
2026-08-20 17:22 ` David Hildenbrand (Arm)
@ 2026-08-21 19:00 ` Lorenzo Stoakes (ARM)
2026-08-24 17:28 ` Jann Horn
2026-08-25 13:13 ` Christian Brauner
2026-08-25 13:19 ` Christian Brauner
4 siblings, 1 reply; 37+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-21 19:00 UTC (permalink / raw)
To: Jann Horn
Cc: Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
Jeff Xu, Thiébaud Weksteen, Alexander Viro,
Christian Brauner, Jan Kara, linux-fsdevel, linux-security-module,
Ondrej Mosnacek, selinux, Andrew Morton, Liam R. Howlett,
Vlastimil Babka, Pedro Falcato, David Hildenbrand, linux-mm
On Tue, Aug 18, 2026 at 09:51:06PM +0200, Jann Horn wrote:
> If the system is running with PROC_MEM_FORCE_ALWAYS, LSMs currently have no
> good opportunity to block a process from overwriting read-only code in its
> own address space through FOLL_FORCE writes via /proc/self/mem.
> The security_ptrace_access_check() LSM hook is bypassed when a process
> opens /proc/self/mem because this is considered "introspection".
>
> This causes a hole in SELinux EXECMEM enforcement, which tries to ensure
> that a process cannot create executable anonymous pages.
>
> PROC_MEM_FORCE_PTRACE prevents that and ensures that such FOLL_FORCE
> accesses are only possible when the LSM allows ptrace() attachment; but it
> is unclear how quickly PROC_MEM_FORCE_PTRACE can be deployed in
> environments running lots of third-party code, such as Android.
>
> So, introduce a new LSM hook that can forbid FOLL_FORCE specifically for
> such "introspective" accesses.
>
> Signed-off-by: Jann Horn <jannh@google.com>
> ---
> fs/proc/base.c | 6 ++++++
> include/linux/lsm_hook_defs.h | 1 +
> include/linux/security.h | 6 ++++++
> security/security.c | 15 +++++++++++++++
> 4 files changed, 28 insertions(+)
>
> diff --git a/fs/proc/base.c b/fs/proc/base.c
> index bec6197329dc..3dfaef49bb70 100644
> --- a/fs/proc/base.c
> +++ b/fs/proc/base.c
> @@ -851,6 +851,8 @@ static int __mem_open(struct inode *inode, struct file *file, unsigned int mode)
> /* private_data for proc_mem_operations */
> struct mem_private {
> struct mm_struct *mm;
> + /* Was the ptrace access check bypassed due to introspection? */
> + bool introspection;
> };
>
> static int mem_open(struct inode *inode, struct file *file)
> @@ -864,12 +866,14 @@ static int mem_open(struct inode *inode, struct file *file)
> priv->mm = proc_mem_open(inode, PTRACE_MODE_ATTACH);
> if (IS_ERR_OR_NULL(priv->mm))
> return priv->mm ? PTR_ERR(priv->mm) : -ESRCH;
> + priv->introspection = priv->mm == current->mm;
> file->private_data = no_free_ptr(priv);
> return 0;
> }
>
> static bool proc_mem_foll_force(struct file *file, struct mm_struct *mm)
> {
> + struct mem_private *priv = file->private_data;
> struct task_struct *task;
> bool ptrace_active = false;
>
> @@ -886,6 +890,8 @@ static bool proc_mem_foll_force(struct file *file, struct mm_struct *mm)
> }
> return ptrace_active;
> default:
> + if (priv->introspection)
> + return security_introspect_mem_foll_force(file->f_cred) == 0;
As per 3/3 I wonder if you need an additional parameter to cover the fd -> some
other process case?
Like:
if (priv->owned_by_owner) {
const bool is_remote = current->mm != priv->mm;
return !security_fd_from_owner_mem_foll_force(file->f_cred,
is_remote);
}
(I'm not sure how LSM hooks are supposed to look :)
> return true;
> }
> }
> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index 65c9609ec207..67452f71bedf 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -36,6 +36,7 @@ LSM_HOOK(int, 0, binder_transfer_file, const struct cred *from,
> LSM_HOOK(int, 0, ptrace_access_check, struct task_struct *child,
> unsigned int mode)
> LSM_HOOK(int, 0, ptrace_traceme, struct task_struct *parent)
> +LSM_HOOK(int, 0, introspect_mem_foll_force, const struct cred *subject)
> LSM_HOOK(int, 0, capget, const struct task_struct *target, kernel_cap_t *effective,
> kernel_cap_t *inheritable, kernel_cap_t *permitted)
> LSM_HOOK(int, 0, capset, struct cred *new, const struct cred *old,
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 153e9043058f..f8483be58bc8 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -338,6 +338,7 @@ int security_binder_transfer_file(const struct cred *from,
> const struct cred *to, const struct file *file);
> int security_ptrace_access_check(struct task_struct *child, unsigned int mode);
> int security_ptrace_traceme(struct task_struct *parent);
> +int security_introspect_mem_foll_force(const struct cred *subject);
> int security_capget(const struct task_struct *target,
> kernel_cap_t *effective,
> kernel_cap_t *inheritable,
> @@ -676,6 +677,11 @@ static inline int security_ptrace_traceme(struct task_struct *parent)
> return cap_ptrace_traceme(parent);
> }
>
> +static inline int security_introspect_mem_foll_force(const struct cred *subject)
> +{
> + return 0;
> +}
> +
> static inline int security_capget(const struct task_struct *target,
> kernel_cap_t *effective,
> kernel_cap_t *inheritable,
> diff --git a/security/security.c b/security/security.c
> index 71aea8fdf014..d0f790a534eb 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -595,6 +595,21 @@ int security_ptrace_traceme(struct task_struct *parent)
> return call_int_hook(ptrace_traceme, parent);
> }
>
> +/**
> + * security_introspect_mem_foll_force() - Check if introspective FOLL_FORCE is allowed
> + * @subject: credentials of the process accessing its own memory
> + *
> + * Check if FOLL_FORCE is allowed for a process accessing its own memory, which
> + * bypasses the security_ptrace_access_check() hook.
This should be updated to also explicitly mention the fd case. As surely in that
case this is not true? Unless I'm missing something.
> + * This is only used when the system is configured with PROC_MEM_FORCE_ALWAYS.
> + *
> + * Return: Returns 0 if permission is granted.
> + */
> +int security_introspect_mem_foll_force(const struct cred *subject)
> +{
> + return call_int_hook(introspect_mem_foll_force, subject);
> +}
> +
> /**
> * security_capget() - Get the capability sets for a process
> * @target: target process
>
> --
> 2.55.0.737.g08866a6d13-goog
>
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 37+ messages in thread* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-21 19:00 ` Lorenzo Stoakes (ARM)
@ 2026-08-24 17:28 ` Jann Horn
2026-08-25 14:02 ` Lorenzo Stoakes (ARM)
0 siblings, 1 reply; 37+ messages in thread
From: Jann Horn @ 2026-08-24 17:28 UTC (permalink / raw)
To: Lorenzo Stoakes (ARM)
Cc: Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
Jeff Xu, Thiébaud Weksteen, Alexander Viro,
Christian Brauner, Jan Kara, linux-fsdevel, linux-security-module,
Ondrej Mosnacek, selinux, Andrew Morton, Liam R. Howlett,
Vlastimil Babka, Pedro Falcato, David Hildenbrand, linux-mm
On Fri, Aug 21, 2026 at 9:00 PM Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> On Tue, Aug 18, 2026 at 09:51:06PM +0200, Jann Horn wrote:
> > If the system is running with PROC_MEM_FORCE_ALWAYS, LSMs currently have no
> > good opportunity to block a process from overwriting read-only code in its
> > own address space through FOLL_FORCE writes via /proc/self/mem.
> > The security_ptrace_access_check() LSM hook is bypassed when a process
> > opens /proc/self/mem because this is considered "introspection".
> >
> > This causes a hole in SELinux EXECMEM enforcement, which tries to ensure
> > that a process cannot create executable anonymous pages.
> >
> > PROC_MEM_FORCE_PTRACE prevents that and ensures that such FOLL_FORCE
> > accesses are only possible when the LSM allows ptrace() attachment; but it
> > is unclear how quickly PROC_MEM_FORCE_PTRACE can be deployed in
> > environments running lots of third-party code, such as Android.
> >
> > So, introduce a new LSM hook that can forbid FOLL_FORCE specifically for
> > such "introspective" accesses.
> >
> > Signed-off-by: Jann Horn <jannh@google.com>
> > @@ -886,6 +890,8 @@ static bool proc_mem_foll_force(struct file *file, struct mm_struct *mm)
> > }
> > return ptrace_active;
> > default:
> > + if (priv->introspection)
> > + return security_introspect_mem_foll_force(file->f_cred) == 0;
>
> As per 3/3 I wonder if you need an additional parameter to cover the fd -> some
> other process case?
>
> Like:
> if (priv->owned_by_owner) {
> const bool is_remote = current->mm != priv->mm;
>
> return !security_fd_from_owner_mem_foll_force(file->f_cred,
> is_remote);
> }
>
> (I'm not sure how LSM hooks are supposed to look :)
We could do that if we wanted to treat cases differently based on the
identity of the writer, but I think in general that's not a good idea.
In general, if you send an FD to some daemon, and the daemon writes
into the FD, this should not cause access control decisions based on
the identity of the daemon, because it can cause "confused deputy"
bugs - the daemon might think it is just writing log output into a
normal file, or something like that.
> > diff --git a/security/security.c b/security/security.c
> > index 71aea8fdf014..d0f790a534eb 100644
> > --- a/security/security.c
> > +++ b/security/security.c
> > @@ -595,6 +595,21 @@ int security_ptrace_traceme(struct task_struct *parent)
> > return call_int_hook(ptrace_traceme, parent);
> > }
> >
> > +/**
> > + * security_introspect_mem_foll_force() - Check if introspective FOLL_FORCE is allowed
> > + * @subject: credentials of the process accessing its own memory
> > + *
> > + * Check if FOLL_FORCE is allowed for a process accessing its own memory, which
> > + * bypasses the security_ptrace_access_check() hook.
>
> This should be updated to also explicitly mention the fd case. As surely in that
> case this is not true? Unless I'm missing something.
Yeah, I'll clarify this comment.
^ permalink raw reply [flat|nested] 37+ messages in thread* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-24 17:28 ` Jann Horn
@ 2026-08-25 14:02 ` Lorenzo Stoakes (ARM)
0 siblings, 0 replies; 37+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-25 14:02 UTC (permalink / raw)
To: Jann Horn
Cc: Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
Jeff Xu, Thiébaud Weksteen, Alexander Viro,
Christian Brauner, Jan Kara, linux-fsdevel, linux-security-module,
Ondrej Mosnacek, selinux, Andrew Morton, Liam R. Howlett,
Vlastimil Babka, Pedro Falcato, David Hildenbrand, linux-mm
On Mon, Aug 24, 2026 at 07:28:24PM +0200, Jann Horn wrote:
> On Fri, Aug 21, 2026 at 9:00 PM Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> > On Tue, Aug 18, 2026 at 09:51:06PM +0200, Jann Horn wrote:
> > > If the system is running with PROC_MEM_FORCE_ALWAYS, LSMs currently have no
> > > good opportunity to block a process from overwriting read-only code in its
> > > own address space through FOLL_FORCE writes via /proc/self/mem.
> > > The security_ptrace_access_check() LSM hook is bypassed when a process
> > > opens /proc/self/mem because this is considered "introspection".
> > >
> > > This causes a hole in SELinux EXECMEM enforcement, which tries to ensure
> > > that a process cannot create executable anonymous pages.
> > >
> > > PROC_MEM_FORCE_PTRACE prevents that and ensures that such FOLL_FORCE
> > > accesses are only possible when the LSM allows ptrace() attachment; but it
> > > is unclear how quickly PROC_MEM_FORCE_PTRACE can be deployed in
> > > environments running lots of third-party code, such as Android.
> > >
> > > So, introduce a new LSM hook that can forbid FOLL_FORCE specifically for
> > > such "introspective" accesses.
> > >
> > > Signed-off-by: Jann Horn <jannh@google.com>
>
> > > @@ -886,6 +890,8 @@ static bool proc_mem_foll_force(struct file *file, struct mm_struct *mm)
> > > }
> > > return ptrace_active;
> > > default:
> > > + if (priv->introspection)
> > > + return security_introspect_mem_foll_force(file->f_cred) == 0;
> >
> > As per 3/3 I wonder if you need an additional parameter to cover the fd -> some
> > other process case?
> >
> > Like:
> > if (priv->owned_by_owner) {
> > const bool is_remote = current->mm != priv->mm;
> >
> > return !security_fd_from_owner_mem_foll_force(file->f_cred,
> > is_remote);
> > }
> >
> > (I'm not sure how LSM hooks are supposed to look :)
>
> We could do that if we wanted to treat cases differently based on the
> identity of the writer, but I think in general that's not a good idea.
>
> In general, if you send an FD to some daemon, and the daemon writes
> into the FD, this should not cause access control decisions based on
> the identity of the daemon, because it can cause "confused deputy"
> bugs - the daemon might think it is just writing log output into a
> normal file, or something like that.
Ack yup, variations of a theme of this, I think I was overly confused by
the fd-passing stuff vs. the key reason for the series.
In general the thing LGTM other than the naming so a respin should be good!
>
> > > diff --git a/security/security.c b/security/security.c
> > > index 71aea8fdf014..d0f790a534eb 100644
> > > --- a/security/security.c
> > > +++ b/security/security.c
> > > @@ -595,6 +595,21 @@ int security_ptrace_traceme(struct task_struct *parent)
> > > return call_int_hook(ptrace_traceme, parent);
> > > }
> > >
> > > +/**
> > > + * security_introspect_mem_foll_force() - Check if introspective FOLL_FORCE is allowed
> > > + * @subject: credentials of the process accessing its own memory
> > > + *
> > > + * Check if FOLL_FORCE is allowed for a process accessing its own memory, which
> > > + * bypasses the security_ptrace_access_check() hook.
> >
> > This should be updated to also explicitly mention the fd case. As surely in that
> > case this is not true? Unless I'm missing something.
>
> Yeah, I'll clarify this comment.
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-18 19:51 ` [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS) Jann Horn
` (2 preceding siblings ...)
2026-08-21 19:00 ` Lorenzo Stoakes (ARM)
@ 2026-08-25 13:13 ` Christian Brauner
2026-08-25 13:46 ` Jann Horn
2026-08-25 13:19 ` Christian Brauner
4 siblings, 1 reply; 37+ messages in thread
From: Christian Brauner @ 2026-08-25 13:13 UTC (permalink / raw)
To: Jann Horn
Cc: Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
Jeff Xu, Thiébaud Weksteen, Alexander Viro, Jan Kara,
linux-fsdevel, linux-security-module, Ondrej Mosnacek, selinux,
Andrew Morton, Liam R. Howlett, Lorenzo Stoakes, Vlastimil Babka,
Pedro Falcato, David Hildenbrand, linux-mm
On Tue, Aug 18, 2026 at 09:51:06PM +0200, Jann Horn wrote:
> If the system is running with PROC_MEM_FORCE_ALWAYS, LSMs currently have no
> good opportunity to block a process from overwriting read-only code in its
> own address space through FOLL_FORCE writes via /proc/self/mem.
> The security_ptrace_access_check() LSM hook is bypassed when a process
> opens /proc/self/mem because this is considered "introspection".
Useful. I ran into this issue just yesterday in:
https://github.com/systemd/systemd/pull/43511
Btw, it's kinda annoying that PTRACE_POKE{TEXT,DATA} still allows foll
force writes even if PROC_MEM_FORCE_NEVER is enabled. So ideally there'd
also be a hook for that option.
The other thing - though not directly FOLL_FORCE related - is that
process_vm_writev() isn't subject to any security restrictions other
than seccomp filtering either.
^ permalink raw reply [flat|nested] 37+ messages in thread* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-25 13:13 ` Christian Brauner
@ 2026-08-25 13:46 ` Jann Horn
2026-08-26 10:26 ` Christian Brauner
0 siblings, 1 reply; 37+ messages in thread
From: Jann Horn @ 2026-08-25 13:46 UTC (permalink / raw)
To: Christian Brauner
Cc: Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
Jeff Xu, Thiébaud Weksteen, Alexander Viro, Jan Kara,
linux-fsdevel, linux-security-module, Ondrej Mosnacek, selinux,
Andrew Morton, Liam R. Howlett, Lorenzo Stoakes, Vlastimil Babka,
Pedro Falcato, David Hildenbrand, linux-mm
On Tue, Aug 25, 2026 at 3:13 PM Christian Brauner <brauner@kernel.org> wrote:
> On Tue, Aug 18, 2026 at 09:51:06PM +0200, Jann Horn wrote:
> > If the system is running with PROC_MEM_FORCE_ALWAYS, LSMs currently have no
> > good opportunity to block a process from overwriting read-only code in its
> > own address space through FOLL_FORCE writes via /proc/self/mem.
> > The security_ptrace_access_check() LSM hook is bypassed when a process
> > opens /proc/self/mem because this is considered "introspection".
>
> Useful. I ran into this issue just yesterday in:
>
> https://github.com/systemd/systemd/pull/43511
>
> Btw, it's kinda annoying that PTRACE_POKE{TEXT,DATA} still allows foll
> force writes even if PROC_MEM_FORCE_NEVER is enabled. So ideally there'd
> also be a hook for that option.
You need either /proc/$pid/mem or PTRACE_POKETEXT for installing
software breakpoints. I think if you want to completely block
FOLL_FORCE through ptrace, you're probably in a scenario where ptrace
should either be blocked completely, or at least restricted to
mostly-read-only operations?
> The other thing - though not directly FOLL_FORCE related - is that
> process_vm_writev() isn't subject to any security restrictions other
> than seccomp filtering either.
It does go through mm_access() and ptrace_may_access() unless the
access is same-MM, so it can be blocked by LSMs like Yama.
^ permalink raw reply [flat|nested] 37+ messages in thread* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-25 13:46 ` Jann Horn
@ 2026-08-26 10:26 ` Christian Brauner
0 siblings, 0 replies; 37+ messages in thread
From: Christian Brauner @ 2026-08-26 10:26 UTC (permalink / raw)
To: Jann Horn
Cc: Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
Jeff Xu, Thiébaud Weksteen, Alexander Viro, Jan Kara,
linux-fsdevel, linux-security-module, Ondrej Mosnacek, selinux,
Andrew Morton, Liam R. Howlett, Lorenzo Stoakes, Vlastimil Babka,
Pedro Falcato, David Hildenbrand, linux-mm
On Tue, Aug 25, 2026 at 03:46:50PM +0200, Jann Horn wrote:
> On Tue, Aug 25, 2026 at 3:13 PM Christian Brauner <brauner@kernel.org> wrote:
> > On Tue, Aug 18, 2026 at 09:51:06PM +0200, Jann Horn wrote:
> > > If the system is running with PROC_MEM_FORCE_ALWAYS, LSMs currently have no
> > > good opportunity to block a process from overwriting read-only code in its
> > > own address space through FOLL_FORCE writes via /proc/self/mem.
> > > The security_ptrace_access_check() LSM hook is bypassed when a process
> > > opens /proc/self/mem because this is considered "introspection".
> >
> > Useful. I ran into this issue just yesterday in:
> >
> > https://github.com/systemd/systemd/pull/43511
> >
> > Btw, it's kinda annoying that PTRACE_POKE{TEXT,DATA} still allows foll
> > force writes even if PROC_MEM_FORCE_NEVER is enabled. So ideally there'd
> > also be a hook for that option.
>
> You need either /proc/$pid/mem or PTRACE_POKETEXT for installing
> software breakpoints. I think if you want to completely block
This won't be enabled for general-purpose systems. But for a lot of
other systems with a lot stricter requirements this is very useful. And
you can always allow a mode where you intentionally degrade to an
audited "debug" mode where you can turn of the restrictions. Which btw,
isn't possible with seccomp.
> FOLL_FORCE through ptrace, you're probably in a scenario where ptrace
> should either be blocked completely, or at least restricted to
> mostly-read-only operations?
Yes but the list of ptrace() options is prctl()-like. They even have
interactions. Also seccomp isn't necessarily the right tool for this
because it doesn't allow dynamic policies. That would be lsm territory.
>
> > The other thing - though not directly FOLL_FORCE related - is that
> > process_vm_writev() isn't subject to any security restrictions other
> > than seccomp filtering either.
>
> It does go through mm_access() and ptrace_may_access() unless the
> access is same-MM, so it can be blocked by LSMs like Yama.
I think ptrace_may_access() is way to coarse to be really useful. It's a
very frustrating tool. It's easy to use because everyone knows "you need
to access properties of another task, ptrace_may_access() is your guy".
But it prevents better policies. TL;DR you never know _why_ you were
called specifically.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-18 19:51 ` [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS) Jann Horn
` (3 preceding siblings ...)
2026-08-25 13:13 ` Christian Brauner
@ 2026-08-25 13:19 ` Christian Brauner
2026-08-25 14:00 ` Jann Horn
4 siblings, 1 reply; 37+ messages in thread
From: Christian Brauner @ 2026-08-25 13:19 UTC (permalink / raw)
To: Jann Horn
Cc: Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
Jeff Xu, Thiébaud Weksteen, Alexander Viro, Jan Kara,
linux-fsdevel, linux-security-module, Ondrej Mosnacek, selinux,
Andrew Morton, Liam R. Howlett, Lorenzo Stoakes, Vlastimil Babka,
Pedro Falcato, David Hildenbrand, linux-mm
On Tue, Aug 18, 2026 at 09:51:06PM +0200, Jann Horn wrote:
> If the system is running with PROC_MEM_FORCE_ALWAYS, LSMs currently have no
> good opportunity to block a process from overwriting read-only code in its
> own address space through FOLL_FORCE writes via /proc/self/mem.
> The security_ptrace_access_check() LSM hook is bypassed when a process
> opens /proc/self/mem because this is considered "introspection".
>
> This causes a hole in SELinux EXECMEM enforcement, which tries to ensure
> that a process cannot create executable anonymous pages.
>
> PROC_MEM_FORCE_PTRACE prevents that and ensures that such FOLL_FORCE
> accesses are only possible when the LSM allows ptrace() attachment; but it
> is unclear how quickly PROC_MEM_FORCE_PTRACE can be deployed in
> environments running lots of third-party code, such as Android.
>
> So, introduce a new LSM hook that can forbid FOLL_FORCE specifically for
> such "introspective" accesses.
>
> Signed-off-by: Jann Horn <jannh@google.com>
> ---
> fs/proc/base.c | 6 ++++++
> include/linux/lsm_hook_defs.h | 1 +
> include/linux/security.h | 6 ++++++
> security/security.c | 15 +++++++++++++++
> 4 files changed, 28 insertions(+)
>
> diff --git a/fs/proc/base.c b/fs/proc/base.c
> index bec6197329dc..3dfaef49bb70 100644
> --- a/fs/proc/base.c
> +++ b/fs/proc/base.c
> @@ -851,6 +851,8 @@ static int __mem_open(struct inode *inode, struct file *file, unsigned int mode)
> /* private_data for proc_mem_operations */
> struct mem_private {
> struct mm_struct *mm;
> + /* Was the ptrace access check bypassed due to introspection? */
> + bool introspection;
> };
>
> static int mem_open(struct inode *inode, struct file *file)
> @@ -864,12 +866,14 @@ static int mem_open(struct inode *inode, struct file *file)
> priv->mm = proc_mem_open(inode, PTRACE_MODE_ATTACH);
> if (IS_ERR_OR_NULL(priv->mm))
> return priv->mm ? PTR_ERR(priv->mm) : -ESRCH;
> + priv->introspection = priv->mm == current->mm;
> file->private_data = no_free_ptr(priv);
> return 0;
> }
>
> static bool proc_mem_foll_force(struct file *file, struct mm_struct *mm)
> {
> + struct mem_private *priv = file->private_data;
> struct task_struct *task;
> bool ptrace_active = false;
>
> @@ -886,6 +890,8 @@ static bool proc_mem_foll_force(struct file *file, struct mm_struct *mm)
> }
> return ptrace_active;
> default:
> + if (priv->introspection)
> + return security_introspect_mem_foll_force(file->f_cred) == 0;
Hm. Why not pass the reason to security_introspect_mem_foll_force() and
call it unconditionally? Similarly it could also be called for the
active ptracer case. Then you'd just need to pass a flag to the security
hook and the LSM can decide based on that.
^ permalink raw reply [flat|nested] 37+ messages in thread* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-25 13:19 ` Christian Brauner
@ 2026-08-25 14:00 ` Jann Horn
2026-08-26 10:29 ` Christian Brauner
0 siblings, 1 reply; 37+ messages in thread
From: Jann Horn @ 2026-08-25 14:00 UTC (permalink / raw)
To: Christian Brauner
Cc: Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
Jeff Xu, Thiébaud Weksteen, Alexander Viro, Jan Kara,
linux-fsdevel, linux-security-module, Ondrej Mosnacek, selinux,
Andrew Morton, Liam R. Howlett, Lorenzo Stoakes, Vlastimil Babka,
Pedro Falcato, David Hildenbrand, linux-mm
On Tue, Aug 25, 2026 at 3:19 PM Christian Brauner <brauner@kernel.org> wrote:
> On Tue, Aug 18, 2026 at 09:51:06PM +0200, Jann Horn wrote:
> > If the system is running with PROC_MEM_FORCE_ALWAYS, LSMs currently have no
> > good opportunity to block a process from overwriting read-only code in its
> > own address space through FOLL_FORCE writes via /proc/self/mem.
> > The security_ptrace_access_check() LSM hook is bypassed when a process
> > opens /proc/self/mem because this is considered "introspection".
> >
> > This causes a hole in SELinux EXECMEM enforcement, which tries to ensure
> > that a process cannot create executable anonymous pages.
> >
> > PROC_MEM_FORCE_PTRACE prevents that and ensures that such FOLL_FORCE
> > accesses are only possible when the LSM allows ptrace() attachment; but it
> > is unclear how quickly PROC_MEM_FORCE_PTRACE can be deployed in
> > environments running lots of third-party code, such as Android.
> >
> > So, introduce a new LSM hook that can forbid FOLL_FORCE specifically for
> > such "introspective" accesses.
> >
> > Signed-off-by: Jann Horn <jannh@google.com>
> > ---
> > fs/proc/base.c | 6 ++++++
> > include/linux/lsm_hook_defs.h | 1 +
> > include/linux/security.h | 6 ++++++
> > security/security.c | 15 +++++++++++++++
> > 4 files changed, 28 insertions(+)
> >
> > diff --git a/fs/proc/base.c b/fs/proc/base.c
> > index bec6197329dc..3dfaef49bb70 100644
> > --- a/fs/proc/base.c
> > +++ b/fs/proc/base.c
> > @@ -851,6 +851,8 @@ static int __mem_open(struct inode *inode, struct file *file, unsigned int mode)
> > /* private_data for proc_mem_operations */
> > struct mem_private {
> > struct mm_struct *mm;
> > + /* Was the ptrace access check bypassed due to introspection? */
> > + bool introspection;
> > };
> >
> > static int mem_open(struct inode *inode, struct file *file)
> > @@ -864,12 +866,14 @@ static int mem_open(struct inode *inode, struct file *file)
> > priv->mm = proc_mem_open(inode, PTRACE_MODE_ATTACH);
> > if (IS_ERR_OR_NULL(priv->mm))
> > return priv->mm ? PTR_ERR(priv->mm) : -ESRCH;
> > + priv->introspection = priv->mm == current->mm;
> > file->private_data = no_free_ptr(priv);
> > return 0;
> > }
> >
> > static bool proc_mem_foll_force(struct file *file, struct mm_struct *mm)
> > {
> > + struct mem_private *priv = file->private_data;
> > struct task_struct *task;
> > bool ptrace_active = false;
> >
> > @@ -886,6 +890,8 @@ static bool proc_mem_foll_force(struct file *file, struct mm_struct *mm)
> > }
> > return ptrace_active;
> > default:
> > + if (priv->introspection)
> > + return security_introspect_mem_foll_force(file->f_cred) == 0;
>
> Hm. Why not pass the reason to security_introspect_mem_foll_force() and
> call it unconditionally? Similarly it could also be called for the
> active ptracer case. Then you'd just need to pass a flag to the security
> hook and the LSM can decide based on that.
A process which is attached as a ptracer can modify memory with (for
example) PTRACE_POKETEXT and registers with (for example)
PTRACE_SETREGS. LSMs that want to prevent such debugging operations
are supposed to prevent ptrace attachment with the ptrace_access_check
hook.
I am just trying to plug the enforcement hole where ptrace-style
modification of process state is possible without going through
ptrace_access_check - which means just looking at these
"introspection" cases.
If I wanted to provide LSMs with a more granular ability to do some
PTRACE_MODE_ATTACH operations (like attaching via ptrace) while
blocking other operations (like PTRACE_POKETEXT or changing register
values), that would require more plumbing, so I'm not trying to do
that here.
^ permalink raw reply [flat|nested] 37+ messages in thread* Re: [PATCH 2/3] proc: query LSMs for introspective mem access (if PROC_MEM_FORCE_ALWAYS)
2026-08-25 14:00 ` Jann Horn
@ 2026-08-26 10:29 ` Christian Brauner
0 siblings, 0 replies; 37+ messages in thread
From: Christian Brauner @ 2026-08-26 10:29 UTC (permalink / raw)
To: Jann Horn
Cc: Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
Jeff Xu, Thiébaud Weksteen, Alexander Viro, Jan Kara,
linux-fsdevel, linux-security-module, Ondrej Mosnacek, selinux,
Andrew Morton, Liam R. Howlett, Lorenzo Stoakes, Vlastimil Babka,
Pedro Falcato, David Hildenbrand, linux-mm
On Tue, Aug 25, 2026 at 04:00:40PM +0200, Jann Horn wrote:
> On Tue, Aug 25, 2026 at 3:19 PM Christian Brauner <brauner@kernel.org> wrote:
> > On Tue, Aug 18, 2026 at 09:51:06PM +0200, Jann Horn wrote:
> > > If the system is running with PROC_MEM_FORCE_ALWAYS, LSMs currently have no
> > > good opportunity to block a process from overwriting read-only code in its
> > > own address space through FOLL_FORCE writes via /proc/self/mem.
> > > The security_ptrace_access_check() LSM hook is bypassed when a process
> > > opens /proc/self/mem because this is considered "introspection".
> > >
> > > This causes a hole in SELinux EXECMEM enforcement, which tries to ensure
> > > that a process cannot create executable anonymous pages.
> > >
> > > PROC_MEM_FORCE_PTRACE prevents that and ensures that such FOLL_FORCE
> > > accesses are only possible when the LSM allows ptrace() attachment; but it
> > > is unclear how quickly PROC_MEM_FORCE_PTRACE can be deployed in
> > > environments running lots of third-party code, such as Android.
> > >
> > > So, introduce a new LSM hook that can forbid FOLL_FORCE specifically for
> > > such "introspective" accesses.
> > >
> > > Signed-off-by: Jann Horn <jannh@google.com>
> > > ---
> > > fs/proc/base.c | 6 ++++++
> > > include/linux/lsm_hook_defs.h | 1 +
> > > include/linux/security.h | 6 ++++++
> > > security/security.c | 15 +++++++++++++++
> > > 4 files changed, 28 insertions(+)
> > >
> > > diff --git a/fs/proc/base.c b/fs/proc/base.c
> > > index bec6197329dc..3dfaef49bb70 100644
> > > --- a/fs/proc/base.c
> > > +++ b/fs/proc/base.c
> > > @@ -851,6 +851,8 @@ static int __mem_open(struct inode *inode, struct file *file, unsigned int mode)
> > > /* private_data for proc_mem_operations */
> > > struct mem_private {
> > > struct mm_struct *mm;
> > > + /* Was the ptrace access check bypassed due to introspection? */
> > > + bool introspection;
> > > };
> > >
> > > static int mem_open(struct inode *inode, struct file *file)
> > > @@ -864,12 +866,14 @@ static int mem_open(struct inode *inode, struct file *file)
> > > priv->mm = proc_mem_open(inode, PTRACE_MODE_ATTACH);
> > > if (IS_ERR_OR_NULL(priv->mm))
> > > return priv->mm ? PTR_ERR(priv->mm) : -ESRCH;
> > > + priv->introspection = priv->mm == current->mm;
> > > file->private_data = no_free_ptr(priv);
> > > return 0;
> > > }
> > >
> > > static bool proc_mem_foll_force(struct file *file, struct mm_struct *mm)
> > > {
> > > + struct mem_private *priv = file->private_data;
> > > struct task_struct *task;
> > > bool ptrace_active = false;
> > >
> > > @@ -886,6 +890,8 @@ static bool proc_mem_foll_force(struct file *file, struct mm_struct *mm)
> > > }
> > > return ptrace_active;
> > > default:
> > > + if (priv->introspection)
> > > + return security_introspect_mem_foll_force(file->f_cred) == 0;
> >
> > Hm. Why not pass the reason to security_introspect_mem_foll_force() and
> > call it unconditionally? Similarly it could also be called for the
> > active ptracer case. Then you'd just need to pass a flag to the security
> > hook and the LSM can decide based on that.
>
> A process which is attached as a ptracer can modify memory with (for
> example) PTRACE_POKETEXT and registers with (for example)
> PTRACE_SETREGS. LSMs that want to prevent such debugging operations
> are supposed to prevent ptrace attachment with the ptrace_access_check
> hook.
Yeah, but as I said elsewhere that is very very coarse and you can't
differentiate between the different operations performed on the other
task.
> I am just trying to plug the enforcement hole where ptrace-style
> modification of process state is possible without going through
> ptrace_access_check - which means just looking at these
> "introspection" cases.
It seems odd to just call a hook when it's introspection denied.
And if that's the case why not also have a general hook in
ptrace_may_access() itself in the introspection branch?
I would actually have use-cases for this btw.
^ permalink raw reply [flat|nested] 37+ messages in thread