1
1
/* SPDX-License-Identifier: GPL-2.0 */
2
2
3
+ #define _GNU_SOURCE
3
4
#include <linux/limits.h>
5
+ #include <linux/sched.h>
4
6
#include <sys/types.h>
5
7
#include <sys/mman.h>
6
8
#include <sys/wait.h>
7
9
#include <unistd.h>
8
10
#include <fcntl.h>
11
+ #include <sched.h>
9
12
#include <stdio.h>
10
13
#include <errno.h>
11
14
#include <signal.h>
@@ -741,6 +744,99 @@ static int test_cgcore_lesser_euid_open(const char *root)
741
744
return ret ;
742
745
}
743
746
747
+ struct lesser_ns_open_thread_arg {
748
+ const char * path ;
749
+ int fd ;
750
+ int err ;
751
+ };
752
+
753
+ static int lesser_ns_open_thread_fn (void * arg )
754
+ {
755
+ struct lesser_ns_open_thread_arg * targ = arg ;
756
+
757
+ targ -> fd = open (targ -> path , O_RDWR );
758
+ targ -> err = errno ;
759
+ return 0 ;
760
+ }
761
+
762
+ /*
763
+ * cgroup migration permission check should be performed based on the cgroup
764
+ * namespace at the time of open instead of write.
765
+ */
766
+ static int test_cgcore_lesser_ns_open (const char * root )
767
+ {
768
+ static char stack [65536 ];
769
+ const uid_t test_euid = 65534 ; /* usually nobody, any !root is fine */
770
+ int ret = KSFT_FAIL ;
771
+ char * cg_test_a = NULL , * cg_test_b = NULL ;
772
+ char * cg_test_a_procs = NULL , * cg_test_b_procs = NULL ;
773
+ int cg_test_b_procs_fd = -1 ;
774
+ struct lesser_ns_open_thread_arg targ = { .fd = -1 };
775
+ pid_t pid ;
776
+ int status ;
777
+
778
+ cg_test_a = cg_name (root , "cg_test_a" );
779
+ cg_test_b = cg_name (root , "cg_test_b" );
780
+
781
+ if (!cg_test_a || !cg_test_b )
782
+ goto cleanup ;
783
+
784
+ cg_test_a_procs = cg_name (cg_test_a , "cgroup.procs" );
785
+ cg_test_b_procs = cg_name (cg_test_b , "cgroup.procs" );
786
+
787
+ if (!cg_test_a_procs || !cg_test_b_procs )
788
+ goto cleanup ;
789
+
790
+ if (cg_create (cg_test_a ) || cg_create (cg_test_b ))
791
+ goto cleanup ;
792
+
793
+ if (cg_enter_current (cg_test_b ))
794
+ goto cleanup ;
795
+
796
+ if (chown (cg_test_a_procs , test_euid , -1 ) ||
797
+ chown (cg_test_b_procs , test_euid , -1 ))
798
+ goto cleanup ;
799
+
800
+ targ .path = cg_test_b_procs ;
801
+ pid = clone (lesser_ns_open_thread_fn , stack + sizeof (stack ),
802
+ CLONE_NEWCGROUP | CLONE_FILES | CLONE_VM | SIGCHLD ,
803
+ & targ );
804
+ if (pid < 0 )
805
+ goto cleanup ;
806
+
807
+ if (waitpid (pid , & status , 0 ) < 0 )
808
+ goto cleanup ;
809
+
810
+ if (!WIFEXITED (status ))
811
+ goto cleanup ;
812
+
813
+ cg_test_b_procs_fd = targ .fd ;
814
+ if (cg_test_b_procs_fd < 0 )
815
+ goto cleanup ;
816
+
817
+ if (cg_enter_current (cg_test_a ))
818
+ goto cleanup ;
819
+
820
+ if ((status = write (cg_test_b_procs_fd , "0" , 1 )) >= 0 || errno != ENOENT )
821
+ goto cleanup ;
822
+
823
+ ret = KSFT_PASS ;
824
+
825
+ cleanup :
826
+ cg_enter_current (root );
827
+ if (cg_test_b_procs_fd >= 0 )
828
+ close (cg_test_b_procs_fd );
829
+ if (cg_test_b )
830
+ cg_destroy (cg_test_b );
831
+ if (cg_test_a )
832
+ cg_destroy (cg_test_a );
833
+ free (cg_test_b_procs );
834
+ free (cg_test_a_procs );
835
+ free (cg_test_b );
836
+ free (cg_test_a );
837
+ return ret ;
838
+ }
839
+
744
840
#define T (x ) { x, #x }
745
841
struct corecg_test {
746
842
int (* fn )(const char * root );
@@ -757,6 +853,7 @@ struct corecg_test {
757
853
T (test_cgcore_thread_migration ),
758
854
T (test_cgcore_destroy ),
759
855
T (test_cgcore_lesser_euid_open ),
856
+ T (test_cgcore_lesser_ns_open ),
760
857
};
761
858
#undef T
762
859
0 commit comments