Home | History | Annotate | Line # | Download | only in dist
      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.
     16 //
     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.
     28 
     29 #if defined(HAVE_CONFIG_H)
     30 #   include "config.h"
     31 #endif
     32 
     33 #include "run.h"
     34 
     35 #include <sys/resource.h>
     36 #include <sys/stat.h>
     37 #include <sys/time.h>
     38 #include <sys/wait.h>
     39 
     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>
     50 
     51 #include "defs.h"
     52 #include "env.h"
     53 #include "error.h"
     54 #include "fs.h"
     55 #include "text.h"
     56 
     57 
     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.
     61 
     62 
     63 /// Whether we got a signal or not.
     64 static volatile bool signal_fired = false;
     65 
     66 
     67 /// Whether the process timed out or not.
     68 static volatile bool process_timed_out = false;
     69 
     70 
     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;
     75 
     76 
     77 /// Whether we are holding signals or not.
     78 static bool protected = false;
     79 
     80 
     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;
     89 
     90 
     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;
    101 
    102 
    103 /// Masks or unmasks all the signals programmed by this module.
    104 ///
    105 /// \param operation One of SIG_BLOCK or SIG_UNBLOCK.
    106 static void
    107 mask_handlers(const int operation)
    108 {
    109     sigset_t mask;
    110     sigemptyset(&mask);
    111     sigaddset(&mask, SIGALRM);
    112     sigaddset(&mask, SIGINT);
    113     sigaddset(&mask, SIGHUP);
    114     sigaddset(&mask, SIGTERM);
    115     const int ret = sigprocmask(operation, &mask, NULL);
    116     assert(ret != -1);
    117 }
    118 
    119 
    120 /// Masks all signals programmed by this module.
    121 static void
    122 protect(void)
    123 {
    124     mask_handlers(SIG_BLOCK);
    125     protected = true;
    126 }
    127 
    128 
    129 /// Unmasks all signals programmed by this module.
    130 static void
    131 unprotect(void)
    132 {
    133     protected = false;
    134     mask_handlers(SIG_UNBLOCK);
    135 }
    136 
    137 
    138 /// Handler for signals that should abort execution.
    139 ///
    140 /// When called the first time, this handler kills any running subprocess so
    141 /// that the cleanup routines can proceed.  Calling this a second time aborts
    142 /// execution of the program.
    143 ///
    144 /// \param unused_signo Number of the captured signal.
    145 static void
    146 cleanup_handler(const int KYUA_DEFS_UNUSED_PARAM(signo))
    147 {
    148     static const char* clean_message = "Signal caught; cleaning up...\n";
    149     static const char* abort_message = "Double signal caught; aborting...\n";
    150 
    151     protect();
    152     if (!signal_fired) {
    153         signal_fired = true;
    154         if (write(STDERR_FILENO, clean_message, strlen(clean_message)) == -1) {
    155             // Ignore.
    156         }
    157         if (pid_to_kill != -1) {
    158             kill(pid_to_kill, SIGKILL);
    159             pid_to_kill = -1;
    160         }
    161         unprotect();
    162     } else {
    163         if (write(STDERR_FILENO, abort_message, strlen(abort_message)) == -1) {
    164             // Ignore.
    165         }
    166         if (pid_to_kill != -1) {
    167             kill(pid_to_kill, SIGKILL);
    168             pid_to_kill = -1;
    169         }
    170         abort();
    171     }
    172 }
    173 
    174 
    175 /// Handler for signals that should terminate the active subprocess.
    176 ///
    177 /// \param unused_signo Number of the captured signal.
    178 static void
    179 timeout_handler(const int KYUA_DEFS_UNUSED_PARAM(signo))
    180 {
    181     static const char* message = "Subprocess timed out; sending KILL "
    182         "signal...\n";
    183 
    184     protect();
    185     process_timed_out = true;
    186     if (write(STDERR_FILENO, message, strlen(message)) == -1) {
    187         // Ignore.
    188     }
    189     if (pid_to_kill != -1) {
    190         kill(pid_to_kill, SIGKILL);
    191         pid_to_kill = -1;
    192     }
    193     unprotect();
    194 }
    195 
    196 
    197 /// Installs a signal handler.
    198 ///
    199 /// \param signo Number of the signal to program.
    200 /// \param handler Handler for the signal.
    201 /// \param [out] old_sa Pointer to the sigaction structure in which to save the
    202 ///     current signal handler data.
    203 static void
    204 setup_signal(const int signo, void (*handler)(const int),
    205              struct sigaction* old_sa)
    206 {
    207     struct sigaction sa;
    208     sa.sa_handler = handler;
    209     sigemptyset(&sa.sa_mask);
    210     sa.sa_flags = SA_RESTART;
    211 
    212     const int ret = sigaction(signo, &sa, old_sa);
    213     assert(ret != -1);
    214 }
    215 
    216 
    217 /// Installs a timer.
    218 ///
    219 /// \param seconds Deadline for the timer.
    220 /// \param [out] old_itimerval Pointer to the itimerval structure in which to
    221 ///     save the current timer data into.
    222 static void
    223 setup_timer(const int seconds, struct itimerval* old_itimerval)
    224 {
    225     struct itimerval new_timer;
    226     new_timer.it_interval.tv_sec = 0;
    227     new_timer.it_interval.tv_usec = 0;
    228     new_timer.it_value.tv_sec = seconds;
    229     new_timer.it_value.tv_usec = 0;
    230     const int ret = setitimer(ITIMER_REAL, &new_timer, old_itimerval);
    231     assert(ret != -1);
    232 }
    233 
    234 
    235 /// Resets the environment of the process to a known state.
    236 ///
    237 /// \param work_directory Path to the work directory being used.
    238 ///
    239 /// \return An error if there is a problem configuring the environment
    240 /// variables, or OK if successful.  Note that if this returns an error, we have
    241 /// left the environment in an inconsistent state.
    242 static kyua_error_t
    243 prepare_environment(const char* work_directory)
    244 {
    245     kyua_error_t error;
    246 
    247     // TODO(jmmv): It might be better to do the opposite: just pass a good known
    248     // set of variables to the child (aka HOME, PATH, ...).  But how do we
    249     // determine this minimum set?
    250 
    251     const char* to_unset[] = { "LANG", "LC_ALL", "LC_COLLATE", "LC_CTYPE",
    252                                "LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC",
    253                                "LC_TIME", NULL };
    254     const char** iter;
    255     for (iter = to_unset; *iter != NULL; ++iter) {
    256         error = kyua_env_unset(*iter);
    257         if (kyua_error_is_set(error))
    258             return error;
    259     }
    260 
    261     error = kyua_env_set("HOME", work_directory);
    262     if (kyua_error_is_set(error))
    263         return error;
    264 
    265     error = kyua_env_set("TZ", "UTC");
    266     if (kyua_error_is_set(error))
    267         return error;
    268 
    269     error = kyua_env_set("__RUNNING_INSIDE_ATF_RUN", "internal-yes-value");
    270     if (kyua_error_is_set(error))
    271         return error;
    272 
    273     assert(!kyua_error_is_set(error));
    274     return error;
    275 }
    276 
    277 
    278 /// Resets all signals to their default handlers.
    279 static void
    280 reset_signals(void)
    281 {
    282     int signo;
    283 
    284     for (signo = 1; signo <= LAST_SIGNO; ++signo) {
    285         if (signo == SIGKILL || signo == SIGSTOP) {
    286             // Don't attempt to reset immutable signals.
    287             continue;
    288         }
    289 
    290         struct sigaction sa;
    291         sa.sa_handler = SIG_DFL;
    292         sigemptyset(&sa.sa_mask);
    293         sa.sa_flags = 0;
    294         (void)sigaction(signo, &sa, NULL);
    295     }
    296 }
    297 
    298 
    299 /// Raises core size limit to its possible maximum.
    300 ///
    301 /// This is a best-effort operation.  There is no guarantee that the operation
    302 /// will yield a large-enough limit to generate any possible core file.
    303 static void
    304 unlimit_core_size(void)
    305 {
    306     struct rlimit rl;
    307     {
    308         const int ret = getrlimit(RLIMIT_CORE, &rl);
    309         assert(ret != -1);
    310     }
    311     rl.rlim_cur = rl.rlim_max;
    312     const int ret = setrlimit(RLIMIT_CORE, &rl) != -1;
    313     assert(ret != -1);
    314 }
    315 
    316 
    317 /// Cleans up the container process to run a new child.
    318 ///
    319 /// If there is any error during the setup, the new process is terminated
    320 /// with an error code.
    321 ///
    322 /// \param run_params End-user parameters that describe how to isolate the
    323 ///     newly-created process.
    324 static void
    325 setup_child(const kyua_run_params_t* run_params)
    326 {
    327     setpgid(getpid(), getpid());
    328 
    329     if (chdir(run_params->work_directory) == -1)
    330         err(exit_setup_child, "chdir(%s) failed", run_params->work_directory);
    331 
    332     unlimit_core_size();
    333     reset_signals();
    334 
    335     const kyua_error_t error = prepare_environment(run_params->work_directory);
    336     if (kyua_error_is_set(error))
    337         kyua_error_err(exit_setup_child, error, "Failed to configure the "
    338                        "environment");
    339 
    340     (void)umask(0022);
    341 
    342     if (run_params->unprivileged_group != getgid()) {
    343         if (setgid(run_params->unprivileged_group) == -1)
    344             err(exit_setup_child, "setgid(%ld) failed; uid is %ld and gid "
    345                 "is %ld", (long int)run_params->unprivileged_group,
    346                 (long int)getuid(), (long int)getgid());
    347     }
    348     if (run_params->unprivileged_user != getuid()) {
    349         if (setuid(run_params->unprivileged_user) == -1)
    350             err(exit_setup_child, "setuid(%ld) failed; uid is %ld and gid "
    351                 "is %ld", (long int)run_params->unprivileged_user,
    352                 (long int)getuid(), (long int)getgid());
    353     }
    354 }
    355 
    356 
    357 /// Constructs a path to a work directory based on a template.
    358 ///
    359 /// \param template Template of the work directory to create.  Should be a
    360 ///      basename and must include the XXXXXX placeholder string.  The directory
    361 ///      is created within the temporary directory specified by the TMPDIR
    362 ///      environment variable or the builtin value in kyua_run_tmpdir.
    363 /// \param [out] work_directory Pointer to a dynamically-allocated string
    364 ///      containing the full path to the work directory.  The caller is
    365 ///      responsible for releasing this string.
    366 ///
    367 /// \return An error if there is a problem (most likely OOM), or OK otherwise.
    368 static kyua_error_t
    369 build_work_directory_path(const char* template, char** work_directory)
    370 {
    371     assert(strstr(template, "XXXXXX") != NULL);
    372 
    373     const char* tmpdir = getenv("TMPDIR");
    374     if (tmpdir == NULL)
    375         return kyua_text_printf(work_directory, "%s/%s", kyua_run_tmpdir,
    376                                 template);
    377     else
    378         return kyua_text_printf(work_directory, "%s/%s", tmpdir, template);
    379 }
    380 
    381 
    382 /// Initializes the run_params parameters with default values.
    383 ///
    384 /// \param [out] run_params The object to initialize.
    385 void
    386 kyua_run_params_init(kyua_run_params_t* run_params)
    387 {
    388     run_params->timeout_seconds = 60;
    389     run_params->unprivileged_user = getuid();
    390     run_params->unprivileged_group = getgid();
    391     run_params->work_directory = ".";
    392 }
    393 
    394 
    395 /// Executes a program and exits if there is a problem.
    396 ///
    397 /// This routine is supposed to be used in conjunction with kyua_run_fork and
    398 /// kyua_run_wait so that the various return codes of the exec system call are
    399 /// properly propagated to the parent process.
    400 ///
    401 /// \param program Path to the program to run.
    402 /// \param args Arguments to the program.
    403 void
    404 kyua_run_exec(const char* program, const char* const* args)
    405 {
    406     (void)execvp(program, KYUA_DEFS_UNCONST(args));
    407     switch (errno) {
    408     case EACCES:
    409         exit(exit_exec_eacces);
    410     case ENOENT:
    411         exit(exit_exec_enoent);
    412     default:
    413         err(exit_exec_unknown, "execvp failed");
    414     }
    415 }
    416 
    417 
    418 /// Forks and isolates the child process.
    419 ///
    420 /// The created subprocess must be waited for with kyua_run_wait().
    421 ///
    422 /// \param run_params Parameters that describe how to isolate the newly-created
    423 ///     process.
    424 /// \param [out] out_pid The PID of the child in the parent, or 0 in the child.
    425 ///     The value left here should only be accessed if this function does not
    426 ///     return an error.
    427 ///
    428 /// \return An error object if fork(2) fails.
    429 kyua_error_t
    430 kyua_run_fork(const kyua_run_params_t* run_params, pid_t* const out_pid)
    431 {
    432     protect();
    433     pid_t pid = fork();
    434     if (pid == -1) {
    435         unprotect();
    436         *out_pid = pid;  // Not necessary, but avoid mistakes in the caller.
    437         return kyua_libc_error_new(errno, "fork failed");
    438     } else if (pid == 0) {
    439         unprotect();
    440         setup_child(run_params);
    441         *out_pid = pid;
    442         return kyua_error_ok();
    443     } else {
    444         pid_to_kill = pid;
    445         unprotect();
    446 
    447         setup_signal(SIGALRM, timeout_handler, &old_sigalrm);
    448         process_timed_out = false;
    449         setup_timer(run_params->timeout_seconds, &old_timer);
    450 
    451         *out_pid = pid;
    452         return kyua_error_ok();
    453     }
    454 }
    455 
    456 
    457 /// Waits for a process started via kyua_run_fork.
    458 ///
    459 /// \param pid The PID of the child to wait for.
    460 /// \param [out] status The exit status of the awaited process.
    461 /// \param [out] timed_out Whether the process timed out or not.
    462 ///
    463 /// \return An error if the process failed due to an problem in kyua_run_exec.
    464 /// However, note that the wait for the process itself is expected to have been
    465 /// successful.
    466 kyua_error_t
    467 kyua_run_wait(const pid_t pid, int* status, bool* timed_out)
    468 {
    469     int tmp_status;
    470     const pid_t waited_pid = waitpid(pid, &tmp_status, 0);
    471     assert(pid == waited_pid);
    472 
    473     protect();
    474     (void)setitimer(ITIMER_REAL, &old_timer, NULL);
    475     (void)sigaction(SIGALRM, &old_sigalrm, NULL);
    476     pid_to_kill = -1;
    477     unprotect();
    478 
    479     killpg(pid, SIGKILL);
    480 
    481     if (WIFEXITED(tmp_status)) {
    482         if (WEXITSTATUS(tmp_status) == exit_setup_child) {
    483             return kyua_generic_error_new("Failed to isolate subprocess; "
    484                                           "see stderr for details");
    485         } else if (WEXITSTATUS(tmp_status) == exit_exec_eacces) {
    486             return kyua_libc_error_new(EACCES, "execvp failed");
    487         } else if (WEXITSTATUS(tmp_status) == exit_exec_enoent) {
    488             return kyua_libc_error_new(ENOENT, "execvp failed");
    489         } else if (WEXITSTATUS(tmp_status) == exit_exec_unknown) {
    490             return kyua_generic_error_new("execvp failed; see stderr for "
    491                                           "details");
    492         } else {
    493             // Fall-through.
    494         }
    495     }
    496     *status = tmp_status;
    497     *timed_out = process_timed_out;
    498     return kyua_error_ok();
    499 }
    500 
    501 
    502 /// Creates a temporary directory for use by a subprocess.
    503 ///
    504 /// The temporary directory must be deleted with kyua_run_work_directory_leave.
    505 ///
    506 /// \param template Template of the work directory to create.  Should be a
    507 ///      basename and must include the XXXXXX placeholder string.  The directory
    508 ///      is created within the temporary directory specified by the TMPDIR
    509 ///      environment variable or the builtin value.
    510 /// \param uid User to set the owner of the directory to.
    511 /// \param gid Group to set the owner of the directory to.
    512 /// \param [out] out_work_directory Updated with a pointer to a dynamic string
    513 ///      holding the path to the created work directory.  This must be passed as
    514 ///      is to kyua_run_work_directory_leave, which takes care of freeing the
    515 ///      memory.
    516 ///
    517 /// \return An error code if there is a problem creating the directory.
    518 kyua_error_t
    519 kyua_run_work_directory_enter(const char* template, const uid_t uid,
    520                               const gid_t gid, char** out_work_directory)
    521 {
    522     kyua_error_t error = kyua_error_ok();
    523 
    524     signal_fired = false;
    525     setup_signal(SIGHUP, cleanup_handler, &old_sighup);
    526     setup_signal(SIGINT, cleanup_handler, &old_sigint);
    527     setup_signal(SIGTERM, cleanup_handler, &old_sigterm);
    528 
    529     char* work_directory;
    530     error = build_work_directory_path(template, &work_directory);
    531     if (kyua_error_is_set(error))
    532         goto err_signals;
    533 
    534     if (mkdtemp(work_directory) == NULL) {
    535         error = kyua_libc_error_new(errno, "mkdtemp(%s) failed",
    536                                     work_directory);
    537         goto err_work_directory_variable;
    538     }
    539 
    540     if (uid != getuid() || gid != getgid()) {
    541         if (chown(work_directory, uid, gid) == -1) {
    542             error = kyua_libc_error_new(errno,
    543                 "chown(%s, %ld, %ld) failed; uid is %ld and gid is %ld",
    544                 work_directory, (long int)uid, (long int)gid,
    545                 (long int)getuid(), (long int)getgid());
    546             goto err_work_directory_file;
    547         }
    548     }
    549 
    550     *out_work_directory = work_directory;
    551     assert(!kyua_error_is_set(error));
    552     goto out;
    553 
    554 err_work_directory_file:
    555     (void)rmdir(work_directory);
    556 err_work_directory_variable:
    557     free(work_directory);
    558 err_signals:
    559     (void)sigaction(SIGTERM, &old_sigterm, NULL);
    560     (void)sigaction(SIGINT, &old_sigint, NULL);
    561     (void)sigaction(SIGHUP, &old_sighup, NULL);
    562 out:
    563     return error;
    564 }
    565 
    566 
    567 /// Deletes a temporary directory created by kyua_run_work_directory_enter().
    568 ///
    569 /// \param [in,out] work_directory The pointer to the work_directory string as
    570 ///     originally returned by kyua_run_work_directory_leave().  This is
    571 ///     explicitly invalidated by this function to clearly denote that this
    572 ///     performs the memory releasing.
    573 ///
    574 /// \return An error code if the cleanup of the directory fails.  Note that any
    575 /// intermediate errors during the cleanup are sent to stderr.
    576 kyua_error_t
    577 kyua_run_work_directory_leave(char** work_directory)
    578 {
    579     kyua_error_t error = kyua_fs_cleanup(*work_directory);
    580 
    581     free(*work_directory);
    582     *work_directory = NULL;
    583 
    584     (void)sigaction(SIGTERM, &old_sigterm, NULL);
    585     (void)sigaction(SIGHUP, &old_sighup, NULL);
    586     (void)sigaction(SIGINT, &old_sigint, NULL);
    587 
    588     // At this point, we have cleaned up the work directory and we could
    589     // (should?)  re-deliver the signal to ourselves so that we terminated with
    590     // the right code.  However, we just let this return and allow the caller
    591     // code to perform any other cleanups instead.
    592 
    593     return error;
    594 }
    595