selftests-improve-vmmemfd_noexec-sysctl-tests.patch removed from -mm tree
The quilt patch titled
Subject: selftests: improve vm.memfd_noexec sysctl tests
has been removed from the -mm tree. Its filename was
selftests-improve-vmmemfd_noexec-sysctl-tests.patch
This patch was dropped because it was merged into the mm-stable branch of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
------------------------------------------------------
From: Aleksa Sarai <[email protected]>
Subject: selftests: improve vm.memfd_noexec sysctl tests
Date: Mon, 14 Aug 2023 18:41:01 +1000
This adds proper tests for the nesting functionality of vm.memfd_noexec as well as some minor cleanups to spawn_*_thread().
Signed-off-by Aleksa Sarai <[email protected]>
Cc Christian Brauner <[email protected]>
Cc Daniel Verkamp <[email protected]>
Cc Dominique Martinet <[email protected]>
Cc Jeff Xu <[email protected]>
Cc Kees Cook <[email protected]>
Cc Shuah Khan <[email protected]>
Signed-off-by Andrew Morton <[email protected]>
---
tools/testing/selftests/memfd/memfd_test.c | 339 ++++++++++++++----- 1 file changed, 254 insertions(+), 85 deletions(-)
tools/testing/selftests/memfd/memfd_test.c renamed from tools/testing/selftests/memfd/memfd_test.c~selftests-improve-vmmemfd_noexec-sysctl-tests +254 -85
@@ -18,6 +18,7 @@#include <sys/syscall.h> #include <sys/wait.h> #include <unistd.h> +#include <ctype.h> #include "common.h"
@@ -43,7 +44,6 @@*/ static size_t mfd_def_size =MFD_DEF_SIZE ;static const char *memfd_str =MEMFD_STR ; -static pid_t spawn_newpid_thread (unsigned int flags,int (*fn)(void *));static int newpid_thread_fn2 (void *arg);static void join_newpid_thread (pid_t pid);
@@ -96,12 +96,12 @@ static void sysctl_assert_write(const chint fd =open ("/proc/sys/vm/memfd_noexec" ,O_WRONLY |O_CLOEXEC );if (fd <0 ) { -printf ("open sysctl failed\n" ); +printf ("open sysctl failed: %m\n" );abort (); }if (write (fd, val,strlen (val)) <0 ) { -printf ("write sysctl failed\n" ); +printf ("write sysctl %s failed: %m\n" , val);abort (); } }
@@ -111,7 +111,7 @@ static void sysctl_fail_write(const charint fd =open ("/proc/sys/vm/memfd_noexec" ,O_WRONLY |O_CLOEXEC );if (fd <0 ) { -printf ("open sysctl failed\n" ); +printf ("open sysctl failed: %m\n" );abort (); }
@@ -122,6 +122,33 @@ static void sysctl_fail_write(const char } } +static void sysctl_assert_equal (const char *val) +{ +char *p, buf[128 ] = {}; +int fd =open ("/proc/sys/vm/memfd_noexec" ,O_RDONLY |O_CLOEXEC ); + +if (fd <0 ) { +printf ("open sysctl failed: %m\n" ); +abort (); + } + +if (read (fd, buf,sizeof (buf)) <0 ) { +printf ("read sysctl failed: %m\n" ); +abort (); + } + +/* Strip trailing whitespace. */ + p = buf; +while (!isspace (*p)) + p++; + *p ='\0' ; + +if (strcmp (buf, val) !=0 ) { +printf ("unexpected sysctl value: expected %s, got %s\n" , val, buf); +abort (); + } +} +static int mfd_assert_reopen_fd (int fd_in) {int fd;
@@ -736,7 +763,7 @@ static int idle_thread_fn(void *arg)return 0 ; } -static pid_t spawn_idle_thread (unsigned int flags) +static pid_t spawn_thread (unsigned int flags,int (*fn)(void *),void *arg) {uint8_t *stack;pid_t pid;
@@ -747,10 +774,7 @@ static pid_t spawn_idle_thread(unsignedabort (); } - pid =clone (idle_thread_fn, - stack +STACK_SIZE , -SIGCHLD | flags, -NULL ); + pid =clone (fn, stack +STACK_SIZE ,SIGCHLD | flags, arg);if (pid <0 ) {printf ("clone() failed: %m\n" );abort ();
@@ -759,6 +783,33 @@ static pid_t spawn_idle_thread(unsignedreturn pid; } +static void join_thread (pid_t pid) +{ +int wstatus; + +if (waitpid (pid, &wstatus,0 ) <0 ) { +printf ("newpid thread: waitpid() failed: %m\n" ); +abort (); + } + +if (WIFEXITED (wstatus) &&WEXITSTATUS (wstatus) !=0 ) { +printf ("newpid thread: exited with non-zero error code %d\n" , +WEXITSTATUS (wstatus)); +abort (); + } + +if (WIFSIGNALED (wstatus)) { +printf ("newpid thread: killed by signal %d\n" , +WTERMSIG (wstatus)); +abort (); + } +} + +static pid_t spawn_idle_thread (unsigned int flags) +{ +return spawn_thread (flags, idle_thread_fn,NULL ); +} +static void join_idle_thread (pid_t pid) {kill (pid,SIGTERM );
@@ -1111,42 +1162,69 @@ static void test_noexec_seal(void)close (fd); } -static void test_sysctl_child (void ) +static void test_sysctl_sysctl0 (void ) {int fd; -int pid; -printf ("%s sysctl 0\n" , memfd_str); -sysctl_assert_write ("0" ); - fd =mfd_assert_new ("kern_memfd_sysctl_0" , +sysctl_assert_equal ("0" ); + + fd =mfd_assert_new ("kern_memfd_sysctl_0_dfl" , mfd_def_size,MFD_CLOEXEC |MFD_ALLOW_SEALING ); -mfd_assert_mode (fd,0777 );mfd_assert_has_seals (fd,0 );mfd_assert_chmod (fd,0644 );close (fd); +} -printf ("%s sysctl 1\n" , memfd_str); -sysctl_assert_write ("1" ); - fd =mfd_assert_new ("kern_memfd_sysctl_1" , +static void test_sysctl_set_sysctl0 (void ) +{ +sysctl_assert_write ("0" ); +test_sysctl_sysctl0 (); +} + +static void test_sysctl_sysctl1 (void ) +{ +int fd; + +sysctl_assert_equal ("1" ); + + fd =mfd_assert_new ("kern_memfd_sysctl_1_dfl" , mfd_def_size,MFD_CLOEXEC |MFD_ALLOW_SEALING ); +mfd_assert_mode (fd,0666 ); +mfd_assert_has_seals (fd,F_SEAL_EXEC ); +mfd_fail_chmod (fd,0777 ); +close (fd); -printf ("%s child ns\n" , memfd_str); - pid =spawn_newpid_thread (CLONE_NEWPID , newpid_thread_fn2); -join_newpid_thread (pid); + fd =mfd_assert_new ("kern_memfd_sysctl_1_exec" , + mfd_def_size, +MFD_CLOEXEC |MFD_EXEC |MFD_ALLOW_SEALING ); +mfd_assert_mode (fd,0777 ); +mfd_assert_has_seals (fd,0 ); +mfd_assert_chmod (fd,0644 ); +close (fd); + fd =mfd_assert_new ("kern_memfd_sysctl_1_noexec" , + mfd_def_size, +MFD_CLOEXEC |MFD_NOEXEC_SEAL |MFD_ALLOW_SEALING );mfd_assert_mode (fd,0666 );mfd_assert_has_seals (fd,F_SEAL_EXEC );mfd_fail_chmod (fd,0777 ); -sysctl_fail_write ("0" );close (fd); +} -printf ("%s sysctl 2\n" , memfd_str); -sysctl_assert_write ("2" ); -mfd_fail_new ("kern_memfd_sysctl_2_exec" , -MFD_EXEC |MFD_CLOEXEC |MFD_ALLOW_SEALING ); +static void test_sysctl_set_sysctl1 (void ) +{ +sysctl_assert_write ("1" ); +test_sysctl_sysctl1 (); +} + +static void test_sysctl_sysctl2 (void ) +{ +int fd; + +sysctl_assert_equal ("2" ); fd = mfd_assert_new("kern_memfd_sysctl_2_dfl", mfd_def_size,
@@ -1156,98 +1234,188 @@ static void test_sysctl_child(void)mfd_fail_chmod (fd,0777 );close (fd); - fd =mfd_assert_new ("kern_memfd_sysctl_2_noexec_seal" , +mfd_fail_new ("kern_memfd_sysctl_2_exec" , +MFD_CLOEXEC |MFD_EXEC |MFD_ALLOW_SEALING ); + + fd =mfd_assert_new ("kern_memfd_sysctl_2_noexec" , mfd_def_size, -MFD_NOEXEC_SEAL |MFD_CLOEXEC |MFD_ALLOW_SEALING ); +MFD_CLOEXEC |MFD_NOEXEC_SEAL |MFD_ALLOW_SEALING );mfd_assert_mode (fd,0666 );mfd_assert_has_seals (fd,F_SEAL_EXEC );mfd_fail_chmod (fd,0777 );close (fd); - -sysctl_fail_write ("0" ); -sysctl_fail_write ("1" ); } -static int newpid_thread_fn (void *arg) +static void test_sysctl_set_sysctl2 (void ) { -test_sysctl_child (); -return 0 ; +sysctl_assert_write ("2" ); +test_sysctl_sysctl2 (); } -static void test_sysctl_child2 (void ) +static int sysctl_simple_child (void *arg) {int fd; +int pid; -sysctl_fail_write ("0" ); - fd =mfd_assert_new ("kern_memfd_sysctl_1" , - mfd_def_size, -MFD_CLOEXEC |MFD_ALLOW_SEALING ); +printf ("%s sysctl 0\n" , memfd_str); +test_sysctl_set_sysctl0 (); -mfd_assert_mode (fd,0666 ); -mfd_assert_has_seals (fd,F_SEAL_EXEC ); -mfd_fail_chmod (fd,0777 ); -close (fd); +printf ("%s sysctl 1\n" , memfd_str); +test_sysctl_set_sysctl1 (); + +printf ("%s sysctl 0\n" , memfd_str); +test_sysctl_set_sysctl0 (); + +printf ("%s sysctl 2\n" , memfd_str); +test_sysctl_set_sysctl2 (); + +printf ("%s sysctl 1\n" , memfd_str); +test_sysctl_set_sysctl1 (); + +printf ("%s sysctl 0\n" , memfd_str); +test_sysctl_set_sysctl0 (); + +return 0 ; +} + +/* +* Test sysctl +* A very basic test to make sure the core sysctl semantics work. +*/ +static void test_sysctl_simple (void ) +{ +int pid =spawn_thread (CLONE_NEWPID , sysctl_simple_child,NULL ); + +join_thread (pid); } -static int newpid_thread_fn2 (void *arg) +static int sysctl_nested (void *arg) { -test_sysctl_child2 (); +void (*fn)(void ) = arg; + +fn ();return 0 ; } -static pid_t spawn_newpid_thread (unsigned int flags,int (*fn)(void *)) + +static int sysctl_nested_wait (void *arg) { -uint8_t *stack; -pid_t pid; +/* Wait for a SIGCONT. */ +kill (getpid (),SIGSTOP ); +return sysctl_nested (arg); +} - stack =malloc (STACK_SIZE ); -if (!stack) { -printf ("malloc(STACK_SIZE) failed: %m\n" ); -abort (); - } +static void test_sysctl_sysctl1_failset (void ) +{ +sysctl_fail_write ("0" ); +test_sysctl_sysctl1 (); +} - pid =clone (fn, - stack +STACK_SIZE , -SIGCHLD | flags, -NULL ); -if (pid <0 ) { -printf ("clone() failed: %m\n" ); -abort (); - } +static void test_sysctl_sysctl2_failset (void ) +{ +sysctl_fail_write ("1" ); +test_sysctl_sysctl2 (); -return pid; +sysctl_fail_write ("0" ); +test_sysctl_sysctl2 (); } -static void join_newpid_thread (pid_t pid) +static int sysctl_nested_child (void *arg) { -int wstatus; +int fd; +int pid; -if (waitpid (pid, &wstatus,0 ) <0 ) { -printf ("newpid thread: waitpid() failed: %m\n" ); -abort (); - } +printf ("%s nested sysctl 0\n" , memfd_str); +sysctl_assert_write ("0" ); +/* A further nested pidns works the same. */ + pid =spawn_thread (CLONE_NEWPID , sysctl_simple_child,NULL ); +join_thread (pid); -if (WIFEXITED (wstatus) &&WEXITSTATUS (wstatus) !=0 ) { -printf ("newpid thread: exited with non-zero error code %d\n" , -WEXITSTATUS (wstatus)); -abort (); - } +printf ("%s nested sysctl 1\n" , memfd_str); +sysctl_assert_write ("1" ); +/* Child inherits our setting. */ + pid =spawn_thread (CLONE_NEWPID , sysctl_nested, test_sysctl_sysctl1); +join_thread (pid); +/* Child cannot raise the setting. */ + pid =spawn_thread (CLONE_NEWPID , sysctl_nested, + test_sysctl_sysctl1_failset); +join_thread (pid); +/* Child can lower the setting. */ + pid =spawn_thread (CLONE_NEWPID , sysctl_nested, + test_sysctl_set_sysctl2); +join_thread (pid); +/* Child lowering the setting has no effect on our setting. */ +test_sysctl_sysctl1 (); -if (WIFSIGNALED (wstatus)) { -printf ("newpid thread: killed by signal %d\n" , -WTERMSIG (wstatus)); -abort (); - } +printf ("%s nested sysctl 2\n" , memfd_str); +sysctl_assert_write ("2" ); +/* Child inherits our setting. */ + pid =spawn_thread (CLONE_NEWPID , sysctl_nested, test_sysctl_sysctl2); +join_thread (pid); +/* Child cannot raise the setting. */ + pid =spawn_thread (CLONE_NEWPID , sysctl_nested, + test_sysctl_sysctl2_failset); +join_thread (pid); + +/* Verify that the rules are actually inherited after fork. */ +printf ("%s nested sysctl 0 -> 1 after fork\n" , memfd_str); +sysctl_assert_write ("0" ); + + pid =spawn_thread (CLONE_NEWPID , sysctl_nested_wait, + test_sysctl_sysctl1_failset); +sysctl_assert_write ("1" ); +kill (pid,SIGCONT ); +join_thread (pid); + +printf ("%s nested sysctl 0 -> 2 after fork\n" , memfd_str); +sysctl_assert_write ("0" ); + + pid =spawn_thread (CLONE_NEWPID , sysctl_nested_wait, + test_sysctl_sysctl2_failset); +sysctl_assert_write ("2" ); +kill (pid,SIGCONT ); +join_thread (pid); + +/* +* Verify that the current effective setting is saved on fork, meaning +* that the parent lowering the sysctl doesn't affect already-forked +* children. +*/ +printf ("%s nested sysctl 2 -> 1 after fork\n" , memfd_str); +sysctl_assert_write ("2" ); + pid =spawn_thread (CLONE_NEWPID , sysctl_nested_wait, + test_sysctl_sysctl2); +sysctl_assert_write ("1" ); +kill (pid,SIGCONT ); +join_thread (pid); + +printf ("%s nested sysctl 2 -> 0 after fork\n" , memfd_str); +sysctl_assert_write ("2" ); + pid =spawn_thread (CLONE_NEWPID , sysctl_nested_wait, + test_sysctl_sysctl2); +sysctl_assert_write ("0" ); +kill (pid,SIGCONT ); +join_thread (pid); + +printf ("%s nested sysctl 1 -> 0 after fork\n" , memfd_str); +sysctl_assert_write ("1" ); + pid =spawn_thread (CLONE_NEWPID , sysctl_nested_wait, + test_sysctl_sysctl1); +sysctl_assert_write ("0" ); +kill (pid,SIGCONT ); +join_thread (pid); + +return 0 ; }/* -* Test sysctl -* A very basic sealing test to see whether setting/retrieving seals works. +* Test sysctl with nested pid namespaces +* Make sure that the sysctl nesting semantics work correctly. */ -static void test_sysctl (void ) +static void test_sysctl_nested (void ) { -int pid =spawn_newpid_thread (CLONE_NEWPID , newpid_thread_fn); +int pid =spawn_thread (CLONE_NEWPID , sysctl_nested_child,NULL ); -join_newpid_thread (pid); +join_thread (pid); }/*
@@ -1433,6 +1601,9 @@ int main(int argc, char **argv)test_seal_grow ();test_seal_resize (); +test_sysctl_simple (); +test_sysctl_nested (); +test_share_dup ("SHARE-DUP" ,"" );test_share_mmap ("SHARE-MMAP" ,"" );test_share_open ("SHARE-OPEN" ,"" );
@@ -1447,8 +1618,6 @@ int main(int argc, char **argv)test_share_fork ("SHARE-FORK" ,SHARED_FT_STR );join_idle_thread (pid); -test_sysctl (); -printf ("memfd: DONE\n" );return 0 ;
_
Patches currently in -mm which might be from [email protected] are