77#include <inttypes.h>
88#include <linux/types.h>
99#include <linux/sched.h>
10+ #include <stdbool.h>
1011#include <stdint.h>
1112#include <stdio.h>
1213#include <stdlib.h>
@@ -103,8 +104,8 @@ static int call_clone3(uint64_t flags, size_t size, enum test_mode test_mode)
103104 return 0 ;
104105}
105106
106- static void test_clone3 (uint64_t flags , size_t size , int expected ,
107- enum test_mode test_mode )
107+ static bool test_clone3 (uint64_t flags , size_t size , int expected ,
108+ enum test_mode test_mode )
108109{
109110 int ret ;
110111
@@ -114,92 +115,210 @@ static void test_clone3(uint64_t flags, size_t size, int expected,
114115 ret = call_clone3 (flags , size , test_mode );
115116 ksft_print_msg ("[%d] clone3() with flags says: %d expected %d\n" ,
116117 getpid (), ret , expected );
117- if (ret != expected )
118- ksft_test_result_fail (
118+ if (ret != expected ) {
119+ ksft_print_msg (
119120 "[%d] Result (%d) is different than expected (%d)\n" ,
120121 getpid (), ret , expected );
121- else
122- ksft_test_result_pass (
123- "[%d] Result (%d) matches expectation (%d)\n" ,
124- getpid (), ret , expected );
125- }
126-
127- int main (int argc , char * argv [])
128- {
129- uid_t uid = getuid ();
130-
131- ksft_print_header ();
132- ksft_set_plan (19 );
133- test_clone3_supported ();
134-
135- /* Just a simple clone3() should return 0.*/
136- test_clone3 (0 , 0 , 0 , CLONE3_ARGS_NO_TEST );
137-
138- /* Do a clone3() in a new PID NS.*/
139- if (uid == 0 )
140- test_clone3 (CLONE_NEWPID , 0 , 0 , CLONE3_ARGS_NO_TEST );
141- else
142- ksft_test_result_skip ("Skipping clone3() with CLONE_NEWPID\n" );
143-
144- /* Do a clone3() with CLONE_ARGS_SIZE_VER0. */
145- test_clone3 (0 , CLONE_ARGS_SIZE_VER0 , 0 , CLONE3_ARGS_NO_TEST );
146-
147- /* Do a clone3() with CLONE_ARGS_SIZE_VER0 - 8 */
148- test_clone3 (0 , CLONE_ARGS_SIZE_VER0 - 8 , - EINVAL , CLONE3_ARGS_NO_TEST );
149-
150- /* Do a clone3() with sizeof(struct clone_args) + 8 */
151- test_clone3 (0 , sizeof (struct __clone_args ) + 8 , 0 , CLONE3_ARGS_NO_TEST );
152-
153- /* Do a clone3() with exit_signal having highest 32 bits non-zero */
154- test_clone3 (0 , 0 , - EINVAL , CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG );
122+ return false;
123+ }
155124
156- /* Do a clone3() with negative 32-bit exit_signal */
157- test_clone3 ( 0 , 0 , - EINVAL , CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG );
125+ return true;
126+ }
158127
159- /* Do a clone3() with exit_signal not fitting into CSIGNAL mask */
160- test_clone3 ( 0 , 0 , - EINVAL , CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG );
128+ typedef bool ( * filter_function )( void );
129+ typedef size_t ( * size_function )( void );
161130
162- /* Do a clone3() with NSIG < exit_signal < CSIG */
163- test_clone3 (0 , 0 , - EINVAL , CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG );
131+ static bool not_root (void )
132+ {
133+ if (getuid () != 0 ) {
134+ ksft_print_msg ("Not running as root\n" );
135+ return true;
136+ }
164137
165- test_clone3 (0 , sizeof (struct __clone_args ) + 8 , 0 , CLONE3_ARGS_ALL_0 );
138+ return false;
139+ }
166140
167- test_clone3 (0 , sizeof (struct __clone_args ) + 16 , - E2BIG ,
168- CLONE3_ARGS_ALL_0 );
141+ static size_t page_size_plus_8 (void )
142+ {
143+ return getpagesize () + 8 ;
144+ }
169145
170- test_clone3 (0 , sizeof (struct __clone_args ) * 2 , - E2BIG ,
171- CLONE3_ARGS_ALL_0 );
146+ struct test {
147+ const char * name ;
148+ uint64_t flags ;
149+ size_t size ;
150+ size_function size_function ;
151+ int expected ;
152+ enum test_mode test_mode ;
153+ filter_function filter ;
154+ };
172155
173- /* Do a clone3() with > page size */
174- test_clone3 (0 , getpagesize () + 8 , - E2BIG , CLONE3_ARGS_NO_TEST );
156+ static const struct test tests [] = {
157+ {
158+ .name = "simple clone3()" ,
159+ .flags = 0 ,
160+ .size = 0 ,
161+ .expected = 0 ,
162+ .test_mode = CLONE3_ARGS_NO_TEST ,
163+ },
164+ {
165+ .name = "clone3() in a new PID_NS" ,
166+ .flags = CLONE_NEWPID ,
167+ .size = 0 ,
168+ .expected = 0 ,
169+ .test_mode = CLONE3_ARGS_NO_TEST ,
170+ .filter = not_root ,
171+ },
172+ {
173+ .name = "CLONE_ARGS_SIZE_VER0" ,
174+ .flags = 0 ,
175+ .size = CLONE_ARGS_SIZE_VER0 ,
176+ .expected = 0 ,
177+ .test_mode = CLONE3_ARGS_NO_TEST ,
178+ },
179+ {
180+ .name = "CLONE_ARGS_SIZE_VER0 - 8" ,
181+ .flags = 0 ,
182+ .size = CLONE_ARGS_SIZE_VER0 - 8 ,
183+ .expected = - EINVAL ,
184+ .test_mode = CLONE3_ARGS_NO_TEST ,
185+ },
186+ {
187+ .name = "sizeof(struct clone_args) + 8" ,
188+ .flags = 0 ,
189+ .size = sizeof (struct __clone_args ) + 8 ,
190+ .expected = 0 ,
191+ .test_mode = CLONE3_ARGS_NO_TEST ,
192+ },
193+ {
194+ .name = "exit_signal with highest 32 bits non-zero" ,
195+ .flags = 0 ,
196+ .size = 0 ,
197+ .expected = - EINVAL ,
198+ .test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG ,
199+ },
200+ {
201+ .name = "negative 32-bit exit_signal" ,
202+ .flags = 0 ,
203+ .size = 0 ,
204+ .expected = - EINVAL ,
205+ .test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG ,
206+ },
207+ {
208+ .name = "exit_signal not fitting into CSIGNAL mask" ,
209+ .flags = 0 ,
210+ .size = 0 ,
211+ .expected = - EINVAL ,
212+ .test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG ,
213+ },
214+ {
215+ .name = "NSIG < exit_signal < CSIG" ,
216+ .flags = 0 ,
217+ .size = 0 ,
218+ .expected = - EINVAL ,
219+ .test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG ,
220+ },
221+ {
222+ .name = "Arguments sizeof(struct clone_args) + 8" ,
223+ .flags = 0 ,
224+ .size = sizeof (struct __clone_args ) + 8 ,
225+ .expected = 0 ,
226+ .test_mode = CLONE3_ARGS_ALL_0 ,
227+ },
228+ {
229+ .name = "Arguments sizeof(struct clone_args) + 16" ,
230+ .flags = 0 ,
231+ .size = sizeof (struct __clone_args ) + 16 ,
232+ .expected = - E2BIG ,
233+ .test_mode = CLONE3_ARGS_ALL_0 ,
234+ },
235+ {
236+ .name = "Arguments sizeof(struct clone_arg) * 2" ,
237+ .flags = 0 ,
238+ .size = sizeof (struct __clone_args ) + 16 ,
239+ .expected = - E2BIG ,
240+ .test_mode = CLONE3_ARGS_ALL_0 ,
241+ },
242+ {
243+ .name = "Arguments > page size" ,
244+ .flags = 0 ,
245+ .size_function = page_size_plus_8 ,
246+ .expected = - E2BIG ,
247+ .test_mode = CLONE3_ARGS_NO_TEST ,
248+ },
249+ {
250+ .name = "CLONE_ARGS_SIZE_VER0 in a new PID NS" ,
251+ .flags = CLONE_NEWPID ,
252+ .size = CLONE_ARGS_SIZE_VER0 ,
253+ .expected = 0 ,
254+ .test_mode = CLONE3_ARGS_NO_TEST ,
255+ .filter = not_root ,
256+ },
257+ {
258+ .name = "CLONE_ARGS_SIZE_VER0 - 8 in a new PID NS" ,
259+ .flags = CLONE_NEWPID ,
260+ .size = CLONE_ARGS_SIZE_VER0 - 8 ,
261+ .expected = - EINVAL ,
262+ .test_mode = CLONE3_ARGS_NO_TEST ,
263+ },
264+ {
265+ .name = "sizeof(struct clone_args) + 8 in a new PID NS" ,
266+ .flags = CLONE_NEWPID ,
267+ .size = sizeof (struct __clone_args ) + 8 ,
268+ .expected = 0 ,
269+ .test_mode = CLONE3_ARGS_NO_TEST ,
270+ .filter = not_root ,
271+ },
272+ {
273+ .name = "Arguments > page size in a new PID NS" ,
274+ .flags = CLONE_NEWPID ,
275+ .size_function = page_size_plus_8 ,
276+ .expected = - E2BIG ,
277+ .test_mode = CLONE3_ARGS_NO_TEST ,
278+ },
279+ {
280+ .name = "New time NS" ,
281+ .flags = CLONE_NEWTIME ,
282+ .size = 0 ,
283+ .expected = 0 ,
284+ .test_mode = CLONE3_ARGS_NO_TEST ,
285+ },
286+ {
287+ .name = "exit signal (SIGCHLD) in flags" ,
288+ .flags = SIGCHLD ,
289+ .size = 0 ,
290+ .expected = - EINVAL ,
291+ .test_mode = CLONE3_ARGS_NO_TEST ,
292+ },
293+ };
175294
176- /* Do a clone3() with CLONE_ARGS_SIZE_VER0 in a new PID NS. */
177- if (uid == 0 )
178- test_clone3 (CLONE_NEWPID , CLONE_ARGS_SIZE_VER0 , 0 ,
179- CLONE3_ARGS_NO_TEST );
180- else
181- ksft_test_result_skip ("Skipping clone3() with CLONE_NEWPID\n" );
295+ int main (int argc , char * argv [])
296+ {
297+ size_t size ;
298+ int i ;
182299
183- /* Do a clone3() with CLONE_ARGS_SIZE_VER0 - 8 in a new PID NS */
184- test_clone3 ( CLONE_NEWPID , CLONE_ARGS_SIZE_VER0 - 8 , - EINVAL ,
185- CLONE3_ARGS_NO_TEST );
300+ ksft_print_header ();
301+ ksft_set_plan ( ARRAY_SIZE ( tests ));
302+ test_clone3_supported ( );
186303
187- /* Do a clone3() with sizeof(struct clone_args) + 8 in a new PID NS */
188- if (uid == 0 )
189- test_clone3 (CLONE_NEWPID , sizeof (struct __clone_args ) + 8 , 0 ,
190- CLONE3_ARGS_NO_TEST );
191- else
192- ksft_test_result_skip ("Skipping clone3() with CLONE_NEWPID\n" );
304+ for (i = 0 ; i < ARRAY_SIZE (tests ); i ++ ) {
305+ if (tests [i ].filter && tests [i ].filter ()) {
306+ ksft_test_result_skip ("%s\n" , tests [i ].name );
307+ continue ;
308+ }
193309
194- /* Do a clone3() with > page size in a new PID NS */
195- test_clone3 (CLONE_NEWPID , getpagesize () + 8 , - E2BIG ,
196- CLONE3_ARGS_NO_TEST );
310+ if (tests [i ].size_function )
311+ size = tests [i ].size_function ();
312+ else
313+ size = tests [i ].size ;
197314
198- /* Do a clone3() in a new time namespace */
199- test_clone3 (CLONE_NEWTIME , 0 , 0 , CLONE3_ARGS_NO_TEST );
315+ ksft_print_msg ("Running test '%s'\n" , tests [i ].name );
200316
201- /* Do a clone3() with exit signal (SIGCHLD) in flags */
202- test_clone3 (SIGCHLD , 0 , - EINVAL , CLONE3_ARGS_NO_TEST );
317+ ksft_test_result (test_clone3 (tests [i ].flags , size ,
318+ tests [i ].expected ,
319+ tests [i ].test_mode ),
320+ "%s\n" , tests [i ].name );
321+ }
203322
204323 ksft_finished ();
205324}
0 commit comments