Skip to content

Ctrl+C doesn't work as expected with SSH Remoting #2321

Description

In PowerShell Ctrl+C should stop a running command. But in an SSH interactive remote session Ctrl+C terminates the SSH process and closes the session. This behavior is the same for both Windows and Linux clients.

This is happening because both PowerShell and SSH processes are attached to the console and so they both get the SIGINT signal. PowerShell sends a PSRP stop signal over the channel as expected but the SSH process also handles the signal and terminates the process which closes the remote session.

Steps to reproduce

PS> Enter-PSSession -HostName <hostName> -UserName <userName>
[<hostName>]: PS > 1..100 % { sleep 1; "Output $_" }
Output 1
Output 2
# While script is running type Ctrl+C to stop it

Expected behavior

Running command stops and remote session prompt is displayed.

Actual behavior

Session is ended with error:

System.IO.IOException: Pipe is broken

Also the exception is unhandled causing PowerShell process to crash.

Environment data

Name                           Value
----                           -----
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
SerializationVersion           1.1.0.1
PSRemotingProtocolVersion      2.3
BuildVersion                   3.0.0.0
WSManStackVersion              3.0
PSVersion                      6.0.0-alpha
CLRVersion
GitCommitId                    v6.0.0-alpha.10-8-gdd2394b1e6088f6c82054f5cae5520e532010fd4-dirty
PSEdition                      Core

