utils: fix task_blocking_signal()

Closes #2342.

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
This commit is contained in:
Christian Brauner 2018-05-26 14:22:51 +02:00
parent a2db71c041
commit 573ad77fc2
No known key found for this signature in database
GPG Key ID: 8EB056D53EECB12D
8 changed files with 99 additions and 13 deletions

View 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). */ /* Detect whether we should send SIGRTMIN + 3 (e.g. systemd). */
if (c->lxc_conf && c->lxc_conf->haltsignal) if (c->lxc_conf && c->lxc_conf->haltsignal)
haltsignal = 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); haltsignal = (SIGRTMIN + 3);
/* Add a new state client before sending the shutdown signal so that we /* Add a new state client before sending the shutdown signal so that we

View 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) int lxc_char_left_gc(const char *buffer, size_t len)
{ {
size_t i; size_t i;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (buffer[i] == ' ' || if (buffer[i] == ' ' ||
buffer[i] == '\t') buffer[i] == '\t')
continue; continue;
return i; return i;
} }
return 0; return 0;
} }
int lxc_char_right_gc(const char *buffer, size_t len) int lxc_char_right_gc(const char *buffer, size_t len)
{ {
int i; int i;
for (i = len - 1; i >= 0; i--) { for (i = len - 1; i >= 0; i--) {
if (buffer[i] == ' ' || if (buffer[i] == ' ' ||
buffer[i] == '\t' || buffer[i] == '\t' ||
buffer[i] == '\n' || buffer[i] == '\n' ||
buffer[i] == '\0') buffer[i] == '\0')
continue; continue;
return i + 1; return i + 1;
} }
return 0; 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 lxc_is_line_empty(const char *line)
{ {
int i; int i;

View 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 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); extern int lxc_is_line_empty(const char *line);
/* mmap() wrapper. lxc_strmmap() will take care to \0-terminate files so that /* mmap() wrapper. lxc_strmmap() will take care to \0-terminate files so that

View File

@ -215,13 +215,13 @@ static int get_seccomp_arg_value(char *key, struct seccomp_v2_rule_args *rule_ar
return -1; return -1;
} }
ret = lxc_safe_uint64(v, &value); ret = lxc_safe_uint64(v, &value, 0);
if (ret < 0) { if (ret < 0) {
ERROR("Invalid argument value"); ERROR("Invalid argument value");
return -1; return -1;
} }
ret = lxc_safe_uint64(m, &mask); ret = lxc_safe_uint64(m, &mask, 0);
if (ret < 0) { if (ret < 0) {
ERROR("Invalid argument mask"); ERROR("Invalid argument mask");
return -1; return -1;

View File

@ -1815,12 +1815,12 @@ int lxc_count_file_lines(const char *fn)
/* Check whether a signal is blocked by a process. */ /* Check whether a signal is blocked by a process. */
/* /proc/pid-to-str/status\0 = (5 + 21 + 7 + 1) */ /* /proc/pid-to-str/status\0 = (5 + 21 + 7 + 1) */
#define __PROC_STATUS_LEN (6 + (LXC_NUMSTRLEN64) + 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; int ret;
char status[__PROC_STATUS_LEN]; char status[__PROC_STATUS_LEN];
FILE *f; FILE *f;
long unsigned int sigblk = 0; uint64_t sigblk = 0, one = 1;
size_t n = 0; size_t n = 0;
bool bret = false; bool bret = false;
char *line = NULL; char *line = NULL;
@ -1834,14 +1834,20 @@ bool task_blocking_signal(pid_t pid, int signal)
return bret; return bret;
while (getline(&line, &n, f) != -1) { while (getline(&line, &n, f) != -1) {
char *numstr;
if (strncmp(line, "SigBlk:", 7)) if (strncmp(line, "SigBlk:", 7))
continue; 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; goto out;
break;
} }
if (sigblk & (1LU << (signal - 1))) if (sigblk & (one << (signal - 1)))
bret = true; bret = true;
out: out:
@ -1958,7 +1964,7 @@ int lxc_safe_ulong(const char *numstr, unsigned long *converted)
return 0; 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; char *err = NULL;
uint64_t u; uint64_t u;
@ -1970,7 +1976,7 @@ int lxc_safe_uint64(const char *numstr, uint64_t *converted)
return -EINVAL; return -EINVAL;
errno = 0; errno = 0;
u = strtoull(numstr, &err, 0); u = strtoull(numstr, &err, base);
if (errno == ERANGE && u == ULLONG_MAX) if (errno == ERANGE && u == ULLONG_MAX)
return -ERANGE; return -ERANGE;

View 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); extern int lxc_preserve_ns(const int pid, const char *ns);
/* Check whether a signal is blocked by a process. */ /* 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. */ /* Helper functions to parse numbers. */
extern int lxc_safe_uint(const char *numstr, unsigned int *converted); 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(const char *numstr, long int *converted);
extern int lxc_safe_long_long(const char *numstr, long 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_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. */ /* Handles B, kb, MB, GB. Detects overflows and reports -ERANGE. */
extern int parse_byte_size_string(const char *s, int64_t *converted); extern int parse_byte_size_string(const char *s, int64_t *converted);

View File

@ -44,7 +44,8 @@ AM_CFLAGS=-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
-I $(top_srcdir)/src/lxc \ -I $(top_srcdir)/src/lxc \
-I $(top_srcdir)/src/lxc/bdev \ -I $(top_srcdir)/src/lxc/bdev \
-I $(top_srcdir)/src/lxc/cgroups \ -I $(top_srcdir)/src/lxc/cgroups \
-I $(top_srcdir)/src/lxc/tools -I $(top_srcdir)/src/lxc/tools \
-pthread
if ENABLE_APPARMOR if ENABLE_APPARMOR
AM_CFLAGS += -DHAVE_APPARMOR AM_CFLAGS += -DHAVE_APPARMOR

View File

@ -27,14 +27,16 @@
#include <fcntl.h> #include <fcntl.h>
#include <inttypes.h> #include <inttypes.h>
#include <limits.h> #include <limits.h>
#include <pthread.h>
#include <sched.h> #include <sched.h>
#include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h>
#include "lxctest.h" #include "lxctest.h"
#include "utils.h" #include "utils.h"
@ -507,6 +509,67 @@ void test_lxc_config_net_hwaddr(void)
exit(EXIT_FAILURE); 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[]) int main(int argc, char *argv[])
{ {
test_lxc_string_replace(); test_lxc_string_replace();
@ -518,6 +581,7 @@ int main(int argc, char *argv[])
test_lxc_safe_long(); test_lxc_safe_long();
test_parse_byte_size_string(); test_parse_byte_size_string();
test_lxc_config_net_hwaddr(); test_lxc_config_net_hwaddr();
test_task_blocks_signal();
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }