[PATCH] channels: fix ChannelTimeout deadline for global= and xctype refinement

Bhagavathiyappan Shanmugam Bhagavathiyappan.Shanmugam at ibm.com
Fri Aug 21 18:00:02 AEST 2026


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 at 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 at 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 <Bhagavathiyappan.Shanmugam at ibm.com<mailto:Bhagavathiyappan.Shanmugam at ibm.com>>

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>


More information about the openssh-unix-dev mailing list