summaryrefslogtreecommitdiff
path: root/ssh-agent.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2018-05-11 03:38:51 +0000
committerDamien Miller <djm@mindrot.org>2018-05-11 13:56:42 +1000
commitb2140a739be4c3b43cc1dc08322dca39a1e39d20 (patch)
tree156f0f28048aef460860c93bb908005e4e06c008 /ssh-agent.c
parentfdba503fdfc647ee8a244002f1581e869c1f3d90 (diff)
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
Diffstat (limited to 'ssh-agent.c')
-rw-r--r--ssh-agent.c60
1 files changed, 49 insertions, 11 deletions
diff --git a/ssh-agent.c b/ssh-agent.c
index cd028913e..d8a8260f9 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-agent.c,v 1.230 2018/04/10 00:10:49 djm Exp $ */ 1/* $OpenBSD: ssh-agent.c,v 1.231 2018/05/11 03:38:51 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -886,10 +886,10 @@ handle_conn_write(u_int socknum)
886} 886}
887 887
888static void 888static void
889after_poll(struct pollfd *pfd, size_t npfd) 889after_poll(struct pollfd *pfd, size_t npfd, u_int maxfds)
890{ 890{
891 size_t i; 891 size_t i;
892 u_int socknum; 892 u_int socknum, activefds = npfd;
893 893
894 for (i = 0; i < npfd; i++) { 894 for (i = 0; i < npfd; i++) {
895 if (pfd[i].revents == 0) 895 if (pfd[i].revents == 0)
@@ -909,18 +909,30 @@ after_poll(struct pollfd *pfd, size_t npfd)
909 /* Process events */ 909 /* Process events */
910 switch (sockets[socknum].type) { 910 switch (sockets[socknum].type) {
911 case AUTH_SOCKET: 911 case AUTH_SOCKET:
912 if ((pfd[i].revents & (POLLIN|POLLERR)) != 0) 912 if ((pfd[i].revents & (POLLIN|POLLERR)) == 0)
913 handle_socket_read(socknum); 913 break;
914 if (npfd > maxfds) {
915 debug3("out of fds (active %u >= limit %u); "
916 "skipping accept", activefds, maxfds);
917 break;
918 }
919 if (handle_socket_read(socknum) == 0)
920 activefds++;
914 break; 921 break;
915 case AUTH_CONNECTION: 922 case AUTH_CONNECTION:
916 if ((pfd[i].revents & (POLLIN|POLLERR)) != 0 && 923 if ((pfd[i].revents & (POLLIN|POLLERR)) != 0 &&
917 handle_conn_read(socknum) != 0) { 924 handle_conn_read(socknum) != 0) {
918 close_socket(&sockets[socknum]); 925 goto close_sock;
919 break;
920 } 926 }
921 if ((pfd[i].revents & (POLLOUT|POLLHUP)) != 0 && 927 if ((pfd[i].revents & (POLLOUT|POLLHUP)) != 0 &&
922 handle_conn_write(socknum) != 0) 928 handle_conn_write(socknum) != 0) {
929 close_sock:
930 if (activefds == 0)
931 fatal("activefds == 0 at close_sock");
923 close_socket(&sockets[socknum]); 932 close_socket(&sockets[socknum]);
933 activefds--;
934 break;
935 }
924 break; 936 break;
925 default: 937 default:
926 break; 938 break;
@@ -929,7 +941,7 @@ after_poll(struct pollfd *pfd, size_t npfd)
929} 941}
930 942
931static int 943static int
932prepare_poll(struct pollfd **pfdp, size_t *npfdp, int *timeoutp) 944prepare_poll(struct pollfd **pfdp, size_t *npfdp, int *timeoutp, u_int maxfds)
933{ 945{
934 struct pollfd *pfd = *pfdp; 946 struct pollfd *pfd = *pfdp;
935 size_t i, j, npfd = 0; 947 size_t i, j, npfd = 0;
@@ -958,6 +970,16 @@ prepare_poll(struct pollfd **pfdp, size_t *npfdp, int *timeoutp)
958 for (i = j = 0; i < sockets_alloc; i++) { 970 for (i = j = 0; i < sockets_alloc; i++) {
959 switch (sockets[i].type) { 971 switch (sockets[i].type) {
960 case AUTH_SOCKET: 972 case AUTH_SOCKET:
973 if (npfd > maxfds) {
974 debug3("out of fds (active %zu >= limit %u); "
975 "skipping arming listener", npfd, maxfds);
976 break;
977 }
978 pfd[j].fd = sockets[i].fd;
979 pfd[j].revents = 0;
980 pfd[j].events = POLLIN;
981 j++;
982 break;
961 case AUTH_CONNECTION: 983 case AUTH_CONNECTION:
962 pfd[j].fd = sockets[i].fd; 984 pfd[j].fd = sockets[i].fd;
963 pfd[j].revents = 0; 985 pfd[j].revents = 0;
@@ -1058,6 +1080,7 @@ main(int ac, char **av)
1058 int timeout = -1; /* INFTIM */ 1080 int timeout = -1; /* INFTIM */
1059 struct pollfd *pfd = NULL; 1081 struct pollfd *pfd = NULL;
1060 size_t npfd = 0; 1082 size_t npfd = 0;
1083 u_int maxfds;
1061 1084
1062 ssh_malloc_init(); /* must be called before any mallocs */ 1085 ssh_malloc_init(); /* must be called before any mallocs */
1063 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 1086 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
@@ -1069,6 +1092,9 @@ main(int ac, char **av)
1069 1092
1070 platform_disable_tracing(0); /* strict=no */ 1093 platform_disable_tracing(0); /* strict=no */
1071 1094
1095 if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
1096 fatal("%s: getrlimit: %s", __progname, strerror(errno));
1097
1072#ifdef WITH_OPENSSL 1098#ifdef WITH_OPENSSL
1073 OpenSSL_add_all_algorithms(); 1099 OpenSSL_add_all_algorithms();
1074#endif 1100#endif
@@ -1165,6 +1191,18 @@ main(int ac, char **av)
1165 printf("echo Agent pid %ld killed;\n", (long)pid); 1191 printf("echo Agent pid %ld killed;\n", (long)pid);
1166 exit(0); 1192 exit(0);
1167 } 1193 }
1194
1195 /*
1196 * Minimum file descriptors:
1197 * stdio (3) + listener (1) + syslog (1 maybe) + connection (1) +
1198 * a few spare for libc / stack protectors / sanitisers, etc.
1199 */
1200#define SSH_AGENT_MIN_FDS (3+1+1+1+4)
1201 if (rlim.rlim_cur < SSH_AGENT_MIN_FDS)
1202 fatal("%s: file descriptior rlimit %lld too low (minimum %u)",
1203 __progname, (long long)rlim.rlim_cur, SSH_AGENT_MIN_FDS);
1204 maxfds = rlim.rlim_cur - SSH_AGENT_MIN_FDS;
1205
1168 parent_pid = getpid(); 1206 parent_pid = getpid();
1169 1207
1170 if (agentsocket == NULL) { 1208 if (agentsocket == NULL) {
@@ -1284,7 +1322,7 @@ skip:
1284 platform_pledge_agent(); 1322 platform_pledge_agent();
1285 1323
1286 while (1) { 1324 while (1) {
1287 prepare_poll(&pfd, &npfd, &timeout); 1325 prepare_poll(&pfd, &npfd, &timeout, maxfds);
1288 result = poll(pfd, npfd, timeout); 1326 result = poll(pfd, npfd, timeout);
1289 saved_errno = errno; 1327 saved_errno = errno;
1290 if (parent_alive_interval != 0) 1328 if (parent_alive_interval != 0)
@@ -1295,7 +1333,7 @@ skip:
1295 continue; 1333 continue;
1296 fatal("poll: %s", strerror(saved_errno)); 1334 fatal("poll: %s", strerror(saved_errno));
1297 } else if (result > 0) 1335 } else if (result > 0)
1298 after_poll(pfd, npfd); 1336 after_poll(pfd, npfd, maxfds);
1299 } 1337 }
1300 /* NOTREACHED */ 1338 /* NOTREACHED */
1301} 1339}