master
c 619 lines 13.2 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 execve.c
8
9 Abstract:
10
11 This file contains the execve tests.
12
13 --*/
14
15 #include "lxtcommon.h"
16 #include "unittests.h"
17 #include <pthread.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <sys/wait.h>
23 #include <linux/binfmts.h>
24 #include "lxtutil.h"
25
26 #define LXT_NAME "Execve"
27
28 #define LXT_EXECV_TEST_DIRECTORY "/data/test/execvDir"
29
30 int ExecveExecValidate(char* Path);
31
32 int ExecveValidate(int ExpectedPid);
33
34 int ExecveVariationArguments(PLXT_ARGS Args);
35
36 int ExecveVariationSingle(PLXT_ARGS Args);
37
38 int ExecveVariationMultipleWithThreads(PLXT_ARGS Args);
39
40 int ExecveWaitForChild(void);
41
42 void* ExecveWorkerThread(void* Arg);
43
44 void* ExecveWorkerThread2(void* Arg);
45
46 //
47 // Global constants
48 //
49
50 static const LXT_VARIATION g_LxtVariations[] = {
51 {"Execve - Single", ExecveVariationSingle},
52 {"Execve - Multiple with threads", ExecveVariationMultipleWithThreads},
53 {"Execve - Arguments", ExecveVariationArguments}};
54
55 int ExecveTestEntry(int Argc, char* Argv[], char** Envp)
56
57 /*++
58 --*/
59
60 {
61
62 LXT_ARGS Args;
63 int Result;
64
65 //
66 // For a child invocation, validate that the PID/TID is as expected.
67 //
68
69 if ((Argc == 3) && (strcmp(Argv[1], "-c") == 0))
70 {
71
72 int Pid;
73
74 Pid = atoi(Argv[2]);
75 LxtCheckResult(ExecveValidate(Pid));
76 goto ErrorExit;
77 }
78
79 //
80 // For environment variable child validation, make sure a non-NULL pointer
81 // is passed but there are no arguments.
82 //
83
84 if ((Argc == 2) && (strcmp(Argv[1], "-e") == 0))
85 {
86 LxtCheckTrue(Envp != NULL);
87
88 char** Env;
89 int Count = 0;
90 for (Env = Envp; *Env != NULL; Env += 1)
91 {
92 Count += 1;
93 }
94
95 LxtCheckTrue(Count == 0);
96 goto ErrorExit;
97 }
98
99 //
100 // Run the master test.
101 //
102
103 LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
104 LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
105
106 ErrorExit:
107 LxtUninitialize();
108 return !LXT_SUCCESS(Result);
109 }
110
111 int ExecveExecValidate(char* Path)
112
113 /*++
114 --*/
115
116 {
117
118 char* ExecArgs[5];
119 char ExpectedPid[16];
120 int Pid;
121 int Result;
122
123 Pid = getpid();
124 LxtLogInfo("Execve'ing validation for PID %d", Pid);
125
126 sprintf(ExpectedPid, "%d", Pid);
127 ExecArgs[0] = Path;
128 ExecArgs[1] = "execve";
129 ExecArgs[2] = "-c";
130 ExecArgs[3] = ExpectedPid;
131 ExecArgs[4] = NULL;
132 execv(ExecArgs[0], ExecArgs);
133 LxtCheckTrue(FALSE);
134 Result = LXT_RESULT_SUCCESS;
135
136 ErrorExit:
137 return Result;
138 }
139
140 int ExecveValidate(int ExpectedPid)
141
142 /*++
143 --*/
144
145 {
146
147 int Pid;
148 int Result;
149 int ThreadCount;
150 int Tid;
151
152 //
153 // Check that the PID/TID matches the expected value.
154 //
155
156 Pid = getpid();
157 Tid = gettid();
158 LxtCheckTrue(Pid == ExpectedPid);
159 LxtCheckTrue(Tid == ExpectedPid);
160 Result = LXT_RESULT_SUCCESS;
161
162 ErrorExit:
163 return Result;
164 }
165
166 #define COMMAND_LINE_SIZE (((size_t)MAX_ARG_STRINGS) + 1)
167 #define LARGE_STRING_SIZE (((size_t)MAX_ARG_STRLEN) + 1)
168 #define MAX_STACK_SIZE ((size_t)(2 * 1024 * 1024))
169
170 int ExecveVariationArguments(PLXT_ARGS Args)
171
172 /*++
173 --*/
174
175 {
176
177 int ChildPid;
178 char* ExecArgs[4];
179 char** ExecArgsLong;
180 size_t Index;
181 char* LongString;
182 int Result;
183 int Status;
184 size_t TotalSize;
185
186 ExecArgsLong = NULL;
187 LongString = NULL;
188
189 //
190 // Test a null environment block.
191 //
192
193 LxtCheckResult(ChildPid = fork());
194 if (ChildPid == 0)
195 {
196 ExecArgs[0] = "/bin/true";
197 ExecArgs[1] = NULL;
198 LxtCheckErrno(LxtExecve(ExecArgs[0], ExecArgs, NULL));
199
200 //
201 // The parent waits for the child to exit successfully.
202 //
203 }
204 else
205 {
206 LxtCheckResult(ExecveWaitForChild());
207 }
208
209 //
210 // Test exec args with spaces and path.
211 //
212
213 LxtCheckResult(ChildPid = fork());
214 if (ChildPid == 0)
215 {
216 ExecArgs[0] = "/bin/true with a space";
217 ExecArgs[1] = NULL;
218 LxtCheckErrno(LxtExecve("/bin/true", ExecArgs, NULL));
219
220 //
221 // The parent waits for the child to exit successfully.
222 //
223 }
224 else
225 {
226 LxtCheckResult(ExecveWaitForChild());
227 }
228
229 //
230 // Validate that a null environment block results in zero entries for the
231 // environment argument to the main function.
232 //
233
234 LxtCheckResult(ChildPid = fork());
235 if (ChildPid == 0)
236 {
237 ExecArgs[0] = WSL_UNIT_TEST_BINARY;
238 ExecArgs[1] = "execve";
239 ExecArgs[2] = "-e";
240 ExecArgs[3] = NULL;
241 LxtCheckErrno(LxtExecve(ExecArgs[0], ExecArgs, NULL));
242
243 //
244 // The parent waits for the child to exit successfully.
245 //
246 }
247 else
248 {
249 LxtCheckResult(ExecveWaitForChild());
250 }
251
252 //
253 // Allocate a very long string of 'a' and null terminate to
254 // validate command line parsing limits.
255 //
256
257 LongString = malloc(LARGE_STRING_SIZE);
258 if (LongString == NULL)
259 {
260 LxtLogError("malloc");
261 goto ErrorExit;
262 }
263
264 memset(LongString, 'a', LARGE_STRING_SIZE);
265 LongString[LARGE_STRING_SIZE - 1] = '\0';
266
267 //
268 // Create a child and verify that exec fails with too long of a string
269 // in the command line or environment variable array.
270 //
271
272 LxtCheckResult(ChildPid = fork());
273 if (ChildPid == 0)
274 {
275 ExecArgs[0] = "/bin/false";
276 ExecArgs[1] = LongString;
277 ExecArgs[2] = NULL;
278 LxtCheckErrnoFailure(LxtExecve(ExecArgs[0], ExecArgs, NULL), E2BIG);
279 LxtCheckErrnoFailure(LxtExecve(ExecArgs[0], NULL, &ExecArgs[1]), E2BIG);
280
281 //
282 // Shorten the string and verify the exec call succeeds.
283 //
284
285 ExecArgs[0] = "/bin/true";
286 ExecArgs[1] = LongString;
287 ExecArgs[2] = NULL;
288 LongString[LARGE_STRING_SIZE - 2] = '\0';
289 LxtCheckErrno(LxtExecve(ExecArgs[0], ExecArgs, NULL));
290 }
291 else
292 {
293 LxtCheckResult(ExecveWaitForChild());
294 }
295
296 //
297 // Allocate a huge argument array.
298 //
299
300 ExecArgsLong = malloc(MAX_STACK_SIZE * sizeof(char*));
301 if (ExecArgsLong == NULL)
302 {
303 LxtLogError("malloc of %zd size buffer", (MAX_STACK_SIZE * sizeof(char*)));
304
305 goto ErrorExit;
306 }
307
308 for (Index = 0; Index < MAX_STACK_SIZE; Index += 1)
309 {
310 ExecArgsLong[Index] = "a";
311 }
312
313 ExecArgsLong[MAX_STACK_SIZE - 1] = NULL;
314
315 //
316 // Create a child and verify that exec fails with too many arguments in the
317 // command line or environment variable array.
318 //
319
320 LxtCheckResult(ChildPid = fork());
321 if (ChildPid == 0)
322 {
323 ExecArgsLong[0] = "/bin/false";
324 ExecArgsLong[MAX_STACK_SIZE - 1] = NULL;
325 LxtCheckErrnoFailure(LxtExecve(ExecArgsLong[0], ExecArgsLong, NULL), E2BIG);
326 LxtCheckErrnoFailure(LxtExecve(ExecArgsLong[0], NULL, &ExecArgsLong[1]), E2BIG);
327
328 //
329 // Shorten the argument list and verify that the command succeeds.
330 //
331
332 ExecArgsLong[0] = "/bin/true";
333 ExecArgsLong[(MAX_STACK_SIZE / 4)] = NULL;
334 LxtCheckErrno(LxtExecve(ExecArgsLong[0], ExecArgsLong, NULL));
335 }
336 else
337 {
338 LxtCheckResult(ExecveWaitForChild());
339 }
340
341 //
342 // Test an empty command line array.
343 //
344
345 LxtCheckResult(ChildPid = fork());
346 if (ChildPid == 0)
347 {
348 ExecArgs[0] = NULL;
349 LxtCheckErrno(LxtExecve("/bin/echo", ExecArgs, NULL));
350
351 //
352 // The parent waits for the child to exit with SIGABRT.
353 //
354 }
355 else
356 {
357 LxtLogInfo("Waiting for child to exit");
358 wait(&Status);
359 LxtLogInfo("Status %d", Status);
360 LxtCheckTrue((WIFSIGNALED(Status)) && (WTERMSIG(Status) == SIGABRT));
361 LxtLogInfo("Child exited with SIGABRT");
362 }
363
364 //
365 // Test a null command line pointer.
366 //
367
368 LxtCheckResult(ChildPid = fork());
369 if (ChildPid == 0)
370 {
371 LxtCheckErrno(LxtExecve("/bin/echo", NULL, NULL));
372
373 //
374 // The parent waits for the child to exit SIGABRT.
375 //
376 }
377 else
378 {
379 LxtLogInfo("Waiting for child to exit");
380 wait(&Status);
381 LxtLogInfo("Status %d", Status);
382 LxtCheckTrue((WIFSIGNALED(Status)) && (WTERMSIG(Status) == SIGABRT));
383 LxtLogInfo("Child exited with SIGABRT");
384 }
385
386 //
387 // Check that executing a directory fails with the expected error code.
388 //
389
390 mkdir(LXT_EXECV_TEST_DIRECTORY, 0777);
391 ExecArgs[0] = LXT_EXECV_TEST_DIRECTORY;
392 ExecArgs[1] = NULL;
393 LxtCheckErrnoFailure(LxtExecve(ExecArgs[0], ExecArgs, NULL), EACCES);
394
395 //
396 // Verify that exec with a NULL filename fails.
397 //
398
399 LxtCheckErrnoFailure(LxtExecve(NULL, NULL, NULL), EFAULT);
400 ExecArgs[0] = "/bin/echo";
401 ExecArgs[1] = NULL;
402 LxtCheckErrnoFailure(LxtExecve(NULL, ExecArgs, NULL), EFAULT);
403
404 Result = LXT_RESULT_SUCCESS;
405
406 ErrorExit:
407 rmdir(LXT_EXECV_TEST_DIRECTORY);
408 if (LongString != NULL)
409 {
410 free(LongString);
411 }
412
413 if (ExecArgsLong != NULL)
414 {
415 free(ExecArgsLong);
416 }
417
418 if (ChildPid == 0)
419 {
420 _exit(Result);
421 }
422
423 return Result;
424 }
425
426 int ExecveVariationSingle(PLXT_ARGS Args)
427
428 /*++
429 --*/
430
431 {
432
433 int ChildPid;
434 int Result;
435
436 LxtLogInfo("Forking single child");
437 LxtCheckResult(ChildPid = fork());
438
439 //
440 // The child process executes the validation program.
441 //
442
443 if (ChildPid == 0)
444 {
445 LxtCheckResult(ExecveExecValidate(WSL_UNIT_TEST_BINARY));
446
447 //
448 // The parent waits for the child to exit successfully.
449 //
450 }
451 else
452 {
453 LxtCheckResult(ExecveWaitForChild());
454 }
455
456 Result = LXT_RESULT_SUCCESS;
457
458 ErrorExit:
459 return Result;
460 }
461
462 int ExecveVariationMultipleWithThreads(PLXT_ARGS Args)
463
464 /*++
465 --*/
466
467 {
468
469 #define NUM_CHILDREN 32
470
471 int ChildPid;
472 int ProcessIndex;
473 int Result;
474
475 //
476 // Launch all child processes.
477 //
478
479 for (ProcessIndex = 0; ProcessIndex < NUM_CHILDREN; ProcessIndex += 1)
480 {
481 LxtLogInfo("Forking child (#%d)", ProcessIndex);
482 LxtCheckResult(ChildPid = fork());
483
484 //
485 // In the child, create worker threads and then exec the validation
486 // step from the leader.
487 //
488
489 if (ChildPid == 0)
490 {
491
492 pthread_t Thread;
493 int ThreadCount;
494 int ThreadIndex;
495
496 ThreadCount = ProcessIndex + 1;
497 LxtLogInfo("Creating %d thread(s) for PID %d", ThreadCount, getpid());
498 for (ThreadIndex = 0; ThreadIndex < ThreadCount; ThreadIndex += 1)
499 {
500 LxtCheckResultError(pthread_create(&Thread, NULL, ExecveWorkerThread, NULL));
501 }
502
503 //
504 // Sleep for 100ms and then execute the validation step.
505 //
506
507 usleep(100000);
508 LxtCheckResult(ExecveExecValidate(WSL_UNIT_TEST_BINARY));
509 }
510 }
511
512 //
513 // Launch again, this time calling exec from the non-leader thread.
514 //
515
516 for (ProcessIndex = 0; ProcessIndex < NUM_CHILDREN; ProcessIndex += 1)
517 {
518 LxtLogInfo("Forking child (#%d)", ProcessIndex);
519 LxtCheckResult(ChildPid = fork());
520 if (ChildPid == 0)
521 {
522 pthread_t Thread;
523 int ThreadCount;
524 int ThreadIndex;
525
526 ThreadCount = ProcessIndex + 1;
527 LxtLogInfo("Creating %d thread(s) for PID %d", ThreadCount, getpid());
528 for (ThreadIndex = 0; ThreadIndex < ThreadCount; ThreadIndex += 1)
529 {
530 LxtCheckResultError(pthread_create(&Thread, NULL, ExecveWorkerThread2, Args));
531 }
532
533 //
534 // Continuously sleep for 100ms.
535 //
536
537 for (;;)
538 {
539 usleep(100000);
540 }
541 }
542 }
543
544 //
545 // Wait for all child processes to exit.
546 //
547
548 LxtLogInfo("Waiting for children to exit");
549 for (ProcessIndex = 0; ProcessIndex < (2 * NUM_CHILDREN); ProcessIndex += 1)
550 {
551
552 LxtCheckResult(ExecveWaitForChild());
553 LxtLogInfo("Child exited (#%d)", ProcessIndex);
554 }
555
556 Result = LXT_RESULT_SUCCESS;
557
558 ErrorExit:
559 return Result;
560 }
561
562 int ExecveWaitForChild(void)
563
564 /*++
565 --*/
566
567 {
568
569 int Result;
570 int Status;
571
572 wait(&Status);
573 LxtCheckTrue((WIFEXITED(Status)) && (WEXITSTATUS(Status) == 0));
574 Result = 0;
575
576 ErrorExit:
577 return Result;
578 }
579
580 void* ExecveWorkerThread(void* Arg)
581
582 /*++
583 --*/
584
585 {
586
587 //
588 // Continuously sleep for 100ms.
589 //
590
591 for (;;)
592 {
593 usleep(100000);
594 }
595
596 return NULL;
597 }
598
599 void* ExecveWorkerThread2(void* Arg)
600
601 /*++
602 --*/
603
604 {
605
606 int Result;
607
608 PLXT_ARGS Args = (PLXT_ARGS)Arg;
609
610 //
611 // Sleep for 100ms and then execute the validation step.
612 //
613
614 usleep(100000);
615 LxtCheckResult(ExecveExecValidate(WSL_UNIT_TEST_BINARY));
616
617 ErrorExit:
618 return (void*)(long)Result;
619 }