<p>George Joseph <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/14393">View Change</a></p><div style="white-space:pre-wrap">Approvals:
George Joseph: Looks good to me, approved; Approved for Submit
</div><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>ASTERISK-28776<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, 75 insertions(+), 58 deletions(-)<br><br></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 6ae9219..000e1a2 100644</span><br><span>--- a/main/asterisk.c</span><br><span>+++ b/main/asterisk.c</span><br><span>@@ -388,6 +388,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>@@ -1099,13 +1103,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>@@ -1804,10 +1802,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>@@ -3920,8 +3916,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..877c11c 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,69 @@</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(120, 100%, 40%);">+ int maxfd;</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef _SC_OPEN_MAX</span><br><span> 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(120, 100%, 40%);">+#endif</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%);">+#ifndef STRICT_COMPAT</span><br><span style="color: hsl(120, 100%, 40%);">+ long flags;</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span> </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%);">+#ifndef _SC_OPEN_MAX</span><br><span style="color: hsl(120, 100%, 40%);">+ if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {</span><br><span style="color: hsl(120, 100%, 40%);">+ maxfd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ maxfd = rl.rlim_cur;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+ maxfd = sysconf (_SC_OPEN_MAX);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (maxfd == -1 || maxfd > 65536) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* A more reasonable value. Consider that the primary source of</span><br><span style="color: hsl(120, 100%, 40%);">+ * file descriptors in Asterisk are UDP sockets, of which we are</span><br><span style="color: hsl(120, 100%, 40%);">+ * limited to 65,535 per address. We additionally limit that down</span><br><span style="color: hsl(120, 100%, 40%);">+ * to about 10,000 sockets per protocol. While the kernel will</span><br><span style="color: hsl(120, 100%, 40%);">+ * allow us to set the fileno limit higher (up to 4.2 billion),</span><br><span style="color: hsl(120, 100%, 40%);">+ * there really is no practical reason for it to be that high.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * sysconf as well as getrlimit can return -1 on error. Let's set</span><br><span style="color: hsl(120, 100%, 40%);">+ * maxfd to the mentioned reasonable value of 65,535 in this case.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ maxfd = 65536;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</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%);">+ 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/+/14393">change 14393</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/+/14393"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Idc76365c0592ee3f3b3bd72a4f48f7a098978e8e </div>
<div style="display:none"> Gerrit-Change-Number: 14393 </div>
<div style="display:none"> Gerrit-PatchSet: 2 </div>
<div style="display:none"> Gerrit-Owner: Joshua Colp <jcolp@sangoma.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: nappsoft <infos@nappsoft.ch> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>