From c9dbf64201acb9107985f57188fe9eb5a23a4a43 Mon Sep 17 00:00:00 2001 From: netblue30 Date: Wed, 25 Oct 2017 09:32:34 -0400 Subject: --timeout, fix #1614 --- src/firejail/firejail.h | 2 ++ src/firejail/main.c | 2 ++ src/firejail/profile.c | 7 ++++++- src/firejail/sandbox.c | 20 +++++++++++++++++++- src/firejail/usage.c | 2 ++ src/firejail/util.c | 14 ++++++++++++++ src/man/firejail-profile.txt | 3 +++ src/man/firejail.txt | 7 +++++++ 8 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 1b399ba10..a6b57f263 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -255,6 +255,7 @@ typedef struct config_t { long long unsigned rlimit_fsize; long long unsigned rlimit_sigpending; long long unsigned rlimit_as; + unsigned timeout; // maximum time elapsed before killing the sandbox // cpu affinity, nice and control groups uint32_t cpus; @@ -513,6 +514,7 @@ void create_empty_file_as_root(const char *dir, mode_t mode); int set_perms(const char *fname, uid_t uid, gid_t gid, mode_t mode); void mkdir_attr(const char *fname, mode_t mode, uid_t uid, gid_t gid); char *read_text_file_or_exit(const char *fname); +unsigned extract_timeout(const char *str); // fs_var.c void fs_var_log(void); // mounting /var/log diff --git a/src/firejail/main.c b/src/firejail/main.c index 04900d6f9..67b40f9c2 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -2156,6 +2156,8 @@ int main(int argc, char **argv) { //************************************* // command //************************************* + else if (strncmp(argv[i], "--timeout=", 10) == 0) + cfg.timeout = extract_timeout(argv[i] + 10); else if (strcmp(argv[i], "--audit") == 0) { arg_audit_prog = LIBDIR "/firejail/faudit"; arg_audit = 1; diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 9f49d7405..dc1333988 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c @@ -1054,7 +1054,12 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { return 0; } - + + if (strncmp(ptr, "timeout ", 8) == 0) { + cfg.timeout = extract_timeout(ptr +8); + return 0; + } + if (strncmp(ptr, "join-or-start ", 14) == 0) { // try to join by name only pid_t pid; diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index abdbbfecd..b92483c66 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c @@ -201,6 +201,14 @@ static int monitor_application(pid_t app_pid) { signal (SIGTERM, sandbox_handler); EUID_USER(); + // handle --timeout + int options = 0;; + unsigned timeout = 0; + if (cfg.timeout) { + options = WNOHANG; + timeout = cfg.timeout; + } + int status = 0; while (monitored_pid) { usleep(20000); @@ -214,9 +222,19 @@ static int monitor_application(pid_t app_pid) { pid_t rv; do { - rv = waitpid(-1, &status, 0); + rv = waitpid(-1, &status, options); if (rv == -1) break; + + // handle --timeout + if (options && --timeout == 0) { + kill(-1, SIGTERM); + flush_stdin(); + sleep(1); + _exit(1); + } + + sleep(1); } while(rv != monitored_pid); if (arg_debug) diff --git a/src/firejail/usage.c b/src/firejail/usage.c index 4222d4d1c..0bc3b20fd 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c @@ -200,6 +200,8 @@ void usage(void) { printf(" --shell=none - run the program directly without a user shell.\n"); printf(" --shell=program - set default user shell.\n"); printf(" --shutdown=name|pid - shutdown the sandbox identified by name or PID.\n"); + printf(" --timeout=hh:mm:ss - kill the sandbox automatically after the time\n"); + printf("\thas elapsed.\n"); printf(" --tmpfs=dirname - mount a tmpfs filesystem on directory dirname.\n"); printf(" --top - monitor the most CPU-intensive sandboxes.\n"); printf(" --trace - trace open, access and connect system calls.\n"); diff --git a/src/firejail/util.c b/src/firejail/util.c index 559f7ee48..cea2b76e3 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c @@ -949,3 +949,17 @@ errexit: fprintf(stderr, "Error: cannot read %s\n", fname); exit(1); } + + +unsigned extract_timeout(const char *str) { + unsigned s; + unsigned m; + unsigned h; + int rv = sscanf(str, "%02u:%02u:%02u", &h, &m, &s); + if (rv != 3) { + fprintf(stderr, "Error: invalid timeout, please use a hh:mm:ss format\n"); + exit(1); + } + + return h * 3600 + m * 60 + s; +} diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt index 808fc7440..39680ab0a 100644 --- a/src/man/firejail-profile.txt +++ b/src/man/firejail-profile.txt @@ -408,6 +408,9 @@ Set a nice value of -5 to all processes running inside the sandbox. .TP \fBcgroup /sys/fs/cgroup/g1/tasks The sandbox is placed in g1 control group. +.TP +\fBtimeout hh:mm:ss +Kill the sandbox automatically after the time has elapsed. The time is specified in hours/minutes/seconds format. .SH User Environment .TP diff --git a/src/man/firejail.txt b/src/man/firejail.txt index d2e04675d..d725bb883 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt @@ -1849,6 +1849,13 @@ $ firejail \-\-list .br $ firejail \-\-shutdown=3272 .TP +\fB\-\-timeout=hh:mm:ss +Kill the sandbox automatically after the time has elapsed. The time is specified in hours/minutes/seconds format. +.br + +.br +$ firejail \-\-timeout=01:30:00 firefox +.TP \fB\-\-tmpfs=dirname Mount a tmpfs filesystem on directory dirname. This option is available only when running the sandbox as root. File globbing is supported, see \fBFILE GLOBBING\fR section for more details. -- cgit v1.2.3-54-g00ecf