From: Christian Brauner Date: Sat, 26 May 2018 12:22:51 +0000 (+0200) Subject: utils: fix task_blocking_signal() X-Git-Tag: lxc-2.0.10~123 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1bd237a60722c83320acae215a21ff98d35a35ad;p=thirdparty%2Flxc.git utils: fix task_blocking_signal() Closes #2342. Signed-off-by: Christian Brauner --- diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index cdbffd9bc..84a7ddeed 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -1837,7 +1837,7 @@ static bool do_lxcapi_shutdown(struct lxc_container *c, int timeout) /* Detect whether we should send SIGRTMIN + 3 (e.g. systemd). */ if (c->lxc_conf && c->lxc_conf->haltsignal) haltsignal = c->lxc_conf->haltsignal; - else if (task_blocking_signal(pid, (SIGRTMIN + 3))) + else if (task_blocks_signal(pid, (SIGRTMIN + 3))) haltsignal = (SIGRTMIN + 3); /* Add a new state client before sending the shutdown signal so that we diff --git a/src/lxc/parse.c b/src/lxc/parse.c index b8eef7f04..82b927b7d 100644 --- a/src/lxc/parse.c +++ b/src/lxc/parse.c @@ -67,29 +67,42 @@ int lxc_file_for_each_line(const char *file, lxc_file_cb callback, void *data) int lxc_char_left_gc(const char *buffer, size_t len) { size_t i; + for (i = 0; i < len; i++) { if (buffer[i] == ' ' || buffer[i] == '\t') continue; + return i; } + return 0; } int lxc_char_right_gc(const char *buffer, size_t len) { int i; + for (i = len - 1; i >= 0; i--) { if (buffer[i] == ' ' || buffer[i] == '\t' || buffer[i] == '\n' || buffer[i] == '\0') continue; + return i + 1; } + return 0; } +char *lxc_trim_whitespace_in_place(char *buffer) +{ + buffer += lxc_char_left_gc(buffer, strlen(buffer)); + buffer[lxc_char_right_gc(buffer, strlen(buffer))] = '\0'; + return buffer; +} + int lxc_is_line_empty(const char *line) { int i; diff --git a/src/lxc/parse.h b/src/lxc/parse.h index 8f753198b..b3faba46c 100644 --- a/src/lxc/parse.h +++ b/src/lxc/parse.h @@ -35,6 +35,8 @@ extern int lxc_char_left_gc(const char *buffer, size_t len); extern int lxc_char_right_gc(const char *buffer, size_t len); +extern char *lxc_trim_whitespace_in_place(char *buffer); + extern int lxc_is_line_empty(const char *line); #endif diff --git a/src/lxc/seccomp.c b/src/lxc/seccomp.c index df851c5dc..ece206d4b 100644 --- a/src/lxc/seccomp.c +++ b/src/lxc/seccomp.c @@ -128,6 +128,7 @@ static uint32_t get_and_clear_v2_action(char *line, uint32_t def_action) case -1: return def_action; default: return ret; } + return ret; } #endif diff --git a/src/lxc/utils.c b/src/lxc/utils.c index 56d64b4ae..fdd59fa2a 100644 --- a/src/lxc/utils.c +++ b/src/lxc/utils.c @@ -1770,12 +1770,12 @@ int lxc_strmunmap(void *addr, size_t length) /* Check whether a signal is blocked by a process. */ /* /proc/pid-to-str/status\0 = (5 + 21 + 7 + 1) */ #define __PROC_STATUS_LEN (6 + (LXC_NUMSTRLEN64) + 7 + 1) -bool task_blocking_signal(pid_t pid, int signal) +bool task_blocks_signal(pid_t pid, int signal) { int ret; char status[__PROC_STATUS_LEN]; FILE *f; - long unsigned int sigblk = 0; + uint64_t sigblk = 0, one = 1; size_t n = 0; bool bret = false; char *line = NULL; @@ -1789,14 +1789,20 @@ bool task_blocking_signal(pid_t pid, int signal) return bret; while (getline(&line, &n, f) != -1) { + char *numstr; + if (strncmp(line, "SigBlk:", 7)) continue; - if (sscanf(line + 7, "%lx", &sigblk) != 1) + numstr = lxc_trim_whitespace_in_place(line + 7); + ret = lxc_safe_uint64(numstr, &sigblk, 16); + if (ret < 0) goto out; + + break; } - if (sigblk & (1LU << (signal - 1))) + if (sigblk & (one << (signal - 1))) bret = true; out: @@ -1913,6 +1919,29 @@ int lxc_safe_ulong(const char *numstr, unsigned long *converted) return 0; } +int lxc_safe_uint64(const char *numstr, uint64_t *converted, int base) +{ + char *err = NULL; + uint64_t u; + + while (isspace(*numstr)) + numstr++; + + if (*numstr == '-') + return -EINVAL; + + errno = 0; + u = strtoull(numstr, &err, base); + if (errno == ERANGE && u == ULLONG_MAX) + return -ERANGE; + + if (err == numstr || *err != '\0') + return -EINVAL; + + *converted = u; + return 0; +} + int lxc_safe_int(const char *numstr, int *converted) { char *err = NULL; diff --git a/src/lxc/utils.h b/src/lxc/utils.h index ebee2bf19..84e2f3a84 100644 --- a/src/lxc/utils.h +++ b/src/lxc/utils.h @@ -522,7 +522,7 @@ int lxc_count_file_lines(const char *fn); int lxc_preserve_ns(const int pid, const char *ns); /* Check whether a signal is blocked by a process. */ -bool task_blocking_signal(pid_t pid, int signal); +extern bool task_blocks_signal(pid_t pid, int signal); /* Helper functions to parse numbers. */ extern int lxc_safe_uint(const char *numstr, unsigned int *converted); @@ -530,6 +530,7 @@ extern int lxc_safe_int(const char *numstr, int *converted); extern int lxc_safe_long(const char *numstr, long int *converted); extern int lxc_safe_long_long(const char *numstr, long long int *converted); extern int lxc_safe_ulong(const char *numstr, unsigned long *converted); +extern int lxc_safe_uint64(const char *numstr, uint64_t *converted, int base); /* Handles B, kb, MB, GB. Detects overflows and reports -ERANGE. */ extern int parse_byte_size_string(const char *s, int64_t *converted); diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index ea2cf8c76..6cbf90a5d 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -40,7 +40,8 @@ AM_CFLAGS=-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \ -I $(top_srcdir)/src/lxc \ -I $(top_srcdir)/src/lxc/bdev \ -I $(top_srcdir)/src/lxc/cgroups \ - -I $(top_srcdir)/src/lxc/tools + -I $(top_srcdir)/src/lxc/tools \ + -pthread if ENABLE_APPARMOR AM_CFLAGS += -DHAVE_APPARMOR diff --git a/src/tests/lxc-test-utils.c b/src/tests/lxc-test-utils.c index 6f56ae675..caed4b5a7 100644 --- a/src/tests/lxc-test-utils.c +++ b/src/tests/lxc-test-utils.c @@ -27,14 +27,16 @@ #include #include #include +#include #include +#include #include #include #include -#include #include #include #include +#include #include "lxctest.h" #include "utils.h" @@ -502,6 +504,67 @@ void test_parse_byte_size_string(void) } } +void test_task_blocks_signal(void) +{ + int ret; + pid_t pid; + + pid = fork(); + if (pid < 0) + _exit(EXIT_FAILURE); + + if (pid == 0) { + int i; + sigset_t mask; + int signals[] = {SIGBUS, SIGILL, SIGSEGV, + SIGWINCH, SIGQUIT, SIGUSR1, + SIGUSR2, SIGRTMIN + 3, SIGRTMIN + 4}; + + sigemptyset(&mask); + + for (i = 0; i < (sizeof(signals) / sizeof(signals[0])); i++) { + ret = sigaddset(&mask, signals[i]); + if (ret < 0) + _exit(EXIT_FAILURE); + } + + ret = pthread_sigmask(SIG_BLOCK, &mask, NULL); + if (ret < 0) { + lxc_error("%s\n", "Failed to block signals"); + _exit(EXIT_FAILURE); + } + + for (i = 0; i < (sizeof(signals) / sizeof(signals[0])); i++) { + if (!task_blocks_signal(getpid(), signals[i])) { + lxc_error("Failed to detect blocked signal " + "(idx = %d, signal number = %d)\n", + i, signals[i]); + _exit(EXIT_FAILURE); + } + } + + if (task_blocks_signal(getpid(), SIGKILL)) { + lxc_error("%s\n", + "Falsely detected SIGKILL as blocked signal"); + _exit(EXIT_FAILURE); + } + + if (task_blocks_signal(getpid(), SIGSTOP)) { + lxc_error("%s\n", + "Falsely detected SIGSTOP as blocked signal"); + _exit(EXIT_FAILURE); + } + + _exit(EXIT_SUCCESS); + } + + ret = wait_for_pid(pid); + if (ret < 0) + _exit(EXIT_FAILURE); + + return; +} + int main(int argc, char *argv[]) { test_lxc_string_replace(); @@ -512,6 +575,7 @@ int main(int argc, char *argv[]) test_lxc_safe_int(); test_lxc_safe_long(); test_parse_byte_size_string(); + test_task_blocks_signal(); exit(EXIT_SUCCESS); }