]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
utils: fix task_blocking_signal()
authorChristian Brauner <christian.brauner@ubuntu.com>
Sat, 26 May 2018 12:22:51 +0000 (14:22 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Mon, 10 Dec 2018 07:41:09 +0000 (08:41 +0100)
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 cdbffd9bcd3fd1fda7829bcf64cebd743904b923..84a7ddeede23fd33498d4138b6b8d531a3e32efd 100644 (file)
@@ -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
index b8eef7f04eaeb141a2f77e95a32299ff9d16aa4d..82b927b7d02590e7e3dc55a11b6e57878436d836 100644 (file)
@@ -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;
index 8f753198b8fd3ee818646029367f45428d0477ff..b3faba46c78994f60152317c69ff932e819280a9 100644 (file)
@@ -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
index df851c5dc463e2e81bd4cc114565bf6891d43d7e..ece206d4b03555decc4c7b497efab4e01e8c1449 100644 (file)
@@ -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
 
index 56d64b4aecd7e62282b274642df6a997b7d4cd29..fdd59fa2acad2132b6e988715b8e65dd106149b7 100644 (file)
@@ -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;
index ebee2bf19f403d4426d7a1faaf09ee10f3b8ecec..84e2f3a84e89c1c8fa06d4693cc9e68ceb4d959b 100644 (file)
@@ -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);
 
index ea2cf8c763848a07b5814805c1ffc27ffbc62128..6cbf90a5d737c9296854b868b52990ca8810f7cf 100644 (file)
@@ -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
index 6f56ae675fad204b70a6e41e5ebffa7422222ee7..caed4b5a7efd5142db8c890866e68a8ff6a5ccec 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"
@@ -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);
 }