Skip to content

Fix panic when remote forward target is unavailable#355

Merged
antoniomika merged 1 commit intoantoniomika:mainfrom
pilat:bugfix/remote-forward-panic
Oct 7, 2025
Merged

Fix panic when remote forward target is unavailable#355
antoniomika merged 1 commit intoantoniomika:mainfrom
pilat:bugfix/remote-forward-panic

Conversation

@pilat
Copy link
Copy Markdown
Contributor

@pilat pilat commented Sep 15, 2025

Hi Antonio Mika 👋

Thanks for building and maintaining sish — it's been really useful.

This PR fixes a crash that occurs when a client creates a remote forward pointing to a local service that isn't listening. In that case OpenChannel("forwarded-tcpip", ...) fails and returns a nil channel; we then pass that nil channel into utils.CopyBoth, which leads to a nil-pointer dereference.

Reproduction

First window — run sish:

go run . \
  -a 127.0.0.1:2222 \
  -i 127.0.0.1:8080 \
  --authentication=false \
  --bind-any-host=true \
  --domain=sish.test \
  --bind-random-subdomains=false \
  --debug

Second window – request a remote forward to a non-existent local service (port 8765 is not bound):

ssh -p 2222 -N \
  -o ExitOnForwardFailure=yes \
  -o StrictHostKeyChecking=no \
  -o UserKnownHostsFile=/dev/null \
  -R some-host:80:localhost:8765 \
  foo@127.0.0.1

Third window – hit the route:

curl -v http://127.0.0.1:8080/ -H "Host: some-host.sish.test"

Panic

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x2 addr=0x18 pc=0x1044a6b24]

goroutine 40 [running]:
io.copyBuffer({0x12cb6f178, 0x1400030a3b0}, {0x0, 0x0}, {0x0, 0x0, 0x0})
	.../go/1.24.3/src/io/io.go:429 +0x174
io.Copy(...)
	.../go/1.24.3/src/io/io.go:388
github.com/antoniomika/sish/utils.CopyBoth.func3(...)
	.../sish/utils/conn.go:247
github.com/antoniomika/sish/utils.CopyBoth({0x1051be820, 0x14000318068}, {0x0, 0x0})
	.../sish/utils/conn.go:256 +0x1e0
github.com/antoniomika/sish/sshmuxer.handleRemoteForward.func7.1()
	.../sish/sshmuxer/requests.go:436 +0x3c0
created by github.com/antoniomika/sish/sshmuxer.handleRemoteForward.func7 in goroutine 201
	.../sish/sshmuxer/requests.go:392 +0xac
exit status 2

Root cause

When the remote-forward destination is down or unbound, this call:

newChan, newReqs, err := sshConn.SSHConn.OpenChannel("forwarded-tcpip", ssh.Marshal(resp))

returns newChan == nil and err != nil. We logged the error, closed cl, but continued to the I/O copy path, eventually invoking utils.CopyBoth(cl, newChan) with a nil reader.

Fix

Add an early return on OpenChannel error to avoid using newChan when it's nil and to close cl:

newChan, newReqs, err := sshConn.SSHConn.OpenChannel("forwarded-tcpip", ssh.Marshal(resp))
if err != nil {
    sshConn.SendMessage(err.Error(), true)
    _ = cl.Close()
    return
}

Nothing else in the flow changes. The connection now fails gracefully.

Behavior after the fix

With this change, the application no longer crashes when a remote forward target is unavailable.

Verification

Verified manually by repeating the same scenario described above. The panic no longer occurs and the server stays stable.


Let me know if you'd like any additional adjustments or if the change conflicts with other parts of the codebase.

@antoniomika
Copy link
Copy Markdown
Owner

Thanks for the contribution @pilat!

Copy link
Copy Markdown
Owner

@antoniomika antoniomika left a comment

Choose a reason for hiding this comment

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

Lgtm 👍

@antoniomika antoniomika merged commit 87f8d8e into antoniomika:main Oct 7, 2025
2 checks passed
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