Remove building with NOCRYPTO option
[minix3.git] / external / bsd / kyua-testers / dist / run.c
blob6c405de3d8d6bea717ed407ad65ffa189c677010
1 // Copyright 2012 Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #if defined(HAVE_CONFIG_H)
30 # include "config.h"
31 #endif
33 #include "run.h"
35 #include <sys/resource.h>
36 #include <sys/stat.h>
37 #include <sys/time.h>
38 #include <sys/wait.h>
40 #include <assert.h>
41 #include <err.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <signal.h>
45 #include <stdbool.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
51 #include "defs.h"
52 #include "env.h"
53 #include "error.h"
54 #include "fs.h"
55 #include "text.h"
58 /// Path to the temporary work directory to use.
59 const char* kyua_run_tmpdir = KYUA_TMPDIR;
60 #undef KYUA_TMPDIR // We really want to use the variable, not the macro.
63 /// Whether we got a signal or not.
64 static volatile bool signal_fired = false;
67 /// Whether the process timed out or not.
68 static volatile bool process_timed_out = false;
71 /// If not -1, PID of the process to forcibly kill when we get a signal.
72 ///
73 /// Must be protected by protect() and unprotect().
74 static volatile pid_t pid_to_kill = -1;
77 /// Whether we are holding signals or not.
78 static bool protected = false;
81 /// Magic exit code to denote an error while preparing the subprocess.
82 static const int exit_setup_child = 124;
83 /// Magic exit code to denote an error in exec(3) that we do not handle.
84 static const int exit_exec_unknown = 123;
85 /// Magic exit code to denote an EACCES error in exec(3).
86 static const int exit_exec_eacces = 122;
87 /// Magic exit code to denote an ENOENT error in exec(3).
88 static const int exit_exec_enoent = 121;
91 /// Area to save the original SIGHUP handler.
92 static struct sigaction old_sighup;
93 /// Area to save the original SIGINT handler.
94 static struct sigaction old_sigint;
95 /// Area to save the original SIGTERM handler.
96 static struct sigaction old_sigterm;
97 /// Area to save the original SIGALRM handler.
98 static struct sigaction old_sigalrm;
99 /// Area to save the original realtime timer.
100 static struct itimerval old_timer;
103 /// Masks or unmasks all the signals programmed by this module.
105 /// \param operation One of SIG_BLOCK or SIG_UNBLOCK.
106 static void
107 mask_handlers(const int operation)
109 sigset_t mask;
110 sigemptyset(&mask);
111 sigaddset(&mask, SIGALRM);
112 sigaddset(&mask, SIGINT);
113 sigaddset(&mask, SIGHUP);
114 sigaddset(&mask, SIGTERM);
115 #if defined(__minix) && !defined(NDEBUG)
116 const int ret =
117 #endif /* defined(__minix) && !defined(NDEBUG) */
118 sigprocmask(operation, &mask, NULL);
119 assert(ret != -1);
123 /// Masks all signals programmed by this module.
124 static void
125 protect(void)
127 mask_handlers(SIG_BLOCK);
128 protected = true;
132 /// Unmasks all signals programmed by this module.
133 static void
134 unprotect(void)
136 protected = false;
137 mask_handlers(SIG_UNBLOCK);
141 /// Handler for signals that should abort execution.
143 /// When called the first time, this handler kills any running subprocess so
144 /// that the cleanup routines can proceed. Calling this a second time aborts
145 /// execution of the program.
147 /// \param unused_signo Number of the captured signal.
148 static void
149 cleanup_handler(const int KYUA_DEFS_UNUSED_PARAM(signo))
151 static const char* clean_message = "Signal caught; cleaning up...\n";
152 static const char* abort_message = "Double signal caught; aborting...\n";
154 protect();
155 if (!signal_fired) {
156 signal_fired = true;
157 if (write(STDERR_FILENO, clean_message, strlen(clean_message)) == -1) {
158 // Ignore.
160 if (pid_to_kill != -1) {
161 kill(pid_to_kill, SIGKILL);
162 pid_to_kill = -1;
164 unprotect();
165 } else {
166 if (write(STDERR_FILENO, abort_message, strlen(abort_message)) == -1) {
167 // Ignore.
169 if (pid_to_kill != -1) {
170 kill(pid_to_kill, SIGKILL);
171 pid_to_kill = -1;
173 abort();
178 /// Handler for signals that should terminate the active subprocess.
180 /// \param unused_signo Number of the captured signal.
181 static void
182 timeout_handler(const int KYUA_DEFS_UNUSED_PARAM(signo))
184 static const char* message = "Subprocess timed out; sending KILL "
185 "signal...\n";
187 protect();
188 process_timed_out = true;
189 if (write(STDERR_FILENO, message, strlen(message)) == -1) {
190 // Ignore.
192 if (pid_to_kill != -1) {
193 kill(pid_to_kill, SIGKILL);
194 pid_to_kill = -1;
196 unprotect();
200 /// Installs a signal handler.
202 /// \param signo Number of the signal to program.
203 /// \param handler Handler for the signal.
204 /// \param [out] old_sa Pointer to the sigaction structure in which to save the
205 /// current signal handler data.
206 static void
207 setup_signal(const int signo, void (*handler)(const int),
208 struct sigaction* old_sa)
210 struct sigaction sa;
211 sa.sa_handler = handler;
212 sigemptyset(&sa.sa_mask);
213 sa.sa_flags = SA_RESTART;
215 #if defined(__minix) && !defined(NDEBUG)
216 const int ret =
217 #endif /* defined(__minix) && !defined(NDEBUG) */
218 sigaction(signo, &sa, old_sa);
219 assert(ret != -1);
223 /// Installs a timer.
225 /// \param seconds Deadline for the timer.
226 /// \param [out] old_itimerval Pointer to the itimerval structure in which to
227 /// save the current timer data into.
228 static void
229 setup_timer(const int seconds, struct itimerval* old_itimerval)
231 struct itimerval new_timer;
232 new_timer.it_interval.tv_sec = 0;
233 new_timer.it_interval.tv_usec = 0;
234 new_timer.it_value.tv_sec = seconds;
235 new_timer.it_value.tv_usec = 0;
236 #if defined(__minix) && !defined(NDEBUG)
237 const int ret =
238 #endif /* defined(__minix) && !defined(NDEBUG) */
239 setitimer(ITIMER_REAL, &new_timer, old_itimerval);
240 assert(ret != -1);
244 /// Resets the environment of the process to a known state.
246 /// \param work_directory Path to the work directory being used.
248 /// \return An error if there is a problem configuring the environment
249 /// variables, or OK if successful. Note that if this returns an error, we have
250 /// left the environment in an inconsistent state.
251 static kyua_error_t
252 prepare_environment(const char* work_directory)
254 kyua_error_t error;
256 // TODO(jmmv): It might be better to do the opposite: just pass a good known
257 // set of variables to the child (aka HOME, PATH, ...). But how do we
258 // determine this minimum set?
260 const char* to_unset[] = { "LANG", "LC_ALL", "LC_COLLATE", "LC_CTYPE",
261 "LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC",
262 "LC_TIME", NULL };
263 const char** iter;
264 for (iter = to_unset; *iter != NULL; ++iter) {
265 error = kyua_env_unset(*iter);
266 if (kyua_error_is_set(error))
267 return error;
270 error = kyua_env_set("HOME", work_directory);
271 if (kyua_error_is_set(error))
272 return error;
274 error = kyua_env_set("TZ", "UTC");
275 if (kyua_error_is_set(error))
276 return error;
278 error = kyua_env_set("__RUNNING_INSIDE_ATF_RUN", "internal-yes-value");
279 if (kyua_error_is_set(error))
280 return error;
282 assert(!kyua_error_is_set(error));
283 return error;
287 /// Resets all signals to their default handlers.
288 static void
289 reset_signals(void)
291 int signo;
293 for (signo = 1; signo <= LAST_SIGNO; ++signo) {
294 if (signo == SIGKILL || signo == SIGSTOP) {
295 // Don't attempt to reset immutable signals.
296 continue;
299 struct sigaction sa;
300 sa.sa_handler = SIG_DFL;
301 sigemptyset(&sa.sa_mask);
302 sa.sa_flags = 0;
303 (void)sigaction(signo, &sa, NULL);
308 /// Raises core size limit to its possible maximum.
310 /// This is a best-effort operation. There is no guarantee that the operation
311 /// will yield a large-enough limit to generate any possible core file.
312 static void
313 unlimit_core_size(void)
315 #if !defined(__minix)
316 struct rlimit rl;
318 const int ret = getrlimit(RLIMIT_CORE, &rl);
319 assert(ret != -1);
321 rl.rlim_cur = rl.rlim_max;
322 const int ret = setrlimit(RLIMIT_CORE, &rl) != -1;
323 assert(ret != -1);
324 #endif /* !defined(__minix) */
328 /// Cleans up the container process to run a new child.
330 /// If there is any error during the setup, the new process is terminated
331 /// with an error code.
333 /// \param run_params End-user parameters that describe how to isolate the
334 /// newly-created process.
335 static void
336 setup_child(const kyua_run_params_t* run_params)
338 setpgid(getpid(), getpid());
340 if (chdir(run_params->work_directory) == -1)
341 err(exit_setup_child, "chdir(%s) failed", run_params->work_directory);
343 unlimit_core_size();
344 reset_signals();
346 const kyua_error_t error = prepare_environment(run_params->work_directory);
347 if (kyua_error_is_set(error))
348 kyua_error_err(exit_setup_child, error, "Failed to configure the "
349 "environment");
351 (void)umask(0022);
353 if (run_params->unprivileged_group != getgid()) {
354 if (setgid(run_params->unprivileged_group) == -1)
355 err(exit_setup_child, "setgid(%ld) failed; uid is %ld and gid "
356 "is %ld", (long int)run_params->unprivileged_group,
357 (long int)getuid(), (long int)getgid());
359 if (run_params->unprivileged_user != getuid()) {
360 if (setuid(run_params->unprivileged_user) == -1)
361 err(exit_setup_child, "setuid(%ld) failed; uid is %ld and gid "
362 "is %ld", (long int)run_params->unprivileged_user,
363 (long int)getuid(), (long int)getgid());
368 /// Constructs a path to a work directory based on a template.
370 /// \param template Template of the work directory to create. Should be a
371 /// basename and must include the XXXXXX placeholder string. The directory
372 /// is created within the temporary directory specified by the TMPDIR
373 /// environment variable or the builtin value in kyua_run_tmpdir.
374 /// \param [out] work_directory Pointer to a dynamically-allocated string
375 /// containing the full path to the work directory. The caller is
376 /// responsible for releasing this string.
378 /// \return An error if there is a problem (most likely OOM), or OK otherwise.
379 static kyua_error_t
380 build_work_directory_path(const char* template, char** work_directory)
382 assert(strstr(template, "XXXXXX") != NULL);
384 const char* tmpdir = getenv("TMPDIR");
385 if (tmpdir == NULL)
386 return kyua_text_printf(work_directory, "%s/%s", kyua_run_tmpdir,
387 template);
388 else
389 return kyua_text_printf(work_directory, "%s/%s", tmpdir, template);
393 /// Initializes the run_params parameters with default values.
395 /// \param [out] run_params The object to initialize.
396 void
397 kyua_run_params_init(kyua_run_params_t* run_params)
399 run_params->timeout_seconds = 60;
400 run_params->unprivileged_user = getuid();
401 run_params->unprivileged_group = getgid();
402 run_params->work_directory = ".";
406 /// Executes a program and exits if there is a problem.
408 /// This routine is supposed to be used in conjunction with kyua_run_fork and
409 /// kyua_run_wait so that the various return codes of the exec system call are
410 /// properly propagated to the parent process.
412 /// \param program Path to the program to run.
413 /// \param args Arguments to the program.
414 void
415 kyua_run_exec(const char* program, const char* const* args)
417 (void)execvp(program, KYUA_DEFS_UNCONST(args));
418 switch (errno) {
419 case EACCES:
420 exit(exit_exec_eacces);
421 case ENOENT:
422 exit(exit_exec_enoent);
423 default:
424 err(exit_exec_unknown, "execvp failed");
429 /// Forks and isolates the child process.
431 /// The created subprocess must be waited for with kyua_run_wait().
433 /// \param run_params Parameters that describe how to isolate the newly-created
434 /// process.
435 /// \param [out] out_pid The PID of the child in the parent, or 0 in the child.
436 /// The value left here should only be accessed if this function does not
437 /// return an error.
439 /// \return An error object if fork(2) fails.
440 kyua_error_t
441 kyua_run_fork(const kyua_run_params_t* run_params, pid_t* const out_pid)
443 protect();
444 pid_t pid = fork();
445 if (pid == -1) {
446 unprotect();
447 *out_pid = pid; // Not necessary, but avoid mistakes in the caller.
448 return kyua_libc_error_new(errno, "fork failed");
449 } else if (pid == 0) {
450 unprotect();
451 setup_child(run_params);
452 *out_pid = pid;
453 return kyua_error_ok();
454 } else {
455 pid_to_kill = pid;
456 unprotect();
458 setup_signal(SIGALRM, timeout_handler, &old_sigalrm);
459 process_timed_out = false;
460 setup_timer(run_params->timeout_seconds, &old_timer);
462 *out_pid = pid;
463 return kyua_error_ok();
468 /// Waits for a process started via kyua_run_fork.
470 /// \param pid The PID of the child to wait for.
471 /// \param [out] status The exit status of the awaited process.
472 /// \param [out] timed_out Whether the process timed out or not.
474 /// \return An error if the process failed due to an problem in kyua_run_exec.
475 /// However, note that the wait for the process itself is expected to have been
476 /// successful.
477 kyua_error_t
478 kyua_run_wait(const pid_t pid, int* status, bool* timed_out)
480 int tmp_status;
481 #if defined(__minix) && !defined(NDEBUG)
482 const pid_t waited_pid =
483 #endif /* defined(__minix) && !defined(NDEBUG) */
484 waitpid(pid, &tmp_status, 0);
485 assert(pid == waited_pid);
487 protect();
488 (void)setitimer(ITIMER_REAL, &old_timer, NULL);
489 (void)sigaction(SIGALRM, &old_sigalrm, NULL);
490 pid_to_kill = -1;
491 unprotect();
493 killpg(pid, SIGKILL);
495 if (WIFEXITED(tmp_status)) {
496 if (WEXITSTATUS(tmp_status) == exit_setup_child) {
497 return kyua_generic_error_new("Failed to isolate subprocess; "
498 "see stderr for details");
499 } else if (WEXITSTATUS(tmp_status) == exit_exec_eacces) {
500 return kyua_libc_error_new(EACCES, "execvp failed");
501 } else if (WEXITSTATUS(tmp_status) == exit_exec_enoent) {
502 return kyua_libc_error_new(ENOENT, "execvp failed");
503 } else if (WEXITSTATUS(tmp_status) == exit_exec_unknown) {
504 return kyua_generic_error_new("execvp failed; see stderr for "
505 "details");
506 } else {
507 // Fall-through.
510 *status = tmp_status;
511 *timed_out = process_timed_out;
512 return kyua_error_ok();
516 /// Creates a temporary directory for use by a subprocess.
518 /// The temporary directory must be deleted with kyua_run_work_directory_leave.
520 /// \param template Template of the work directory to create. Should be a
521 /// basename and must include the XXXXXX placeholder string. The directory
522 /// is created within the temporary directory specified by the TMPDIR
523 /// environment variable or the builtin value.
524 /// \param uid User to set the owner of the directory to.
525 /// \param gid Group to set the owner of the directory to.
526 /// \param [out] out_work_directory Updated with a pointer to a dynamic string
527 /// holding the path to the created work directory. This must be passed as
528 /// is to kyua_run_work_directory_leave, which takes care of freeing the
529 /// memory.
531 /// \return An error code if there is a problem creating the directory.
532 kyua_error_t
533 kyua_run_work_directory_enter(const char* template, const uid_t uid,
534 const gid_t gid, char** out_work_directory)
536 kyua_error_t error = kyua_error_ok();
538 signal_fired = false;
539 setup_signal(SIGHUP, cleanup_handler, &old_sighup);
540 setup_signal(SIGINT, cleanup_handler, &old_sigint);
541 setup_signal(SIGTERM, cleanup_handler, &old_sigterm);
543 char* work_directory;
544 error = build_work_directory_path(template, &work_directory);
545 if (kyua_error_is_set(error))
546 goto err_signals;
548 if (mkdtemp(work_directory) == NULL) {
549 error = kyua_libc_error_new(errno, "mkdtemp(%s) failed",
550 work_directory);
551 goto err_work_directory_variable;
554 if (uid != getuid() || gid != getgid()) {
555 if (chown(work_directory, uid, gid) == -1) {
556 error = kyua_libc_error_new(errno,
557 "chown(%s, %ld, %ld) failed; uid is %ld and gid is %ld",
558 work_directory, (long int)uid, (long int)gid,
559 (long int)getuid(), (long int)getgid());
560 goto err_work_directory_file;
564 *out_work_directory = work_directory;
565 assert(!kyua_error_is_set(error));
566 goto out;
568 err_work_directory_file:
569 (void)rmdir(work_directory);
570 err_work_directory_variable:
571 free(work_directory);
572 err_signals:
573 (void)sigaction(SIGTERM, &old_sigterm, NULL);
574 (void)sigaction(SIGINT, &old_sigint, NULL);
575 (void)sigaction(SIGHUP, &old_sighup, NULL);
576 out:
577 return error;
581 /// Deletes a temporary directory created by kyua_run_work_directory_enter().
583 /// \param [in,out] work_directory The pointer to the work_directory string as
584 /// originally returned by kyua_run_work_directory_leave(). This is
585 /// explicitly invalidated by this function to clearly denote that this
586 /// performs the memory releasing.
588 /// \return An error code if the cleanup of the directory fails. Note that any
589 /// intermediate errors during the cleanup are sent to stderr.
590 kyua_error_t
591 kyua_run_work_directory_leave(char** work_directory)
593 kyua_error_t error = kyua_fs_cleanup(*work_directory);
595 free(*work_directory);
596 *work_directory = NULL;
598 (void)sigaction(SIGTERM, &old_sigterm, NULL);
599 (void)sigaction(SIGHUP, &old_sighup, NULL);
600 (void)sigaction(SIGINT, &old_sigint, NULL);
602 // At this point, we have cleaned up the work directory and we could
603 // (should?) re-deliver the signal to ourselves so that we terminated with
604 // the right code. However, we just let this return and allow the caller
605 // code to perform any other cleanups instead.
607 return error;