mirror of
git://anongit.mindrot.org/openssh.git
synced 2024-12-24 19:02:06 +00:00
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
This commit is contained in:
parent
fdba503fdf
commit
b2140a739b
60
ssh-agent.c
60
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@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@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 */
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user