Skip to content

Commit b040db2

Browse files
committed
server_setup: preserve old listener if it matches the new config
This avoids closing the socket only to reopen it immediately. This reduces the chance that a server realod will fail due to resource starvation. Found by the ZeroPath AI Security Engineer <https://zeropath.com>
1 parent 5ce2bb3 commit b040db2

File tree

2 files changed

+49
-5
lines changed

2 files changed

+49
-5
lines changed

logsrvd/logsrvd.c

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1698,6 +1698,8 @@ register_listener(struct server_address *addr, struct sudo_event_base *evbase)
16981698
/* TODO: make non-fatal */
16991699
if ((l = malloc(sizeof(*l))) == NULL)
17001700
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
1701+
l->sa_str = addr->sa_str;
1702+
sudo_rcstr_addref(l->sa_str);
17011703
l->sock = sock;
17021704
l->tls = addr->tls;
17031705
l->ev = sudo_ev_alloc(sock, SUDO_EV_READ|SUDO_EV_PERSIST, listener_cb, l);
@@ -1716,22 +1718,63 @@ register_listener(struct server_address *addr, struct sudo_event_base *evbase)
17161718
static bool
17171719
server_setup(struct sudo_event_base *base)
17181720
{
1721+
struct listener_list kept_listeners =
1722+
TAILQ_HEAD_INITIALIZER(kept_listeners);
17191723
struct server_address *addr;
17201724
struct listener *l;
17211725
int nlisteners = 0;
17221726
bool ret;
17231727
debug_decl(server_setup, SUDO_DEBUG_UTIL);
17241728

1725-
/* Free old listeners (if any) and register new ones. */
1729+
/*
1730+
* Free any listeners not present in the new config.
1731+
* We must free non-matching listeners before adding new ones.
1732+
*/
17261733
while ((l = TAILQ_FIRST(&listeners)) != NULL) {
17271734
TAILQ_REMOVE(&listeners, l, entries);
1728-
sudo_ev_free(l->ev);
1729-
close(l->sock);
1730-
free(l);
1735+
1736+
TAILQ_FOREACH(addr, logsrvd_conf_server_listen_address(), entries) {
1737+
if (strcmp(addr->sa_str, l->sa_str) == 0) {
1738+
TAILQ_INSERT_TAIL(&kept_listeners, l, entries);
1739+
break;
1740+
}
1741+
}
1742+
if (addr == NULL) {
1743+
/* Listener not used in new config. */
1744+
sudo_rcstr_delref(l->sa_str);
1745+
sudo_ev_free(l->ev);
1746+
close(l->sock);
1747+
free(l);
1748+
}
17311749
}
1750+
1751+
/* Register new listeners, reusing existing ones. */
17321752
TAILQ_FOREACH(addr, logsrvd_conf_server_listen_address(), entries) {
1733-
nlisteners += register_listener(addr, base);
1753+
/* Check for addr in kept_listeners first. */
1754+
TAILQ_FOREACH(l, &kept_listeners, entries) {
1755+
if (strcmp(addr->sa_str, l->sa_str) == 0) {
1756+
/* Reuse existing listener. */
1757+
TAILQ_REMOVE(&kept_listeners, l, entries);
1758+
TAILQ_INSERT_TAIL(&listeners, l, entries);
1759+
1760+
/* Update l->sa_str from new addr. */
1761+
sudo_rcstr_delref(l->sa_str);
1762+
l->sa_str = addr->sa_str;
1763+
sudo_rcstr_addref(l->sa_str);
1764+
1765+
nlisteners++;
1766+
break;
1767+
}
1768+
}
1769+
1770+
if (l == NULL) {
1771+
/* Register new listener. */
1772+
nlisteners += register_listener(addr, base);
1773+
}
17341774
}
1775+
if (!TAILQ_EMPTY(&kept_listeners))
1776+
sudo_warnx("bug: kept_listeners not empty");
1777+
17351778
ret = nlisteners > 0;
17361779

17371780
#if defined(HAVE_OPENSSL)

logsrvd/logsrvd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ TAILQ_HEAD(server_address_list, server_address);
170170
struct listener {
171171
TAILQ_ENTRY(listener) entries;
172172
struct sudo_event *ev;
173+
char *sa_str;
173174
int sock;
174175
bool tls;
175176
};

0 commit comments

Comments
 (0)