Closes #2342.
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
/* 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
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;
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
case -1: return def_action;
default: return ret;
}
+ return ret;
}
#endif
/* 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;
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:
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;
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);
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);
-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
#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"
}
}
+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();
test_lxc_safe_int();
test_lxc_safe_long();
test_parse_byte_size_string();
+ test_task_blocks_signal();
exit(EXIT_SUCCESS);
}