<p>Pirmin Walthert has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/14209">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">app.c: make sure that no non-async-signal-safe syscalls are used after<br>fork before exec<br><br>Posix does only allow async-signal-safe syscalls after fork before exec.<br>As asterisk ignores this, functions like TrySystem or System sometimes<br>end up in a deadlocked child process. The patch prevents the use of<br>non-async-signal-safe syscalls.<br><br>Change-Id: Idc76365c0592ee3f3b3bd72a4f48f7a098978e8e<br>---<br>M main/app.c<br>M main/asterisk.c<br>M main/strcompat.c<br>3 files changed, 50 insertions(+), 60 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/09/14209/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/main/app.c b/main/app.c</span><br><span>index ae3f416..09c0123 100644</span><br><span>--- a/main/app.c</span><br><span>+++ b/main/app.c</span><br><span>@@ -81,6 +81,9 @@</span><br><span> </span><br><span> static AST_LIST_HEAD_STATIC(zombies, zombie);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef HAVE_CAP</span><br><span style="color: hsl(120, 100%, 40%);">+static cap_t child_cap;</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span> /*</span><br><span>  * @{ \brief Define \ref stasis topic objects</span><br><span>  */</span><br><span>@@ -3003,12 +3006,7 @@</span><br><span>     } else {</span><br><span>             /* Child */</span><br><span> #ifdef HAVE_CAP</span><br><span style="color: hsl(0, 100%, 40%);">-          cap_t cap = cap_from_text("cap_net_admin-eip");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               if (cap_set_proc(cap)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        ast_log(LOG_WARNING, "Unable to remove capabilities.\n");</span><br><span style="color: hsl(0, 100%, 40%);">-             }</span><br><span style="color: hsl(0, 100%, 40%);">-               cap_free(cap);</span><br><span style="color: hsl(120, 100%, 40%);">+                cap_set_proc(child_cap);</span><br><span> #endif</span><br><span> </span><br><span>               /* Before we unblock our signals, return our trapped signals back to the defaults */</span><br><span>@@ -3118,6 +3116,9 @@</span><br><span> </span><br><span> static void app_cleanup(void)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef HAS_CAP</span><br><span style="color: hsl(120, 100%, 40%);">+        cap_free(child_cap);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>         ao2_cleanup(queue_topic_pool);</span><br><span>       queue_topic_pool = NULL;</span><br><span>     ao2_cleanup(queue_topic_all);</span><br><span>@@ -3127,7 +3128,9 @@</span><br><span> int app_init(void)</span><br><span> {</span><br><span>     ast_register_cleanup(app_cleanup);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef HAVE_CAP</span><br><span style="color: hsl(120, 100%, 40%);">+   child_cap = cap_from_text("cap_net_admin-eip");</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>    queue_topic_all = stasis_topic_create("queue:all");</span><br><span>        if (!queue_topic_all) {</span><br><span>              return -1;</span><br><span>diff --git a/main/asterisk.c b/main/asterisk.c</span><br><span>index 037c7cd..c0c345d 100644</span><br><span>--- a/main/asterisk.c</span><br><span>+++ b/main/asterisk.c</span><br><span>@@ -385,6 +385,10 @@</span><br><span> </span><br><span> static char randompool[256];</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef HAVE_CAP</span><br><span style="color: hsl(120, 100%, 40%);">+static cap_t child_cap;</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int sig_alert_pipe[2] = { -1, -1 };</span><br><span> static struct {</span><br><span>       unsigned int need_reload:1;</span><br><span>@@ -1096,13 +1100,7 @@</span><br><span> </span><br><span>    if (pid == 0) {</span><br><span> #ifdef HAVE_CAP</span><br><span style="color: hsl(0, 100%, 40%);">-              cap_t cap = cap_from_text("cap_net_admin-eip");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               if (cap_set_proc(cap)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        /* Careful with order! Logging cannot happen after we close FDs */</span><br><span style="color: hsl(0, 100%, 40%);">-                      ast_log(LOG_WARNING, "Unable to remove capabilities.\n");</span><br><span style="color: hsl(0, 100%, 40%);">-             }</span><br><span style="color: hsl(0, 100%, 40%);">-               cap_free(cap);</span><br><span style="color: hsl(120, 100%, 40%);">+                cap_set_proc(child_cap);</span><br><span> #endif</span><br><span> #ifdef HAVE_WORKING_FORK</span><br><span>               if (ast_opt_high_priority) {</span><br><span>@@ -1801,10 +1799,8 @@</span><br><span>        if (pri) {</span><br><span>           sched.sched_priority = 10;</span><br><span>           if (sched_setscheduler(0, SCHED_RR, &sched)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      ast_log(LOG_WARNING, "Unable to set high priority\n");</span><br><span>                     return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-              } else</span><br><span style="color: hsl(0, 100%, 40%);">-                  ast_verb(1, "Set to realtime thread\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span>    } else {</span><br><span>             sched.sched_priority = 0;</span><br><span>            /* According to the manpage, these parameters can never fail. */</span><br><span>@@ -3917,8 +3913,14 @@</span><br><span>            exit(1);</span><br><span>     }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef HAVE_CAP</span><br><span style="color: hsl(120, 100%, 40%);">+        child_cap = cap_from_text("cap_net_admin-eip");</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>    /* Not a remote console? Start the daemon. */</span><br><span>        asterisk_daemon(isroot, runuser, rungroup);</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef HAS_CAP</span><br><span style="color: hsl(120, 100%, 40%);">+   cap_free(child_cap);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>         return 0;</span><br><span> }</span><br><span> </span><br><span>diff --git a/main/strcompat.c b/main/strcompat.c</span><br><span>index 0034c21..623808c 100644</span><br><span>--- a/main/strcompat.c</span><br><span>+++ b/main/strcompat.c</span><br><span>@@ -38,6 +38,8 @@</span><br><span> </span><br><span> #include "asterisk/utils.h"</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define POLL_SIZE 1024</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #ifndef HAVE_STRSEP</span><br><span> char *strsep(char **str, const char *delims)</span><br><span> {</span><br><span>@@ -426,59 +428,42 @@</span><br><span> #ifndef HAVE_CLOSEFROM</span><br><span> void closefrom(int n)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-      long x;</span><br><span style="color: hsl(0, 100%, 40%);">- struct rlimit rl;</span><br><span style="color: hsl(0, 100%, 40%);">-       DIR *dir;</span><br><span style="color: hsl(0, 100%, 40%);">-       char path[16], *result;</span><br><span style="color: hsl(0, 100%, 40%);">- struct dirent *entry;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   snprintf(path, sizeof(path), "/proc/%d/fd", (int) getpid());</span><br><span style="color: hsl(0, 100%, 40%);">-  if ((dir = opendir(path))) {</span><br><span style="color: hsl(0, 100%, 40%);">-            while ((entry = readdir(dir))) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        /* Skip . and .. */</span><br><span style="color: hsl(0, 100%, 40%);">-                     if (entry->d_name[0] == '.') {</span><br><span style="color: hsl(120, 100%, 40%);">+     int maxfd = sysconf (_SC_OPEN_MAX);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (maxfd == -1)</span><br><span style="color: hsl(120, 100%, 40%);">+              maxfd = 1024;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (maxfd > 65536)</span><br><span style="color: hsl(120, 100%, 40%);">+         maxfd = 65536;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct pollfd fds[POLL_SIZE];</span><br><span style="color: hsl(120, 100%, 40%);">+ int fd=n, loopmax, i;</span><br><span style="color: hsl(120, 100%, 40%);">+ while (fd<maxfd) {</span><br><span style="color: hsl(120, 100%, 40%);">+         loopmax = maxfd - fd;</span><br><span style="color: hsl(120, 100%, 40%);">+         if (loopmax>POLL_SIZE) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   loopmax = POLL_SIZE;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             for (i=0;i<loopmax;i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  fds[i].fd = fd+i;</span><br><span style="color: hsl(120, 100%, 40%);">+                     fds[i].events = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+             poll(fds, loopmax, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                for (i=0;i<loopmax;i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (fds[i].revents == POLLNVAL) {</span><br><span>                            continue;</span><br><span>                    }</span><br><span style="color: hsl(0, 100%, 40%);">-                       if ((x = strtol(entry->d_name, &result, 10)) && x >= n) {</span><br><span> #ifdef STRICT_COMPAT</span><br><span style="color: hsl(0, 100%, 40%);">-                             close(x);</span><br><span style="color: hsl(120, 100%, 40%);">+                     close(fds[i].fd);</span><br><span> #else</span><br><span style="color: hsl(0, 100%, 40%);">-                              /* This isn't strictly compatible, but it's actually faster</span><br><span style="color: hsl(0, 100%, 40%);">-                              * for our purposes to set the CLOEXEC flag than to close</span><br><span style="color: hsl(0, 100%, 40%);">-                                * file descriptors.</span><br><span style="color: hsl(0, 100%, 40%);">-                             */</span><br><span style="color: hsl(0, 100%, 40%);">-                             long flags = fcntl(x, F_GETFD);</span><br><span style="color: hsl(0, 100%, 40%);">-                         if (flags == -1 && errno == EBADF) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                    continue;</span><br><span style="color: hsl(0, 100%, 40%);">-                               }</span><br><span style="color: hsl(0, 100%, 40%);">-                               fcntl(x, F_SETFD, flags | FD_CLOEXEC);</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-                    }</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-               closedir(dir);</span><br><span style="color: hsl(0, 100%, 40%);">-  } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                getrlimit(RLIMIT_NOFILE, &rl);</span><br><span style="color: hsl(0, 100%, 40%);">-              if (rl.rlim_cur > 65535) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   /* A more reasonable value.  Consider that the primary source of</span><br><span style="color: hsl(0, 100%, 40%);">-                         * file descriptors in Asterisk are UDP sockets, of which we are</span><br><span style="color: hsl(0, 100%, 40%);">-                         * limited to 65,535 per address.  We additionally limit that down</span><br><span style="color: hsl(0, 100%, 40%);">-                       * to about 10,000 sockets per protocol.  While the kernel will</span><br><span style="color: hsl(0, 100%, 40%);">-                  * allow us to set the fileno limit higher (up to 4.2 billion),</span><br><span style="color: hsl(0, 100%, 40%);">-                  * there really is no practical reason for it to be that high.</span><br><span style="color: hsl(120, 100%, 40%);">+                        /* This isn't strictly compatible, but it's actually faster</span><br><span style="color: hsl(120, 100%, 40%);">+                    * for our purposes to set the CLOEXEC flag than to close</span><br><span style="color: hsl(120, 100%, 40%);">+                      * file descriptors.</span><br><span>                          */</span><br><span style="color: hsl(0, 100%, 40%);">-                     rl.rlim_cur = 65535;</span><br><span style="color: hsl(0, 100%, 40%);">-            }</span><br><span style="color: hsl(0, 100%, 40%);">-               for (x = n; x < rl.rlim_cur; x++) {</span><br><span style="color: hsl(0, 100%, 40%);">-#ifdef STRICT_COMPAT</span><br><span style="color: hsl(0, 100%, 40%);">-                      close(x);</span><br><span style="color: hsl(0, 100%, 40%);">-#else</span><br><span style="color: hsl(0, 100%, 40%);">-                  long flags = fcntl(x, F_GETFD);</span><br><span style="color: hsl(120, 100%, 40%);">+                       long flags = fcntl(fds[i].fd, F_GETFD);</span><br><span>                      if (flags == -1 && errno == EBADF) {</span><br><span>                                 continue;</span><br><span>                    }</span><br><span style="color: hsl(0, 100%, 40%);">-                       fcntl(x, F_SETFD, flags | FD_CLOEXEC);</span><br><span style="color: hsl(120, 100%, 40%);">+                        fcntl(fds[i].fd, F_SETFD, flags | FD_CLOEXEC);</span><br><span> #endif</span><br><span>             }</span><br><span style="color: hsl(120, 100%, 40%);">+             fd+=loopmax;</span><br><span>         }</span><br><span> }</span><br><span> #endif</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/14209">change 14209</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/14209"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 16 </div>
<div style="display:none"> Gerrit-Change-Id: Idc76365c0592ee3f3b3bd72a4f48f7a098978e8e </div>
<div style="display:none"> Gerrit-Change-Number: 14209 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Pirmin Walthert <infos@nappsoft.ch> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>