Re: [PATCH] selinux: fix incorrect execmem checks on overlayfs

Ondrej Mosnacek <[email protected]>
Newsgroups org.kernel.vger.selinux,dev.linux.lists.sashiko-reviews
Message-ID <CAFqZXNvckJRNYahj_wpoZ8zyt-PLug1+CA=CQpKaKZ7MVo6QoQ@mail.gmail.com>
On Fri, Jul 3, 2026 at 2:05 PM <[email protected]> wrote:
>
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
>
> Pre-existing issues:
> - [High] SELinux uses `vma->vm_file` instead of `vma_is_anonymous()` to classify anonymous VMAs, leading to incorrect permission checks.
> --
>
> commit 2446671db8e6a83fbf4c3451f231d685bec26e4e
> Author: Ondrej Mosnacek <[email protected]>
>
> selinux: fix incorrect execmem checks on overlayfs
>
> This commit fixes overlayfs mmap() and mprotect() access checks by skipping
> the execmem check in __file_map_prot_check() during a "mounter check". It
> introduces a boolean to indicate this state, ensuring the check is only
> performed against the calling task's credentials.
>
> > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > index 0f704380a8c81..fca310b7270f3 100644
> > --- a/security/selinux/hooks.c
> > +++ b/security/selinux/hooks.c
> [ ... ]
> > @@ -3988,7 +3989,7 @@ static int __file_map_prot_check(const struct cred *cred,
> >                       inode = file_inode(file);
> >       }
> >
> > -     if (default_noexec && prot_exec &&
> > +     if (!mounter_check && default_noexec && prot_exec &&
> >           (!file || IS_PRIVATE(inode) || (!shared && prot_write))) {
>
> [Severity: High]
> This isn't a bug introduced by this patch, but is it correct to rely on
> !file to identify anonymous mappings here?
>
> Using a file pointer to check for anonymous VMAs instead of
> vma_is_anonymous() can misclassify mappings. A private mapping of /dev/zero
> has vma->vm_file != NULL but is functionally an anonymous mapping. This could
> allow an anonymous mapping to bypass the PROCESS__EXECMEM check.

I don't think this is a problem. There are only a few places where
vma_set_anonymous() is called:
1. mmap_zero_private_success()/mmap_zero_prepare() - this is only
called for MAP_PRIVATE mappings of /dev/zero, where execmem will be
checked if the mapping is writable. If it's not writable, it's the
same situation as creating an RX MAP_PRIVATE mapping of a file that
contains zeros - i.e. the ability to do this will be evaluated by
checking read+execute perms on the /dev/zero inode, which seems better
than treating it as an anonymous mapping.
2. do_mmap_private() - here it is only called when vma->vm_file is NULL.
3. __mmap_new_vma() - here it is only called when vma->vm_file is set to NULL.
4. do_brk_flags() - here it is called for the heap VMA, which is never
file-backed.
5. create_init_stack_vma() - here it is called for the initial stack
VMA, which is never file-backed.

> This same pre-existing pattern appears in selinux_file_mprotect(), which uses
> !file to check for anonymous stack mappings:
>
> security/selinux/hooks.c:selinux_file_mprotect() {
>     ...
>     } else if (!file && (vma_is_initial_stack(vma) ||
>                 vma_is_stack_for_current(vma))) {
>     ...
> }

Initial stack shouldn't be file-backed, so that's a non-issue.

> It also applies the FILE__EXECMOD check to the backing file if vma->anon_vma
> is set, which would incorrectly check the backing device for /dev/zero:
>
> security/selinux/hooks.c:selinux_file_mprotect() {
>     ...
>     } else if (file && vma->anon_vma) {
>         /* ... */
>         rc = __file_has_perm(cred, file, FILE__EXECMOD,
>                              backing_file);
>     ...
> }

The LLM seems to be a bit confused here... The quoted code would check
against the user file (not backing file), and IMHO correctly so. If
the user privately mmaps /dev/zero RW, then modifies the mapping, and
then makes the region executable, it *is* essentially "executing" a
modified version of (possibly overlayed) /dev/zero. And the subsequent
check would then check mounter creds against the backing /dev/zero,
which is also correct.

I don't know, maybe mapping /dev/zero is so close to just doing an
anonymous mapping that it's a bit pointless to take its inodes into
account, but it doesn't seem outright incorrect to me, either.

--
Ondrej Mosnacek
Senior Software Engineer, Linux Security - SELinux kernel
Red Hat, Inc.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.