[openssh-commits] [openssh] 02/02: upstream: implement EMFILE mitigation for ssh-agent: remember the
git+noreply at mindrot.org
git+noreply at mindrot.org
Fri May 11 13:56:50 AEST 2018
This is an automated email from the git hooks/post-receive script.
djm pushed a commit to branch master
in repository openssh.
commit b2140a739be4c3b43cc1dc08322dca39a1e39d20
Author: djm at openbsd.org <djm at openbsd.org>
Date: Fri May 11 03:38:51 2018 +0000
upstream: implement EMFILE mitigation for ssh-agent: remember the
fd rlimit and stop accepting new connections when it is exceeded (with some
grace). Accept is resumed when enough connections are closed.
bz#2576. feedback deraadt; ok dtucker@
OpenBSD-Commit-ID: 6a85d9cec7b85741961e7116a49f8dae777911ea
---
ssh-agent.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 49 insertions(+), 11 deletions(-)
diff --git a/ssh-agent.c b/ssh-agent.c
index cd028913..d8a8260f 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-agent.c,v 1.230 2018/04/10 00:10:49 djm Exp $ */
+/* $OpenBSD: ssh-agent.c,v 1.231 2018/05/11 03:38:51 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo at cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
@@ -886,10 +886,10 @@ handle_conn_write(u_int socknum)
}
static void
-after_poll(struct pollfd *pfd, size_t npfd)
+after_poll(struct pollfd *pfd, size_t npfd, u_int maxfds)
{
size_t i;
- u_int socknum;
+ u_int socknum, activefds = npfd;
for (i = 0; i < npfd; i++) {
if (pfd[i].revents == 0)
@@ -909,18 +909,30 @@ after_poll(struct pollfd *pfd, size_t npfd)
/* Process events */
switch (sockets[socknum].type) {
case AUTH_SOCKET:
- if ((pfd[i].revents & (POLLIN|POLLERR)) != 0)
- handle_socket_read(socknum);
+ if ((pfd[i].revents & (POLLIN|POLLERR)) == 0)
+ break;
+ if (npfd > maxfds) {
+ debug3("out of fds (active %u >= limit %u); "
+ "skipping accept", activefds, maxfds);
+ break;
+ }
+ if (handle_socket_read(socknum) == 0)
+ activefds++;
break;
case AUTH_CONNECTION:
if ((pfd[i].revents & (POLLIN|POLLERR)) != 0 &&
handle_conn_read(socknum) != 0) {
- close_socket(&sockets[socknum]);
- break;
+ goto close_sock;
}
if ((pfd[i].revents & (POLLOUT|POLLHUP)) != 0 &&
- handle_conn_write(socknum) != 0)
+ handle_conn_write(socknum) != 0) {
+ close_sock:
+ if (activefds == 0)
+ fatal("activefds == 0 at close_sock");
close_socket(&sockets[socknum]);
+ activefds--;
+ break;
+ }
break;
default:
break;
@@ -929,7 +941,7 @@ after_poll(struct pollfd *pfd, size_t npfd)
}
static int
-prepare_poll(struct pollfd **pfdp, size_t *npfdp, int *timeoutp)
+prepare_poll(struct pollfd **pfdp, size_t *npfdp, int *timeoutp, u_int maxfds)
{
struct pollfd *pfd = *pfdp;
size_t i, j, npfd = 0;
@@ -958,6 +970,16 @@ prepare_poll(struct pollfd **pfdp, size_t *npfdp, int *timeoutp)
for (i = j = 0; i < sockets_alloc; i++) {
switch (sockets[i].type) {
case AUTH_SOCKET:
+ if (npfd > maxfds) {
+ debug3("out of fds (active %zu >= limit %u); "
+ "skipping arming listener", npfd, maxfds);
+ break;
+ }
+ pfd[j].fd = sockets[i].fd;
+ pfd[j].revents = 0;
+ pfd[j].events = POLLIN;
+ j++;
+ break;
case AUTH_CONNECTION:
pfd[j].fd = sockets[i].fd;
pfd[j].revents = 0;
@@ -1058,6 +1080,7 @@ main(int ac, char **av)
int timeout = -1; /* INFTIM */
struct pollfd *pfd = NULL;
size_t npfd = 0;
+ u_int maxfds;
ssh_malloc_init(); /* must be called before any mallocs */
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
@@ -1069,6 +1092,9 @@ main(int ac, char **av)
platform_disable_tracing(0); /* strict=no */
+ if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
+ fatal("%s: getrlimit: %s", __progname, strerror(errno));
+
#ifdef WITH_OPENSSL
OpenSSL_add_all_algorithms();
#endif
@@ -1165,6 +1191,18 @@ main(int ac, char **av)
printf("echo Agent pid %ld killed;\n", (long)pid);
exit(0);
}
+
+ /*
+ * Minimum file descriptors:
+ * stdio (3) + listener (1) + syslog (1 maybe) + connection (1) +
+ * a few spare for libc / stack protectors / sanitisers, etc.
+ */
+#define SSH_AGENT_MIN_FDS (3+1+1+1+4)
+ if (rlim.rlim_cur < SSH_AGENT_MIN_FDS)
+ fatal("%s: file descriptior rlimit %lld too low (minimum %u)",
+ __progname, (long long)rlim.rlim_cur, SSH_AGENT_MIN_FDS);
+ maxfds = rlim.rlim_cur - SSH_AGENT_MIN_FDS;
+
parent_pid = getpid();
if (agentsocket == NULL) {
@@ -1284,7 +1322,7 @@ skip:
platform_pledge_agent();
while (1) {
- prepare_poll(&pfd, &npfd, &timeout);
+ prepare_poll(&pfd, &npfd, &timeout, maxfds);
result = poll(pfd, npfd, timeout);
saved_errno = errno;
if (parent_alive_interval != 0)
@@ -1295,7 +1333,7 @@ skip:
continue;
fatal("poll: %s", strerror(saved_errno));
} else if (result > 0)
- after_poll(pfd, npfd);
+ after_poll(pfd, npfd, maxfds);
}
/* NOTREACHED */
}
--
To stop receiving notification emails like this one, please contact
djm at mindrot.org.
More information about the openssh-commits
mailing list