Skip to content

add timeout to close path#97

Open
rlerdorf wants to merge 2 commits intomasterfrom
fix-channel-close-timeout
Open

add timeout to close path#97
rlerdorf wants to merge 2 commits intomasterfrom
fix-channel-close-timeout

Conversation

@rlerdorf
Copy link
Copy Markdown
Member

Apply session timeout during channel close

Problem

When a PHP script opens an SSH channel via ssh2_exec() (or similar), the
channel close path can block indefinitely. libssh2_channel_free() calls
libssh2_channel_close() internally, which waits for the remote end to send
SSH_MSG_CHANNEL_CLOSE. If the remote command hasn't finished or the
connection has been lost, this blocks forever.

The session timeout set via stream_set_timeout() is only applied around
explicit stream reads and writes but not during the close path. So even with a
timeout configured, channel cleanup during script shutdown hangs.

This also means max_execution_time / set_time_limit() won't help since
the process is blocked in a socket recv(), not consuming CPU time.

Fix

Apply the channel's timeout to the libssh2 session before calling
libssh2_channel_free(), and clear it after. This matches the existing
pattern used in the read and write stream ops. If the close blocks longer
than the configured timeout, libssh2 returns LIBSSH2_ERROR_TIMEOUT
instead of waiting forever.

Guarded by #ifdef PHP_SSH2_SESSION_TIMEOUT for compatibility with older
libssh2 versions that lack libssh2_session_set_timeout().

Reproducer

<?php
$ssh = ssh2_connect('example.com', 22);
ssh2_auth_password($ssh, 'user', 'pass');
$stream = ssh2_exec($ssh, '/usr/bin/sleep 30000');
stream_set_timeout($stream, 15);
// Without fix: script hangs for 30000 seconds during shutdown
// With fix: channel close times out after 15 seconds

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Applies the configured PHP stream timeout to the libssh2 session during SSH channel cleanup so fclose()/shutdown won’t hang indefinitely when libssh2_channel_free() blocks waiting for SSH_MSG_CHANNEL_CLOSE.

Changes:

  • Set libssh2_session_set_timeout() to the channel stream’s timeout immediately before libssh2_channel_free(), and clear it after (guarded by PHP_SSH2_SESSION_TIMEOUT).
  • Add a PHPT regression test that ensures ssh2_exec() channel close returns within a bounded time when a stream timeout is set.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
ssh2_fopen_wrappers.c Applies the stream timeout around the channel close/free path to prevent indefinite blocking.
tests/ssh2_close_timeout.phpt Adds coverage to verify fclose() respects the configured stream timeout for long-running remote commands.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants