[PATCH] channels: fix ChannelTimeout deadline for global= and xctype refinement
Bhagavathiyappan Shanmugam via openssh-unix-dev <[email protected]>
| Newsgroups | gmane.network.openssh.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi,
This patch fixes two issues with ChannelTimeout in channels.c.
Bug 1 — Functional: session= timeout never fires
-------------------------------------------------
When ChannelTimeout session=5s is configured, the timeout is correctly
set in channel_new() but silently destroyed by channel_set_xtype() when
the channel is refined from "session" to "session:shell" or
"session:command". lookup_timeout("session:shell") returns 0 because the
pattern "session" does not match "session:shell", and the old code
unconditionally overwrote inactive_deadline with 0.
Steps to reproduce:
ssh -o ChannelTimeout="session=5s" user@host "sleep 8"
Expected: connection killed after 5 seconds of inactivity
Actual: sleep 8 completes after 8 seconds, timeout never fires
Debug evidence:
debug1: channel 0: new session [client-session] (inactive timeout: 5)
debug2: channel_set_xtype: labeled channel 0 as session:command (inactive timeout 0)
[session runs for full 8 seconds, no timeout]
debug1: Exit status 0
Bug 2 — Display: global= shows 0 in three debug messages
---------------------------------------------------------
When ChannelTimeout global=10s is configured, three debug messages
incorrectly print 0 instead of 10. The global deadline is stored in
sc->global_deadline, not c->inactive_deadline, but the messages only
read c->inactive_deadline.
Steps to reproduce:
ssh -vvv -o ChannelTimeout="global=10s" user@host
Expected:
channel 0: new session [client-session] (inactive timeout: 10)
channel_set_xtype: labeled channel 0 as session:shell (inactive timeout 10)
channel 0: closing after 10 seconds of inactivity
Actual:
channel 0: new session [client-session] (inactive timeout: 0)
channel_set_xtype: labeled channel 0 as session:shell (inactive timeout 0)
channel 0: closing after 0 seconds of inactivity
Fix
---
Fix 1: In channel_set_xtype(), only overwrite inactive_deadline when
the xctype lookup actually finds a match — preserving the ctype-level
deadline otherwise.
Fix 2: In three debug messages, fall back to sc->global_deadline when
c->inactive_deadline is 0.
Tested on OpenSSH_10.5p1 (macOS).
---
From 36d9a7920055b5306bd4f49e2aa92832c9b84b91 Mon Sep 17 00:00:00 2001
From: Bhagavathiyappan Shanmugam <[email protected]<mailto:[email protected]>>
Date: Fri, 21 Aug 2026 12:32:29 +0530
Subject: [PATCH] channels: fix ChannelTimeout deadline for global= and xctype
refinement
channel_set_xtype() is called after channel_new() to refine the channel
type (e.g. "session" -> "session:shell"). When ChannelTimeout session=5s
is configured, lookup_timeout("session:shell") returns 0 because the
pattern "session" does not match "session:shell". The previous code
unconditionally overwrote inactive_deadline with 0, destroying the value
set by channel_new() and preventing the timeout from ever firing.
Fix: only update inactive_deadline when the xctype lookup finds a
configured match, so a more specific xctype pattern can still override
the ctype-level deadline but an unmatched xctype never erases it.
Also fix three debug messages that printed 0 instead of the configured
value when ChannelTimeout global=Xs is used. The global deadline is
stored in sc->global_deadline, not c->inactive_deadline, so the log
messages now fall back to sc->global_deadline when inactive_deadline
is 0.
---
channels.c | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/channels.c b/channels.c
index fcd80288f..9b9936558 100644
--- a/channels.c
+++ b/channels.c
@@ -378,6 +378,7 @@ channel_classify(struct ssh *ssh, Channel *c)
void
channel_set_xtype(struct ssh *ssh, int id, const char *xctype)
{
+ struct ssh_channels *sc = ssh->chanctxt;
Channel *c;
if ((c = channel_by_id(ssh, id)) == NULL)
@@ -385,11 +386,15 @@ channel_set_xtype(struct ssh *ssh, int id, const char *xctype)
if (c->xctype != NULL)
free(c->xctype);
c->xctype = xstrdup(xctype);
- /* Type has changed, so look up inactivity deadline again */
- c->inactive_deadline = lookup_timeout(ssh, c->xctype);
+ /* Only override deadline if xctype has a more specific match. */
+ int xtype_deadline = lookup_timeout(ssh, c->xctype);
+ if (xtype_deadline != 0)
+ c->inactive_deadline = xtype_deadline;
channel_classify(ssh, c);
+ /* report effective timeout: per-channel if set, else global */
debug2_f("labeled channel %d as %s (inactive timeout %u)", id, xctype,
- c->inactive_deadline);
+ c->inactive_deadline != 0 ? c->inactive_deadline
+ : (u_int)sc->global_deadline);
}
/*
@@ -560,7 +565,9 @@ channel_new(struct ssh *ssh, char *ctype, int type, int rfd, int wfd, int efd,
TAILQ_INIT(&c->status_confirms);
channel_classify(ssh, c);
debug("channel %d: new %s [%s] (inactive timeout: %u)",
- found, c->ctype, remote_name, c->inactive_deadline);
+ found, c->ctype, remote_name,
+ c->inactive_deadline != 0 ? c->inactive_deadline
+ : (u_int)sc->global_deadline);
return c;
}
@@ -2708,9 +2715,11 @@ channel_handler(struct ssh *ssh, int table, struct timespec *timeout)
channel_get_expiry(ssh, c) != 0 &&
now >= channel_get_expiry(ssh, c)) {
/* channel closed for inactivity */
+ u_int fired_deadline = c->inactive_deadline != 0
+ ? c->inactive_deadline
+ : (u_int)sc->global_deadline;
verbose("channel %d: closing after %u seconds "
- "of inactivity", c->self,
- c->inactive_deadline);
+ "of inactivity", c->self, fired_deadline);
channel_force_close(ssh, c, 1);
} else if (c->notbefore <= now) {
/* Run handlers that are not paused. */
--
2.50.1 (Apple Git-155)
———
Reported a issue in Bugzilla as well, please find the attached link to it,
https://bugzilla.mindrot.org/show_bug.cgi?id=3994
Thank You,
Bhagavathiyappan
Get Outlook for Mac<https://aka.ms/GetOutlookForMac>