public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
From: Ondrej Mosnacek <omosnace@redhat.com>
To: git-commits@fedoraproject.org
Subject: [tests/selinux] main: Add a test for overlayfs mmap bugs (CVE-2026-46054)
Date: Wed, 03 Jun 2026 05:48:08 GMT [thread overview]
Message-ID: <178046568832.1.875100787970483319.tests-selinux-9a7d3d69fb0b@fedoraproject.org> (raw)
A new commit has been pushed.
Repo : tests/selinux
Branch : main
Commit : 9a7d3d69fb0bf1dd81ec4aab9aba66d2423e2230
Author : Ondrej Mosnacek <omosnace@redhat.com>
Date : 2026-05-28T14:14:02+02:00
Stats : +271/-0 in 4 file(s)
URL : https://src.fedoraproject.org/tests/selinux/c/9a7d3d69fb0bf1dd81ec4aab9aba66d2423e2230?branch=main
Log:
Add a test for overlayfs mmap bugs (CVE-2026-46054)
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
---
diff --git a/kernel/overlayfs-mmap-bugs/main.fmf b/kernel/overlayfs-mmap-bugs/main.fmf
new file mode 100644
index 0000000..dddb9db
--- /dev/null
+++ b/kernel/overlayfs-mmap-bugs/main.fmf
@@ -0,0 +1,22 @@
+summary: Regression test for overlayfs mmap/mprotect bugs
+description: |
+ Tests various scenarios with overlayfs and mmap/mprotect syscalls.
+ This also covers CVE-2026-46054.
+contact: Ondrej Mosnacek <omosnace@redhat.com>
+component:
+ - kernel
+framework: beakerlib
+require:
+ - selinux-policy-devel
+ - gcc
+duration: 5m
+tier: 2
+enabled: true
+link:
+ - verifies: https://issues.redhat.com/browse/RHEL-127505
+ - verifies: https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2026-46054
+environment:
+ AVC_ERROR: +no_avc_check
+check:
+ - how: avc
+ result: xfail
diff --git a/kernel/overlayfs-mmap-bugs/map_access.c b/kernel/overlayfs-mmap-bugs/map_access.c
new file mode 100644
index 0000000..9300365
--- /dev/null
+++ b/kernel/overlayfs-mmap-bugs/map_access.c
@@ -0,0 +1,70 @@
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/mman.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+int main(int argc, const char **argv)
+{
+ const char *file, *context;
+ void *ptr;
+ int rdonly, fd, ctxfd, ret;
+
+ if (argc < 3 || argc > 4 || (strcmp(argv[2], "RDONLY") && strcmp(argv[2], "RDWR"))) {
+ fprintf(stderr, "Usage %s <file> RDONLY|RDWR\n", argv[0]);
+ return EINVAL;
+ }
+
+ file = argv[1];
+ rdonly = strcmp(argv[2], "RDONLY") == 0;
+ context = argc >= 4 ? argv[3] : NULL;
+
+ fd = open(file, rdonly ? O_RDONLY : O_RDWR);
+ if (fd == -1) {
+ perror("open");
+ return 2;
+ }
+
+ /* try direct mmap */
+ ptr = mmap(NULL, 1, rdonly ? PROT_READ : PROT_READ|PROT_WRITE,
+ MAP_SHARED, fd, 0);
+ if (ptr == MAP_FAILED) {
+ perror("mmap");
+ return 3;
+ }
+ munmap(ptr, 1);
+
+ /* try mmap with PROT_NONE followed by mprotect with full access */
+ ptr = mmap(NULL, 1, PROT_NONE, MAP_SHARED, fd, 0);
+ if (ptr == MAP_FAILED) {
+ perror("mmap PROT_NONE");
+ return 4;
+ }
+
+ if (context) {
+ ctxfd = open("/proc/self/attr/current", O_RDWR);
+ if (ctxfd == -1) {
+ perror("open");
+ return 6;
+ }
+ ret = write(ctxfd, context, strlen(context));
+ if (ret == -1) {
+ perror("write");
+ return 7;
+ }
+ close(ctxfd);
+ }
+
+ ret = mprotect(ptr, 1, rdonly ? PROT_READ : PROT_READ|PROT_WRITE);
+ if (ret == -1) {
+ perror("mprotect");
+ return 5;
+ }
+
+ munmap(ptr, 1);
+ close(fd);
+ return 0;
+}
diff --git a/kernel/overlayfs-mmap-bugs/runtest.sh b/kernel/overlayfs-mmap-bugs/runtest.sh
new file mode 100755
index 0000000..3d15777
--- /dev/null
+++ b/kernel/overlayfs-mmap-bugs/runtest.sh
@@ -0,0 +1,79 @@
+#!/bin/bash
+# vim: dict=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2025 Red Hat, Inc.
+# Author: Ondrej Mosnacek <omosnace@redhat.com>
+
+# Include Beakerlib environment
+. /usr/share/beakerlib/beakerlib.sh || exit 1
+
+rlJournalStart
+ rlPhaseStartSetup
+ rlRun "uname -r" 0 "Print current running kernel version"
+
+ SE_USER="$(secon -u --pid $$)"
+ SE_ROLE="$(secon -r --pid $$)"
+ SE_TYPE="$(secon -t --pid $$)"
+ SE_MLS="$(secon -m --pid $$)"
+
+ OVERLAYCON="$SE_USER:object_r:test_mountedfile_t:s0"
+ DYNTRANSCON="$SE_USER:$SE_ROLE:test_access_exploit_t:$SE_MLS"
+
+ rlRun "gcc -o map_access map_access.c" 0 \
+ "Build the test program"
+ rlRun "chcon -t bin_t map_access" 0 "Relabel the test program"
+ rlRun "make -f /usr/share/selinux/devel/Makefile test_policy.pp M4PARAM='-D TEST_ROLE=$SE_ROLE -D TEST_TYPE=$SE_TYPE'" 0 \
+ "Build the test policy"
+ rlRun "semodule -i test_policy.pp" 0 "Load test policy"
+
+ rlRun "mkdir lowerdir upperdir workdir mountpoint" 0 "Create test dirs"
+ rlRun "touch lowerdir/file_ok lowerdir/file_no_map lowerdir/file_no_read lowerdir/file_no_write" 0 \
+ "Create test files"
+ rlRun "chcon -R -t test_lowerfile_t lowerdir workdir upperdir"
+ rlRun "chcon -t test_lowerfile_no_map_t lowerdir/file_no_map"
+ rlRun "chcon -t test_lowerfile_no_write_t lowerdir/file_no_write"
+ rlRun "chcon -t test_lowerfile_no_read_t lowerdir/file_no_read"
+
+ rlRun "runcon -t test_mounter_t mount -t overlay none -o 'context=$OVERLAYCON,lowerdir=./lowerdir,upperdir=./upperdir,workdir=./workdir' ./mountpoint" 0 \
+ "Mount the overlay filesystem"
+
+ rlRun ":>/var/log/audit/audit.log; rm -f /var/log/audit/audit.log.*" 0 \
+ "Clear the audit log"
+ rlPhaseEnd
+
+ rlPhaseStartTest
+ # Bug 1
+ # Should get below AVC:
+ # avc: denied { map } for scontext=...test_mounter_t... tcontext=...test_lowerfile_no_map_t... tclass=file
+ rlRun "runcon -t test_access_full_t ./map_access ./mountpoint/file_no_map RDONLY" 3 "Test Bug 1"
+
+ # Bug 2, result 1
+ # Shouldn't get below AVC:
+ # avc: denied { use } for scontext=...test_access_full_t... tcontext=...test_mounter_t... tclass=fd
+ rlRun "setsebool domain_fd_use 0"
+ rlRun "runcon -t test_access_full_t ./map_access ./mountpoint/file_ok RDONLY" 0 "Test Bug 2, result 1"
+ rlRun "setsebool domain_fd_use 1"
+
+ # Bug 2, result 2
+ # Shouldn't get below AVC:
+ # avc: denied { read } for scontext=...test_access_full_t... tcontext=...test_lowerfile_t... tclass=file
+ rlRun "runcon -t test_access_full_t ./map_access ./mountpoint/file_ok RDONLY" 0 "Test Bug 2, result 2"
+
+ # Bug 2, result 3
+ # Should get below AVC:
+ # avc: denied { read } for scontext=...test_access_exploit_t... tcontext=...test_mountedfile_t... tclass=file
+ rlRun "runcon -t test_access_full_t ./map_access ./mountpoint/file_ok RDONLY $DYNTRANSCON" 5 "Test Bug 2, result 3"
+ rlPhaseEnd
+
+ rlPhaseStartCleanup
+ rlRun "ausearch -i -m avc" 0 "Show AVC denials"
+
+ rlRun "umount ./mountpoint"
+ rlRun "rm -rf lowerdir upperdir workdir mountpoint"
+ rlRun "semodule -r test_policy" 0 "Unload test policy"
+ rlRun "make -f /usr/share/selinux/devel/Makefile clean" 0 \
+ "Clean the test policy"
+ rlRun "rm -f map_access" 0 "Remove the test program"
+ rlPhaseEnd
+rlJournalPrintText
+rlJournalEnd
diff --git a/kernel/overlayfs-mmap-bugs/test_policy.te b/kernel/overlayfs-mmap-bugs/test_policy.te
new file mode 100644
index 0000000..5260f28
--- /dev/null
+++ b/kernel/overlayfs-mmap-bugs/test_policy.te
@@ -0,0 +1,100 @@
+policy_module(test_policy,1.0.0)
+
+type test_lowerfile_t;
+files_type(test_lowerfile_t)
+
+type test_lowerfile_no_map_t;
+files_type(test_lowerfile_no_map_t)
+
+type test_lowerfile_no_write_t;
+files_type(test_lowerfile_no_write_t)
+
+type test_lowerfile_no_read_t;
+files_type(test_lowerfile_no_read_t)
+
+type test_mountedfile_t;
+files_type(test_mountedfile_t)
+
+type test_mounter_t;
+domain_type(test_mounter_t)
+
+allow test_mounter_t self:capability { sys_admin dac_read_search dac_override };
+
+# test_mounter_t has full access to test_lowerfile_t
+manage_dirs_pattern(test_mounter_t, test_lowerfile_t, test_lowerfile_t)
+manage_files_pattern(test_mounter_t, test_lowerfile_t, test_lowerfile_t)
+manage_chr_files_pattern(test_mounter_t, test_lowerfile_t, test_lowerfile_t)
+allow test_mounter_t test_lowerfile_t:file map;
+
+# test_mounter_t can't map test_lowerfile_t
+rw_files_pattern(test_mounter_t, test_lowerfile_no_map_t, test_lowerfile_no_map_t)
+
+# test_mounter_t can't write test_lowerfile_no_write_t
+read_files_pattern(test_mounter_t, test_lowerfile_no_write_t, test_lowerfile_no_write_t)
+allow test_mounter_t test_lowerfile_no_write_t:file map;
+
+# test_mounter_t can't read test_lowerfile_no_read_t
+write_files_pattern(test_mounter_t, test_lowerfile_no_read_t, test_lowerfile_no_read_t)
+allow test_mounter_t test_lowerfile_no_read_t:file map;
+
+allow test_mounter_t test_mountedfile_t:dir { getattr setattr };
+allow test_mounter_t test_mountedfile_t:filesystem { relabelfrom relabelto mount };
+
+kernel_read_system_state(test_mounter_t)
+kernel_read_proc_symlinks(test_mounter_t)
+kernel_request_load_module(test_mounter_t)
+kernel_search_proc(test_mounter_t)
+
+fs_getattr_xattr_fs(test_mounter_t)
+fs_relabelfrom_xattr_fs(test_mounter_t)
+
+mount_entry_type(test_mounter_t)
+mount_rw_pid_files(test_mounter_t)
+
+selinux_getattr_fs(test_mounter_t)
+
+files_mounton_all_mountpoints(test_mounter_t)
+
+# Domain with full mountedfile access
+type test_access_full_t;
+domain_type(test_access_full_t)
+
+manage_dirs_pattern(test_access_full_t, test_mountedfile_t, test_mountedfile_t)
+manage_files_pattern(test_access_full_t, test_mountedfile_t, test_mountedfile_t)
+allow test_access_full_t test_mountedfile_t:file map;
+
+corecmd_bin_entry_type(test_access_full_t)
+
+# Domain with lowerfile access, but no mountedfile access (exploiting Bug 2)
+type test_access_exploit_t;
+domain_type(test_access_exploit_t)
+
+manage_files_pattern(test_access_exploit_t, test_lowerfile_t, test_lowerfile_t)
+
+corecmd_bin_entry_type(test_access_exploit_t)
+
+# for dyntransition test_access_full_t -> test_access_exploit_t
+allow test_access_full_t self:process { setcurrent };
+allow test_access_full_t test_access_exploit_t:process { dyntransition };
+
+attribute test_domain;
+typeattribute test_mounter_t test_domain;
+typeattribute test_access_full_t test_domain;
+typeattribute test_access_exploit_t test_domain;
+
+require {
+ type TEST_TYPE;
+ role TEST_ROLE;
+}
+allow TEST_TYPE test_domain:process transition;
+role TEST_ROLE types test_domain;
+
+allow test_domain TEST_TYPE:fd use;
+allow test_domain TEST_TYPE:fifo_file rw_inherited_fifo_file_perms;
+allow test_domain TEST_TYPE:process { sigchld };
+
+files_search_tmp(test_domain)
+
+term_use_all_terms(test_domain)
+
+userdom_search_user_tmp_dirs(test_domain)
reply other threads:[~2026-06-03 5:48 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=178046568832.1.875100787970483319.tests-selinux-9a7d3d69fb0b@fedoraproject.org \
--to=omosnace@redhat.com \
--cc=git-commits@fedoraproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox