]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
utils: fix task_blocking_signal() 2354/head
authorChristian Brauner <christian.brauner@ubuntu.com>
Sat, 26 May 2018 12:22:51 +0000 (14:22 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Sat, 26 May 2018 19:47:46 +0000 (21:47 +0200)
Closes #2342.

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/lxccontainer.c
src/lxc/parse.c
src/lxc/parse.h
src/lxc/seccomp.c
src/lxc/utils.c
src/lxc/utils.h
src/tests/Makefile.am
src/tests/lxc-test-utils.c

index 828ebb8e54d7d22bdf39ebd968bfded133b3ba0a..8a21d97e46f0b9c15642d4dadfcca56f3907a179 100644 (file)
@@ -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
index d3589c1f5c61dfb06a80e084dd016c19d3e5f1e2..01801c58207e822b8c716aba10b4e28772e8ecca 100644 (file)
@@ -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;
index 361ad33ea33c6d7fac825f53a5c12365984f2e58..9809e9cec09416f01e04638217e33810523d3522 100644 (file)
@@ -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
index 7ae76a71ca5875efa20798bc749087c9241cc27f..e32c23b43d764674d62b4f422dcf7107265b5458 100644 (file)
@@ -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;
index 34467ad7da21c7955617dcb0dea768d8ec63da80..04f179821b3866811d2644317a54c8d4e3849e6b 100644 (file)
@@ -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;
 
index 93e2a3ee44ab2f3b873665bdf48f20108dd2af8c..fd756597a6e3f8713f5f7dae73fcd42425a78e1c 100644 (file)
@@ -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);
 
index f39c3e047e6108477416fea1a8268ab26087bf41..a2179c3ca798b2c2400ca9329dc00a1a8487697c 100644 (file)
@@ -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
index 1fa702ca6a2436c91620f049e8c2130876d044e2..0da2011a4600a3c647b474f1f1634843ddc54098 100644 (file)
 #include <fcntl.h>
 #include <inttypes.h>
 #include <limits.h>
+#include <pthread.h>
 #include <sched.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <unistd.h>
 
 #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);
 }