nss: block various signals while running NSS lookups
authorLennart Poettering <lennart@poettering.net>
Tue, 26 Jan 2016 21:34:46 +0000 (22:34 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 27 Jan 2016 01:22:58 +0000 (02:22 +0100)
Let's make sure our poll() calls don't get interrupted where they shouldn't (SIGALRM, ...), but allow them to be
interrupted where they should (SIGINT, ...).

Fixes #1965

.gitignore
Makefile.am
src/basic/nss-util.h
src/basic/signal-util.h
src/nss-myhostname/nss-myhostname.c
src/nss-mymachines/nss-mymachines.c
src/nss-resolve/nss-resolve.c
src/test/test-signal-util.c [new file with mode: 0644]

index c045ea4..cc2cd22 100644 (file)
 /test-sched-prio
 /test-set
 /test-sigbus
+/test-signal-util
 /test-siphash24
 /test-sleep
 /test-socket-util
index 73d2375..90bc5d7 100644 (file)
@@ -1500,7 +1500,8 @@ tests += \
        test-arphrd-list \
        test-dns-domain \
        test-install-root \
-       test-rlimit-util
+       test-rlimit-util \
+       test-signal-util
 
 if HAVE_ACL
 tests += \
@@ -1881,6 +1882,12 @@ test_ask_password_api_SOURCES = \
 test_ask_password_api_LDADD = \
        libshared.la
 
+test_signal_util_SOURCES = \
+       src/test/test-signal-util.c
+
+test_signal_util_LDADD = \
+       libshared.la
+
 BUILT_SOURCES += \
        src/test/test-hashmap-ordered.c
 
index cc30d93..4be0136 100644 (file)
@@ -27,6 +27,8 @@
 #include <pwd.h>
 #include <resolv.h>
 
+#define NSS_SIGNALS_BLOCK SIGALRM,SIGVTALRM,SIGPIPE,SIGCHLD,SIGTSTP,SIGIO,SIGHUP,SIGUSR1,SIGUSR2,SIGPROF,SIGURG,SIGWINCH
+
 #define NSS_GETHOSTBYNAME_PROTOTYPES(module)            \
 enum nss_status _nss_##module##_gethostbyname4_r(       \
                 const char *name,                       \
index e7393e2..5d94d1c 100644 (file)
@@ -41,3 +41,14 @@ int signal_from_string(const char *s) _pure_;
 int signal_from_string_try_harder(const char *s);
 
 void nop_signal_handler(int sig);
+
+static inline void block_signals_reset(sigset_t *ss) {
+        assert_se(sigprocmask(SIG_SETMASK, ss, NULL) >= 0);
+}
+
+#define BLOCK_SIGNALS(...)                                              \
+        _cleanup_(block_signals_reset) sigset_t _saved_sigset = ({      \
+                sigset_t t;                                             \
+                assert_se(sigprocmask_many(SIG_BLOCK, &t, __VA_ARGS__, -1) >= 0); \
+                t;                                                      \
+        })
index ee10b10..e438625 100644 (file)
@@ -31,6 +31,7 @@
 #include "local-addresses.h"
 #include "macro.h"
 #include "nss-util.h"
+#include "signal-util.h"
 #include "string-util.h"
 #include "util.h"
 
@@ -63,6 +64,8 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
         char *r_name;
         unsigned n;
 
+        BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
+
         assert(name);
         assert(pat);
         assert(buffer);
@@ -327,6 +330,8 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
         uint32_t local_address_ipv4 = 0;
         int n_addresses = 0;
 
+        BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
+
         assert(name);
         assert(host);
         assert(buffer);
@@ -409,6 +414,8 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
         bool additional_from_hostname = false;
         unsigned n;
 
+        BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
+
         assert(addr);
         assert(host);
         assert(buffer);
index dcdbc31..3cd2950 100644 (file)
@@ -31,6 +31,7 @@
 #include "in-addr-util.h"
 #include "macro.h"
 #include "nss-util.h"
+#include "signal-util.h"
 #include "string-util.h"
 #include "user-util.h"
 #include "util.h"
@@ -94,6 +95,8 @@ enum nss_status _nss_mymachines_gethostbyname4_r(
         char *r_name;
         int n_ifindices, r;
 
+        BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
+
         assert(name);
         assert(pat);
         assert(buffer);
@@ -242,6 +245,8 @@ enum nss_status _nss_mymachines_gethostbyname3_r(
         size_t l, idx, ms, alen;
         int r;
 
+        BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
+
         assert(name);
         assert(result);
         assert(buffer);
@@ -404,6 +409,8 @@ enum nss_status _nss_mymachines_getpwnam_r(
         size_t l;
         int r;
 
+        BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
+
         assert(name);
         assert(pwd);
 
@@ -491,6 +498,8 @@ enum nss_status _nss_mymachines_getpwuid_r(
         uint32_t mapped;
         int r;
 
+        BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
+
         if (!uid_is_valid(uid)) {
                 r = -EINVAL;
                 goto fail;
@@ -564,6 +573,8 @@ enum nss_status _nss_mymachines_getgrnam_r(
         size_t l;
         int r;
 
+        BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
+
         assert(name);
         assert(gr);
 
@@ -649,6 +660,8 @@ enum nss_status _nss_mymachines_getgrgid_r(
         uint32_t mapped;
         int r;
 
+        BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
+
         if (!gid_is_valid(gid)) {
                 r = -EINVAL;
                 goto fail;
index 2b716a6..7864e53 100644 (file)
@@ -34,6 +34,7 @@
 #include "nss-util.h"
 #include "string-util.h"
 #include "util.h"
+#include "signal-util.h"
 
 NSS_GETHOSTBYNAME_PROTOTYPES(resolve);
 NSS_GETHOSTBYADDR_PROTOTYPES(resolve);
@@ -127,6 +128,8 @@ enum nss_status _nss_resolve_gethostbyname4_r(
         char *r_name;
         int c, r, i = 0;
 
+        BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
+
         assert(name);
         assert(pat);
         assert(buffer);
@@ -307,6 +310,8 @@ enum nss_status _nss_resolve_gethostbyname3_r(
         const char *canonical;
         int c, r, i = 0;
 
+        BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
+
         assert(name);
         assert(result);
         assert(buffer);
@@ -512,6 +517,8 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
         const char *n;
         int r, ifindex;
 
+        BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
+
         assert(addr);
         assert(result);
         assert(buffer);
diff --git a/src/test/test-signal-util.c b/src/test/test-signal-util.c
new file mode 100644 (file)
index 0000000..3083501
--- /dev/null
@@ -0,0 +1,49 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2016 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "signal-util.h"
+
+static void test_block_signals(void) {
+        sigset_t ss;
+
+        assert_se(sigprocmask(0, NULL, &ss) >= 0);
+
+        assert_se(sigismember(&ss, SIGUSR1) == 0);
+        assert_se(sigismember(&ss, SIGALRM) == 0);
+        assert_se(sigismember(&ss, SIGVTALRM) == 0);
+
+        {
+                BLOCK_SIGNALS(SIGUSR1, SIGVTALRM);
+
+                assert_se(sigprocmask(0, NULL, &ss) >= 0);
+                assert_se(sigismember(&ss, SIGUSR1) == 1);
+                assert_se(sigismember(&ss, SIGALRM) == 0);
+                assert_se(sigismember(&ss, SIGVTALRM) == 1);
+
+        }
+
+        assert_se(sigprocmask(0, NULL, &ss) >= 0);
+        assert_se(sigismember(&ss, SIGUSR1) == 0);
+        assert_se(sigismember(&ss, SIGALRM) == 0);
+        assert_se(sigismember(&ss, SIGVTALRM) == 0);
+}
+
+int main(int argc, char *argv[]) {
+        test_block_signals();
+}