diff mbox series

tests/secretmem: add test

Message ID 20220831145611.707958-1-cgzones@googlemail.com (mailing list archive)
State Superseded
Headers show
Series tests/secretmem: add test | expand

Commit Message

Christian Göttsche Aug. 31, 2022, 2:56 p.m. UTC
Add test for memfd_secret(2) anonymous inodes check added in 6.0 via
2bfe15c52612 ("mm: create security context for memfd_secret inodes").

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
 .github/workflows/checks.yml |  4 ++
 Vagrantfile                  | 10 +++--
 policy/Makefile              |  4 ++
 policy/test_secretmem.te     | 33 ++++++++++++++
 tests/Makefile               |  5 +++
 tests/secretmem/.gitignore   |  1 +
 tests/secretmem/Makefile     |  5 +++
 tests/secretmem/secretmem.c  | 83 ++++++++++++++++++++++++++++++++++++
 tests/secretmem/test         | 39 +++++++++++++++++
 9 files changed, 180 insertions(+), 4 deletions(-)
 create mode 100644 policy/test_secretmem.te
 create mode 100644 tests/secretmem/.gitignore
 create mode 100644 tests/secretmem/Makefile
 create mode 100644 tests/secretmem/secretmem.c
 create mode 100755 tests/secretmem/test
diff mbox series

Patch

diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml
index 714bb49..ae81925 100644
--- a/.github/workflows/checks.yml
+++ b/.github/workflows/checks.yml
@@ -38,6 +38,10 @@  jobs:
         run: vagrant up
       - name: Wait for the machine to come up if rebooting
         run: while ! vagrant ssh -- true; do sleep 1; done
+      - name: Show Vagrant VM details
+        run: |
+          vagrant ssh -- uname -a
+          vagrant ssh -- cat /proc/cmdline
       - name: Run SELinux testsuite
         run: vagrant ssh -- sudo make -C /root/testsuite test
       - name: Check unwanted denials
diff --git a/Vagrantfile b/Vagrantfile
index f73586c..6f7675f 100644
--- a/Vagrantfile
+++ b/Vagrantfile
@@ -37,15 +37,12 @@  Vagrant.configure("2") do |config|
   when 'default'
     dnf_opts = ''
     kernel_pkgs = 'kernel-devel-"$(uname -r)" kernel-modules-"$(uname -r)"'
-    reboot_cmd = ''
   when 'latest'
     dnf_opts = ''
     kernel_pkgs = 'kernel-devel kernel-modules'
-    reboot_cmd = 'reboot'
   when 'secnext'
     dnf_opts = '--nogpgcheck --releasever rawhide --repofrompath kernel-secnext,https://repo.paul-moore.com/rawhide/x86_64'
     kernel_pkgs = 'kernel-devel kernel-modules'
-    reboot_cmd = 'reboot'
   else
     print("Invalid KERNEL_TYPE '#{ENV['KERNEL_TYPE']}'")
     abort
@@ -93,7 +90,12 @@  EOF
       jfsutils \
       dosfstools \
       #{kernel_pkgs}
+
     #{extra_commands}
-    #{reboot_cmd}
+
+    # for secretmem test
+    grubby --update-kernel=ALL --args=secretmem.enable=1
+
+    reboot
 SCRIPT
 end
diff --git a/policy/Makefile b/policy/Makefile
index b6f2f32..403802b 100644
--- a/policy/Makefile
+++ b/policy/Makefile
@@ -162,6 +162,10 @@  ifeq (x$(DISTRO),$(filter x$(DISTRO),xRHEL4 xRHEL5 xRHEL6))
 TARGETS:=$(filter-out test_overlayfs.te test_mqueue.te test_ibpkey.te, $(TARGETS))
 endif
 
+ifeq ($(shell grep -q anon_inode $(POLDEV)/include/support/all_perms.spt && echo true),true)
+TARGETS += test_secretmem.te
+endif
+
 all: build
 
 expand_check:
diff --git a/policy/test_secretmem.te b/policy/test_secretmem.te
new file mode 100644
index 0000000..357f41d
--- /dev/null
+++ b/policy/test_secretmem.te
@@ -0,0 +1,33 @@ 
+#################################
+#
+# Policy for testing secretmem operations
+#
+
+# Private type for secret memory
+type test_secretmem_inode_t;
+
+# Domain not allowed to create secret memory
+type test_nocreate_secretmem_t;
+testsuite_domain_type_minimal(test_nocreate_secretmem_t)
+
+# Domain allowed to create secret memory with the own domain type
+type test_create_secretmem_t;
+testsuite_domain_type_minimal(test_create_secretmem_t)
+allow test_create_secretmem_t self:anon_inode create;
+
+# Domain allowed to create secret memory with the own domain type and allowed to map WX
+type test_create_wx_secretmem_t;
+testsuite_domain_type_minimal(test_create_wx_secretmem_t)
+allow test_create_wx_secretmem_t self:anon_inode create;
+allow test_create_wx_secretmem_t self:process execmem;
+
+# Domain not allowed to create secret memory via a type transition to a private type
+type test_nocreate_transition_secretmem_t;
+testsuite_domain_type_minimal(test_nocreate_transition_secretmem_t)
+type_transition test_nocreate_transition_secretmem_t test_nocreate_transition_secretmem_t:anon_inode test_secretmem_inode_t "[secretmem]";
+
+# Domain allowed to create secret memory via a type transition to a private type
+type test_create_transition_secretmem_t;
+testsuite_domain_type_minimal(test_create_transition_secretmem_t)
+type_transition test_create_transition_secretmem_t test_create_transition_secretmem_t:anon_inode test_secretmem_inode_t "[secretmem]";
+allow test_create_transition_secretmem_t test_secretmem_inode_t:anon_inode create;
diff --git a/tests/Makefile b/tests/Makefile
index 8abd438..b50cbc6 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -145,6 +145,11 @@  SUBDIRS += vsock_socket
 endif
 endif
 
