From: Christian Brauner Date: Sat, 26 May 2018 12:22:51 +0000 (+0200) Subject: utils: fix task_blocking_signal() X-Git-Tag: lxc-3.1.0~285^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=573ad77fc275bab72a5820c35b16c51139d556fc;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 828ebb8e5..8a21d97e4 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -2008,7 +2008,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 d3589c1f5..01801c582 100644 --- a/src/lxc/parse.c +++ b/src/lxc/parse.c @@ -144,29 +144,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 361ad33ea..9809e9cec 100644 --- a/src/lxc/parse.h +++ b/src/lxc/parse.h @@ -41,6 +41,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); /* mmap() wrapper. lxc_strmmap() will take care to \0-terminate files so that diff --git a/src/lxc/seccomp.c b/src/lxc/seccomp.c index 7ae76a71c..e32c23b43 100644 --- a/src/lxc/seccomp.c +++ b/src/lxc/seccomp.c @@ -215,13 +215,13 @@ static int get_seccomp_arg_value(char *key, struct seccomp_v2_rule_args *rule_ar return -1; } - ret = lxc_safe_uint64(v, &value); + ret = lxc_safe_uint64(v, &value, 0); if (ret < 0) { ERROR("Invalid argument value"); return -1; } - ret = lxc_safe_uint64(m, &mask); + ret = lxc_safe_uint64(m, &mask, 0); if (ret < 0) { ERROR("Invalid argument mask"); return -1; diff --git a/src/lxc/utils.c b/src/lxc/utils.c index 34467ad7d..04f179821 100644 --- a/src/lxc/utils.c +++ b/src/lxc/utils.c @@ -1815,12 +1815,12 @@ int lxc_count_file_lines(const char *fn) /* 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; @@ -1834,14 +1834,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: @@ -1958,7 +1964,7 @@ int lxc_safe_ulong(const char *numstr, unsigned long *converted) return 0; } -int lxc_safe_uint64(const char *numstr, uint64_t *converted) +int lxc_safe_uint64(const char *numstr, uint64_t *converted, int base) { char *err = NULL; uint64_t u; @@ -1970,7 +1976,7 @@ int lxc_safe_uint64(const char *numstr, uint64_t *converted) return -EINVAL; errno = 0; - u = strtoull(numstr, &err, 0); + u = strtoull(numstr, &err, base); if (errno == ERANGE && u == ULLONG_MAX) return -ERANGE; diff --git a/src/lxc/utils.h b/src/lxc/utils.h index 93e2a3ee4..fd756597a 100644 --- a/src/lxc/utils.h +++ b/src/lxc/utils.h @@ -523,7 +523,7 @@ extern int lxc_count_file_lines(const char *fn); extern int lxc_preserve_ns(const int pid, const char *ns); /* Check whether a signal is blocked by a process. */ -extern 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); @@ -531,7 +531,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); +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 f39c3e047..a2179c3ca 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -44,7 +44,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 1fa702ca6..0da2011a4 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" @@ -507,6 +509,67 @@ void test_lxc_config_net_hwaddr(void) exit(EXIT_FAILURE); } +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(); @@ -518,6 +581,7 @@ int main(int argc, char *argv[]) test_lxc_safe_long(); test_parse_byte_size_string(); test_lxc_config_net_hwaddr(); + test_task_blocks_signal(); exit(EXIT_SUCCESS); }