Activity

  1. added this to the milestone on Oct 6, 2016
  2. modified the milestones: , on Dec 19, 2016
  3. PaulHigin commented on Feb 1, 2017

    @PaulHigin
    ContributorAuthor

    This has been fixed as part of the work for issue #2827 for a Windows client. When creating the ssh.exe process we can use the CREATE_NEW_PROCESS_GROUP process creation flag which prevents the console Ctrl+C signal from propagating to that process. But there is no support for this in managed code used on Linux clients so it is not fixed there yet.

  4. vors commented on Feb 28, 2017

    @vors
    Collaborator

    I'm hitting this problem.
    Would be really useful to get fix for unix.

    Unhandled Exception: System.IO.IOException: Broken pipe
       at System.IO.UnixFileStream.CheckFileCall(Int64 result, Boolean ignoreNotSupported)
       at System.IO.UnixFileStream.WriteNative(Byte[] array, Int32 offset, Int32 count)
       at System.IO.UnixFileStream.FlushWriteBuffer()
       at System.IO.UnixFileStream.Flush(Boolean flushToDisk)
       at System.Management.Automation.Remoting.OutOfProcessTextWriter.WriteLine(String data)
       at System.Management.Automation.Remoting.Client.OutOfProcessClientCommandTransportManager.SendStopSignal()
       at System.Management.Automation.Internal.ClientPowerShellDataStructureHandler.SendStopPowerShellMessage()
       at System.Management.Automation.Runspaces.Internal.ClientRemotePowerShell.StopAsync()
       at System.Management.Automation.PowerShell.CoreStop(Boolean isSyncCall, AsyncCallback callback, Object state)
       at System.Management.Automation.PowerShell.BeginStop(AsyncCallback callback, Object state)
       at System.Management.Automation.RemotePipeline.Stop()
       at Microsoft.PowerShell.Executor.Cancel()
       at Microsoft.PowerShell.Executor.CancelCurrentExecutor()
       at Microsoft.PowerShell.ConsoleHost.HandleBreak()
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
    
    

    But there is no support for this in managed code used on Linux clients so it is not fixed there yet

    Is it a CoreCLR limitation? Should we start conversation with dotnet people?

  5. iSazonov commented on Feb 28, 2017

    @iSazonov
    Collaborator

    It seems ssh can set raw mode and send Ctrl-C to remote host as character.
    http://unix.stackexchange.com/questions/102061/ctrl-c-handling-in-ssh-session

  6. PaulHigin commented on Feb 28, 2017

    @PaulHigin
    ContributorAuthor

    This is interesting. I can verify that interactive SSH sessions don't handle the Ctrl+C signal and appear to pass it to the remote session as expected.

    But in any case I don't want ssh to handle Ctrl+C at all. Instead it should be handled only in the PowerShell client process but it appears to get passed to the ssh child process as well.

    In Windows this was an easy fix by simply preventing Ctrl+C from being passed from the PowerShell process to the child ssh process. I am not sure what the mechanism is for Linux but it may be a similar issue.

  7. iSazonov commented on Mar 2, 2017

    @iSazonov
    Collaborator

    Paul Higinbotham (@PaulHigin) Unix has the same behavior as Windows based on process groups
    To move the process in a new process group, the process must make a call setpgid(0,0)

    I believe that it can be easily and quickly be fixed in CoreCLR (add support for CREATE_NEW_PROCESS_GROUP flag)

    I may be wrong, but it seems the above mentioned ssh RAW mode uses setpgid(0,0) https://github.com/openssh/openssh-portable/blob/79e4829ec81dead1b30999e1626eca589319a47f/sshpty.c#L112
    If so, we implicitly have "fix" :-) If you have the opportunity to check, look at PGID for ssd in raw mode ps xao pid,ppid,pgid,sid,comm.

  8. PaulHigin commented on Mar 2, 2017

    @PaulHigin
    ContributorAuthor

    Ilya (@iSazonov) This is great. Thanks very much for the information. I will look into this and check with the CoreCLR group about adding CREATE_NEW_PROCESS_GROUP support.

    But I don't understand your comment about SSH RAW mode. RAW mode doesn't seem to be well documented and it is not clear if it can be used with subsystems. But even if it can it still passes the signal to the SSH process and I presume on to the SSHD remote session, and I want to prevent this.

  9. iSazonov commented on Mar 2, 2017

    @iSazonov
    Collaborator

    I prefer the CoreCLR fix and you too - so that we can both forget about ssh raw mode even if it works :-)

  10. PaulHigin commented on Mar 16, 2017

    @PaulHigin
    ContributorAuthor

    setpgid() doesn't allow the process group id to be set if the process has already started executing code. In addition there are restrictions to what process group id it can be set to (must be a process in the same session). I didn't see anywhere where you can create a process with a new group process id so I am not sure if this is possible. In any case I need to make a request to .Net to see if CREATE_NEW_PROCESS_GROUP can be supported. My guess is this can't be done in the beta 1 timeframe.

  11. 19 remaining items

  12. joeyaiello commented on May 25, 2017

    @joeyaiello
    Contributor

    Paul Higinbotham (@PaulHigin) it looks like this works now (with a weird error about the pipeline that doesn't show up locally). I still leave this to you to close, though, because it still looks like you're talking to CoreFX folks about this issue.

    [jaiello-centos]: PS /home/jaiello> 1..100 | % { sleep 1; "Output $_" }
    Output 1
    Output 2
    Output 3
    Output 4
    The pipeline has been stopped.
        + CategoryInfo          : OperationStopped: (:) [], PipelineStoppedException
        + FullyQualifiedErrorId : PipelineStopped
    
  13. PaulHigin commented on May 25, 2017

    @PaulHigin
    ContributorAuthor

    It currently only works on Windows clients. It is still broken on Linux clients.

  14. joeyaiello commented on May 25, 2017

    @joeyaiello
    Contributor

    Paul Higinbotham (@PaulHigin) Really? Like Linux SSH clients? Or Linux PowerShell clients? Both appear to work for me right now...

  15. PaulHigin commented on Jun 1, 2017

    @PaulHigin
    ContributorAuthor

    Yes. On Linux/Mac OSes Ctrl+C is handled by the SSH child process and closes the process/connection. We want to prevent this and let PSRP (PowerShell remoting protocol) handle the Ctrl+C signal.

  16. joeyaiello commented on Jun 1, 2017

    @joeyaiello
    Contributor

    Okay, I see it now. Not sure why I couldn't get it before, but this looks like it's only for PSRP over SSH. Not generic Linux SSH clients. For posterity, the error I see right now is:

    The background process reported an error with the following message: "The named pipe target process has ended.".
        + CategoryInfo          : ResourceUnavailable: (:) [], ParentContainsErrorRecordException
        + FullyQualifiedErrorId : System.Management.Automation.Remoting.PSRemotingDataStructureException
    
  17. iSazonov commented on Jun 2, 2017

    @iSazonov
    Collaborator

    Paul Higinbotham (@PaulHigin) sergei (@vors) If we put the remote pseudo-terminal in raw mode - is it resolve the problem?

    ssh -t remotehost command args - put local terminal in raw mode. Then PowerShell put remote pseudo-terminal in raw mode with cfmakeraw - Is it possible?

  18. modified the milestones: , on Jun 7, 2017
  19. PaulHigin commented on Jun 19, 2017

    @PaulHigin
    ContributorAuthor

    This is now fixed for both Windows and Linux platforms.

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

Metadata

Metadata

Labels

Issue-BugIssue has been identified as a bug in the productOS-LinuxOS-macOSResolution-FixedThe issue is fixed.WG-RemotingPSRP issues with any transport layer

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions