aboutsummaryrefslogtreecommitdiff
path: root/crypto/openssh/serverloop.c
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2023-02-06 21:54:56 +0000
committerEd Maste <emaste@FreeBSD.org>2023-02-13 13:16:22 +0000
commit2f43f145825d0d8468f583b1686262b0f40c1fe5 (patch)
tree9d2d045e248438affec7e667444316491960c0ac /crypto/openssh/serverloop.c
parent412d15f7268e0662909822b1aef71536a2b285e5 (diff)
ssh: update to OpenSSH 9.2p1
Release notes are available at https://www.openssh.com/txt/release-9.2 OpenSSH 9.2 contains fixes for two security problems and a memory safety problem. The memory safety problem is not believed to be exploitable. These fixes have already been committed to OpenSSH 9.1 in FreeBSD. Some other notable items from the release notes: * ssh(1): add a new EnableEscapeCommandline ssh_config(5) option that controls whether the client-side ~C escape sequence that provides a command-line is available. Among other things, the ~C command-line could be used to add additional port-forwards at runtime. * sshd(8): add support for channel inactivity timeouts via a new sshd_config(5) ChannelTimeout directive. This allows channels that have not seen traffic in a configurable interval to be automatically closed. Different timeouts may be applied to session, X11, agent and TCP forwarding channels. * sshd(8): add a sshd_config UnusedConnectionTimeout option to terminate client connections that have no open channels for a length of time. This complements the ChannelTimeout option above. * sshd(8): add a -V (version) option to sshd like the ssh client has. * scp(1), sftp(1): add a -X option to both scp(1) and sftp(1) to allow control over some SFTP protocol parameters: the copy buffer length and the number of in-flight requests, both of which are used during upload/download. Previously these could be controlled in sftp(1) only. This makes them available in both SFTP protocol clients using the same option character sequence. * ssh-keyscan(1): allow scanning of complete CIDR address ranges, e.g. "ssh-keyscan 192.168.0.0/24". If a CIDR range is passed, then it will be expanded to all possible addresses in the range including the all-0s and all-1s addresses. bz#976 * ssh(1): support dynamic remote port forwarding in escape command-line's -R processing. bz#3499 MFC after: 1 week Sponsored by: The FreeBSD Foundation (cherry picked from commit f374ba41f55c1a127303d92d830dd58eef2f5243)
Diffstat (limited to 'crypto/openssh/serverloop.c')
-rw-r--r--crypto/openssh/serverloop.c98
1 files changed, 49 insertions, 49 deletions
diff --git a/crypto/openssh/serverloop.c b/crypto/openssh/serverloop.c
index b4c0d82b242d..6db0916d8220 100644
--- a/crypto/openssh/serverloop.c
+++ b/crypto/openssh/serverloop.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: serverloop.c,v 1.232 2022/04/20 04:19:11 djm Exp $ */
+/* $OpenBSD: serverloop.c,v 1.234 2023/01/17 09:44:48 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -168,28 +168,41 @@ client_alive_check(struct ssh *ssh)
static void
wait_until_can_do_something(struct ssh *ssh,
int connection_in, int connection_out, struct pollfd **pfdp,
- u_int *npfd_allocp, u_int *npfd_activep, u_int64_t max_time_ms,
- sigset_t *sigsetp, int *conn_in_readyp, int *conn_out_readyp)
+ u_int *npfd_allocp, u_int *npfd_activep, sigset_t *sigsetp,
+ int *conn_in_readyp, int *conn_out_readyp)
{
- struct timespec ts, *tsp;
+ struct timespec timeout;
+ char remote_id[512];
int ret;
- time_t minwait_secs = 0;
int client_alive_scheduled = 0;
u_int p;
- /* time we last heard from the client OR sent a keepalive */
- static time_t last_client_time;
+ time_t now;
+ static time_t last_client_time, unused_connection_expiry;
*conn_in_readyp = *conn_out_readyp = 0;
/* Prepare channel poll. First two pollfd entries are reserved */
- channel_prepare_poll(ssh, pfdp, npfd_allocp, npfd_activep,
- 2, &minwait_secs);
+ ptimeout_init(&timeout);
+ channel_prepare_poll(ssh, pfdp, npfd_allocp, npfd_activep, 2, &timeout);
+ now = monotime();
if (*npfd_activep < 2)
fatal_f("bad npfd %u", *npfd_activep); /* shouldn't happen */
+ if (options.rekey_interval > 0 && !ssh_packet_is_rekeying(ssh)) {
+ ptimeout_deadline_sec(&timeout,
+ ssh_packet_get_rekey_timeout(ssh));
+ }
- /* XXX need proper deadline system for rekey/client alive */
- if (minwait_secs != 0)
- max_time_ms = MINIMUM(max_time_ms, (u_int)minwait_secs * 1000);
+ /*
+ * If no channels are open and UnusedConnectionTimeout is set, then
+ * start the clock to terminate the connection.
+ */
+ if (options.unused_connection_timeout != 0) {
+ if (channel_still_open(ssh) || unused_connection_expiry == 0) {
+ unused_connection_expiry = now +
+ options.unused_connection_timeout;
+ }
+ ptimeout_deadline_monotime(&timeout, unused_connection_expiry);
+ }
/*
* if using client_alive, set the max timeout accordingly,
@@ -200,15 +213,12 @@ wait_until_can_do_something(struct ssh *ssh,
* analysis more difficult, but we're not doing it yet.
*/
if (options.client_alive_interval) {
- uint64_t keepalive_ms =
- (uint64_t)options.client_alive_interval * 1000;
-
- if (max_time_ms == 0 || max_time_ms > keepalive_ms) {
- max_time_ms = keepalive_ms;
- client_alive_scheduled = 1;
- }
+ /* Time we last heard from the client OR sent a keepalive */
if (last_client_time == 0)
- last_client_time = monotime();
+ last_client_time = now;
+ ptimeout_deadline_sec(&timeout, options.client_alive_interval);
+ /* XXX ? deadline_monotime(last_client_time + alive_interval) */
+ client_alive_scheduled = 1;
}
#if 0
@@ -226,19 +236,10 @@ wait_until_can_do_something(struct ssh *ssh,
* from it, then read as much as is available and exit.
*/
if (child_terminated && ssh_packet_not_very_much_data_to_write(ssh))
- if (max_time_ms == 0 || client_alive_scheduled)
- max_time_ms = 100;
-
- if (max_time_ms == 0)
- tsp = NULL;
- else {
- ts.tv_sec = max_time_ms / 1000;
- ts.tv_nsec = 1000000 * (max_time_ms % 1000);
- tsp = &ts;
- }
+ ptimeout_deadline_ms(&timeout, 100);
/* Wait for something to happen, or the timeout to expire. */
- ret = ppoll(*pfdp, *npfd_activep, tsp, sigsetp);
+ ret = ppoll(*pfdp, *npfd_activep, ptimeout_get_tsp(&timeout), sigsetp);
if (ret == -1) {
for (p = 0; p < *npfd_activep; p++)
@@ -251,19 +252,26 @@ wait_until_can_do_something(struct ssh *ssh,
*conn_in_readyp = (*pfdp)[0].revents != 0;
*conn_out_readyp = (*pfdp)[1].revents != 0;
+ now = monotime(); /* need to reset after ppoll() */
+ /* ClientAliveInterval probing */
if (client_alive_scheduled) {
- time_t now = monotime();
-
- /*
- * If the ppoll timed out, or returned for some other reason
- * but we haven't heard from the client in time, send keepalive.
- */
- if (ret == 0 || (last_client_time != 0 && last_client_time +
- options.client_alive_interval <= now)) {
+ if (ret == 0 &&
+ now > last_client_time + options.client_alive_interval) {
+ /* ppoll timed out and we're due to probe */
client_alive_check(ssh);
last_client_time = now;
- } else if (*conn_in_readyp)
+ } else if (ret != 0 && *conn_in_readyp) {
+ /* Data from peer; reset probe timer. */
last_client_time = now;
+ }
+ }
+
+ /* UnusedConnectionTimeout handling */
+ if (unused_connection_expiry != 0 &&
+ now > unused_connection_expiry && !channel_still_open(ssh)) {
+ sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id));
+ logit("terminating inactive connection from %s", remote_id);
+ cleanup_exit(255);
}
}
@@ -338,7 +346,6 @@ server_loop2(struct ssh *ssh, Authctxt *authctxt)
u_int npfd_alloc = 0, npfd_active = 0;
int r, conn_in_ready, conn_out_ready;
u_int connection_in, connection_out;
- u_int64_t rekey_timeout_ms = 0;
sigset_t bsigset, osigset;
debug("Entering interactive session for SSH2.");
@@ -364,13 +371,6 @@ server_loop2(struct ssh *ssh, Authctxt *authctxt)
if (!ssh_packet_is_rekeying(ssh) &&
ssh_packet_not_very_much_data_to_write(ssh))
channel_output_poll(ssh);
- if (options.rekey_interval > 0 &&
- !ssh_packet_is_rekeying(ssh)) {
- rekey_timeout_ms = ssh_packet_get_rekey_timeout(ssh) *
- 1000;
- } else {
- rekey_timeout_ms = 0;
- }
/*
* Block SIGCHLD while we check for dead children, then pass
@@ -381,7 +381,7 @@ server_loop2(struct ssh *ssh, Authctxt *authctxt)
error_f("bsigset sigprocmask: %s", strerror(errno));
collect_children(ssh);
wait_until_can_do_something(ssh, connection_in, connection_out,
- &pfd, &npfd_alloc, &npfd_active, rekey_timeout_ms, &osigset,
+ &pfd, &npfd_alloc, &npfd_active, &osigset,
&conn_in_ready, &conn_out_ready);
if (sigprocmask(SIG_UNBLOCK, &bsigset, &osigset) == -1)
error_f("osigset sigprocmask: %s", strerror(errno));