1 // Copyright 2012 Google Inc.
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
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)
35 #include <sys/resource.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.
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.
107 mask_handlers(const int operation
)
111 sigaddset(&mask
, SIGALRM
);
112 sigaddset(&mask
, SIGINT
);
113 sigaddset(&mask
, SIGHUP
);
114 sigaddset(&mask
, SIGTERM
);
115 #if defined(__minix) && !defined(NDEBUG)
117 #endif /* defined(__minix) && !defined(NDEBUG) */
118 sigprocmask(operation
, &mask
, NULL
);
123 /// Masks all signals programmed by this module.
127 mask_handlers(SIG_BLOCK
);
132 /// Unmasks all signals programmed by this module.
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.
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";
157 if (write(STDERR_FILENO
, clean_message
, strlen(clean_message
)) == -1) {
160 if (pid_to_kill
!= -1) {
161 kill(pid_to_kill
, SIGKILL
);
166 if (write(STDERR_FILENO
, abort_message
, strlen(abort_message
)) == -1) {
169 if (pid_to_kill
!= -1) {
170 kill(pid_to_kill
, SIGKILL
);
178 /// Handler for signals that should terminate the active subprocess.
180 /// \param unused_signo Number of the captured signal.
182 timeout_handler(const int KYUA_DEFS_UNUSED_PARAM(signo
))
184 static const char* message
= "Subprocess timed out; sending KILL "
188 process_timed_out
= true;
189 if (write(STDERR_FILENO
, message
, strlen(message
)) == -1) {
192 if (pid_to_kill
!= -1) {
193 kill(pid_to_kill
, SIGKILL
);
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.
207 setup_signal(const int signo
, void (*handler
)(const int),
208 struct sigaction
* old_sa
)
211 sa
.sa_handler
= handler
;
212 sigemptyset(&sa
.sa_mask
);
213 sa
.sa_flags
= SA_RESTART
;
215 #if defined(__minix) && !defined(NDEBUG)
217 #endif /* defined(__minix) && !defined(NDEBUG) */
218 sigaction(signo
, &sa
, old_sa
);
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.
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)
238 #endif /* defined(__minix) && !defined(NDEBUG) */
239 setitimer(ITIMER_REAL
, &new_timer
, old_itimerval
);
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.
252 prepare_environment(const char* work_directory
)
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",
264 for (iter
= to_unset
; *iter
!= NULL
; ++iter
) {
265 error
= kyua_env_unset(*iter
);
266 if (kyua_error_is_set(error
))
270 error
= kyua_env_set("HOME", work_directory
);
271 if (kyua_error_is_set(error
))
274 error
= kyua_env_set("TZ", "UTC");
275 if (kyua_error_is_set(error
))
278 error
= kyua_env_set("__RUNNING_INSIDE_ATF_RUN", "internal-yes-value");
279 if (kyua_error_is_set(error
))
282 assert(!kyua_error_is_set(error
));
287 /// Resets all signals to their default handlers.
293 for (signo
= 1; signo
<= LAST_SIGNO
; ++signo
) {
294 if (signo
== SIGKILL
|| signo
== SIGSTOP
) {
295 // Don't attempt to reset immutable signals.
300 sa
.sa_handler
= SIG_DFL
;
301 sigemptyset(&sa
.sa_mask
);
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.
313 unlimit_core_size(void)
315 #if !defined(__minix)
318 const int ret
= getrlimit(RLIMIT_CORE
, &rl
);
321 rl
.rlim_cur
= rl
.rlim_max
;
322 const int ret
= setrlimit(RLIMIT_CORE
, &rl
) != -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.
336 setup_child(const kyua_run_params_t
* run_params
)
338 #if !defined(__minix)
339 setpgid(getpid(), getpid());
340 #endif /* !defined(__minix) */
342 if (chdir(run_params
->work_directory
) == -1)
343 err(exit_setup_child
, "chdir(%s) failed", run_params
->work_directory
);
348 const kyua_error_t error
= prepare_environment(run_params
->work_directory
);
349 if (kyua_error_is_set(error
))
350 kyua_error_err(exit_setup_child
, error
, "Failed to configure the "
355 if (run_params
->unprivileged_group
!= getgid()) {
356 if (setgid(run_params
->unprivileged_group
) == -1)
357 err(exit_setup_child
, "setgid(%ld) failed; uid is %ld and gid "
358 "is %ld", (long int)run_params
->unprivileged_group
,
359 (long int)getuid(), (long int)getgid());
361 if (run_params
->unprivileged_user
!= getuid()) {
362 if (setuid(run_params
->unprivileged_user
) == -1)
363 err(exit_setup_child
, "setuid(%ld) failed; uid is %ld and gid "
364 "is %ld", (long int)run_params
->unprivileged_user
,
365 (long int)getuid(), (long int)getgid());
370 /// Constructs a path to a work directory based on a template.
372 /// \param template Template of the work directory to create. Should be a
373 /// basename and must include the XXXXXX placeholder string. The directory
374 /// is created within the temporary directory specified by the TMPDIR
375 /// environment variable or the builtin value in kyua_run_tmpdir.
376 /// \param [out] work_directory Pointer to a dynamically-allocated string
377 /// containing the full path to the work directory. The caller is
378 /// responsible for releasing this string.
380 /// \return An error if there is a problem (most likely OOM), or OK otherwise.
382 build_work_directory_path(const char* template, char** work_directory
)
384 assert(strstr(template, "XXXXXX") != NULL
);
386 const char* tmpdir
= getenv("TMPDIR");
388 return kyua_text_printf(work_directory
, "%s/%s", kyua_run_tmpdir
,
391 return kyua_text_printf(work_directory
, "%s/%s", tmpdir
, template);
395 /// Initializes the run_params parameters with default values.
397 /// \param [out] run_params The object to initialize.
399 kyua_run_params_init(kyua_run_params_t
* run_params
)
401 run_params
->timeout_seconds
= 60;
402 run_params
->unprivileged_user
= getuid();
403 run_params
->unprivileged_group
= getgid();
404 run_params
->work_directory
= ".";
408 /// Executes a program and exits if there is a problem.
410 /// This routine is supposed to be used in conjunction with kyua_run_fork and
411 /// kyua_run_wait so that the various return codes of the exec system call are
412 /// properly propagated to the parent process.
414 /// \param program Path to the program to run.
415 /// \param args Arguments to the program.
417 kyua_run_exec(const char* program
, const char* const* args
)
419 (void)execvp(program
, KYUA_DEFS_UNCONST(args
));
422 exit(exit_exec_eacces
);
424 exit(exit_exec_enoent
);
426 err(exit_exec_unknown
, "execvp failed");
431 /// Forks and isolates the child process.
433 /// The created subprocess must be waited for with kyua_run_wait().
435 /// \param run_params Parameters that describe how to isolate the newly-created
437 /// \param [out] out_pid The PID of the child in the parent, or 0 in the child.
438 /// The value left here should only be accessed if this function does not
441 /// \return An error object if fork(2) fails.
443 kyua_run_fork(const kyua_run_params_t
* run_params
, pid_t
* const out_pid
)
449 *out_pid
= pid
; // Not necessary, but avoid mistakes in the caller.
450 return kyua_libc_error_new(errno
, "fork failed");
451 } else if (pid
== 0) {
453 setup_child(run_params
);
455 return kyua_error_ok();
460 setup_signal(SIGALRM
, timeout_handler
, &old_sigalrm
);
461 process_timed_out
= false;
462 setup_timer(run_params
->timeout_seconds
, &old_timer
);
465 return kyua_error_ok();
470 /// Waits for a process started via kyua_run_fork.
472 /// \param pid The PID of the child to wait for.
473 /// \param [out] status The exit status of the awaited process.
474 /// \param [out] timed_out Whether the process timed out or not.
476 /// \return An error if the process failed due to an problem in kyua_run_exec.
477 /// However, note that the wait for the process itself is expected to have been
480 kyua_run_wait(const pid_t pid
, int* status
, bool* timed_out
)
483 #if defined(__minix) && !defined(NDEBUG)
484 const pid_t waited_pid
=
485 #endif /* defined(__minix) && !defined(NDEBUG) */
486 waitpid(pid
, &tmp_status
, 0);
487 assert(pid
== waited_pid
);
490 (void)setitimer(ITIMER_REAL
, &old_timer
, NULL
);
491 (void)sigaction(SIGALRM
, &old_sigalrm
, NULL
);
495 killpg(pid
, SIGKILL
);
497 if (WIFEXITED(tmp_status
)) {
498 if (WEXITSTATUS(tmp_status
) == exit_setup_child
) {
499 return kyua_generic_error_new("Failed to isolate subprocess; "
500 "see stderr for details");
501 } else if (WEXITSTATUS(tmp_status
) == exit_exec_eacces
) {
502 return kyua_libc_error_new(EACCES
, "execvp failed");
503 } else if (WEXITSTATUS(tmp_status
) == exit_exec_enoent
) {
504 return kyua_libc_error_new(ENOENT
, "execvp failed");
505 } else if (WEXITSTATUS(tmp_status
) == exit_exec_unknown
) {
506 return kyua_generic_error_new("execvp failed; see stderr for "
512 *status
= tmp_status
;
513 *timed_out
= process_timed_out
;
514 return kyua_error_ok();
518 /// Creates a temporary directory for use by a subprocess.
520 /// The temporary directory must be deleted with kyua_run_work_directory_leave.
522 /// \param template Template of the work directory to create. Should be a
523 /// basename and must include the XXXXXX placeholder string. The directory
524 /// is created within the temporary directory specified by the TMPDIR
525 /// environment variable or the builtin value.
526 /// \param uid User to set the owner of the directory to.
527 /// \param gid Group to set the owner of the directory to.
528 /// \param [out] out_work_directory Updated with a pointer to a dynamic string
529 /// holding the path to the created work directory. This must be passed as
530 /// is to kyua_run_work_directory_leave, which takes care of freeing the
533 /// \return An error code if there is a problem creating the directory.
535 kyua_run_work_directory_enter(const char* template, const uid_t uid
,
536 const gid_t gid
, char** out_work_directory
)
538 kyua_error_t error
= kyua_error_ok();
540 signal_fired
= false;
541 setup_signal(SIGHUP
, cleanup_handler
, &old_sighup
);
542 setup_signal(SIGINT
, cleanup_handler
, &old_sigint
);
543 setup_signal(SIGTERM
, cleanup_handler
, &old_sigterm
);
545 char* work_directory
;
546 error
= build_work_directory_path(template, &work_directory
);
547 if (kyua_error_is_set(error
))
550 if (mkdtemp(work_directory
) == NULL
) {
551 error
= kyua_libc_error_new(errno
, "mkdtemp(%s) failed",
553 goto err_work_directory_variable
;
556 if (uid
!= getuid() || gid
!= getgid()) {
557 if (chown(work_directory
, uid
, gid
) == -1) {
558 error
= kyua_libc_error_new(errno
,
559 "chown(%s, %ld, %ld) failed; uid is %ld and gid is %ld",
560 work_directory
, (long int)uid
, (long int)gid
,
561 (long int)getuid(), (long int)getgid());
562 goto err_work_directory_file
;
566 *out_work_directory
= work_directory
;
567 assert(!kyua_error_is_set(error
));
570 err_work_directory_file
:
571 (void)rmdir(work_directory
);
572 err_work_directory_variable
:
573 free(work_directory
);
575 (void)sigaction(SIGTERM
, &old_sigterm
, NULL
);
576 (void)sigaction(SIGINT
, &old_sigint
, NULL
);
577 (void)sigaction(SIGHUP
, &old_sighup
, NULL
);
583 /// Deletes a temporary directory created by kyua_run_work_directory_enter().
585 /// \param [in,out] work_directory The pointer to the work_directory string as
586 /// originally returned by kyua_run_work_directory_leave(). This is
587 /// explicitly invalidated by this function to clearly denote that this
588 /// performs the memory releasing.
590 /// \return An error code if the cleanup of the directory fails. Note that any
591 /// intermediate errors during the cleanup are sent to stderr.
593 kyua_run_work_directory_leave(char** work_directory
)
595 kyua_error_t error
= kyua_fs_cleanup(*work_directory
);
597 free(*work_directory
);
598 *work_directory
= NULL
;
600 (void)sigaction(SIGTERM
, &old_sigterm
, NULL
);
601 (void)sigaction(SIGHUP
, &old_sighup
, NULL
);
602 (void)sigaction(SIGINT
, &old_sigint
, NULL
);
604 // At this point, we have cleaned up the work directory and we could
605 // (should?) re-deliver the signal to ourselves so that we terminated with
606 // the right code. However, we just let this return and allow the caller
607 // code to perform any other cleanups instead.