+# memfd_secret(2) is available since 5.14, but only confined since 6.0
+ifneq ($(shell ./kvercmp $$(uname -r) 6.0),-1)
+SUBDIRS += secretmem
+endif
+
 ifeq ($(DISTRO),RHEL4)
     SUBDIRS:=$(filter-out bounds dyntrace dyntrans inet_socket mmap nnp_nosuid overlay unix_socket, $(SUBDIRS))
 endif
diff --git a/tests/secretmem/.gitignore b/tests/secretmem/.gitignore
new file mode 100644
index 0000000..17e1c19
--- /dev/null
+++ b/tests/secretmem/.gitignore
@@ -0,0 +1 @@ 
+secretmem
diff --git a/tests/secretmem/Makefile b/tests/secretmem/Makefile
new file mode 100644
index 0000000..c27d5f0
--- /dev/null
+++ b/tests/secretmem/Makefile
@@ -0,0 +1,5 @@ 
+TARGETS=secretmem
+
+all: $(TARGETS)
+clean:
+	rm -f $(TARGETS)
diff --git a/tests/secretmem/secretmem.c b/tests/secretmem/secretmem.c
new file mode 100644
index 0000000..93553a7
--- /dev/null
+++ b/tests/secretmem/secretmem.c
@@ -0,0 +1,83 @@ 
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_memfd_secret
+# define __NR_memfd_secret 447
+#endif
+
+#define TEXT "Hello World!\nHello World!\nHello World!\nHello World!\nHello World!\nHello World!\n"
+
+static int _memfd_secret(unsigned long flags)
+{
+	return syscall(__NR_memfd_secret, flags);
+}
+
+int main(int argc, const char *argv[])
+{
+	long page_size;
+	int fd, flags;
+	char *mem;
+	bool check = (argc == 2 && strcmp(argv[1], "check") == 0);
+	bool wx = (argc == 2 && strcmp(argv[1], "wx") == 0);
+
+	page_size = sysconf(_SC_PAGESIZE);
+	if (page_size <= 0) {
+		fprintf(stderr, "failed to get pagesize, got %ld:  %s\n", page_size,
+			strerror(errno));
+		return EXIT_FAILURE;
+	}
+
+	fd = _memfd_secret(0);
+	if (fd < 0) {
+		printf("memfd_secret() failed:  %s\n", strerror(errno));
+		if (check && errno != ENOSYS)
+			return EXIT_SUCCESS;
+
+		return EXIT_FAILURE;
+	}
+
+	if (check)
+		return EXIT_SUCCESS;
+
+	if (ftruncate(fd, page_size) < 0) {
+		fprintf(stderr, "ftruncate failed:  %s\n", strerror(errno));
+	}
+
+	flags = PROT_READ | PROT_WRITE;
+	if (wx)
+		flags |= PROT_EXEC;
+
+	mem = mmap(NULL, page_size, flags, MAP_SHARED, fd, 0);
+	if (mem == MAP_FAILED || !mem) {
+		fprintf(stderr, "unable to mmap secret memory:  %s\n", strerror(errno));
+		close(fd);
+		return EXIT_FAILURE;
+	}
+
+	close(fd);
+
+	memcpy(mem, TEXT, sizeof TEXT);
+
+	if (memcmp(mem, TEXT, sizeof TEXT) != 0) {
+		fprintf(stderr, "data not synced (1)\n");
+		munmap(mem, page_size);
+		return EXIT_FAILURE;
+	}
+
+	if (strlen(mem) + 1 != sizeof TEXT) {
+		fprintf(stderr, "data not synced (2)\n");
+		munmap(mem, page_size);
+		return EXIT_FAILURE;
+	}
+
+	munmap(mem, page_size);
+
+	return EXIT_SUCCESS;
+}
diff --git a/tests/secretmem/test b/tests/secretmem/test
new file mode 100755
index 0000000..d17d423
--- /dev/null
+++ b/tests/secretmem/test
@@ -0,0 +1,39 @@ 
+#!/usr/bin/perl
+
+use Test::More;
+
+BEGIN {
+    $basedir = $0;
+    $basedir =~ s|(.*)/[^/]*|$1|;
+
+    $result =
+      system "runcon -t test_nocreate_secretmem_t $basedir/secretmem check";
+    if ( $result ne 0 ) {
+        plan skip_all => "memfd_secret(2) not available";
+    }
+    else {
+        plan tests => 6;
+    }
+}
+
+$result = system "runcon -t test_nocreate_secretmem_t $basedir/secretmem";
+ok( $result >> 8 eq 1 );
+
+$result = system "runcon -t test_create_secretmem_t $basedir/secretmem";
+ok( $result eq 0 );
+
+$result = system "runcon -t test_create_secretmem_t $basedir/secretmem wx";
+ok( $result >> 8 eq 1 );
+
+$result = system "runcon -t test_create_wx_secretmem_t $basedir/secretmem wx";
+ok( $result >> 8 eq 1 );
+
+$result =
+  system "runcon -t test_nocreate_transition_secretmem_t $basedir/secretmem";
+ok( $result >> 8 eq 1 );
+
+$result =
+  system "runcon -t test_create_transition_secretmem_t $basedir/secretmem";
+ok( $result eq 0 );
+
+exit;