mirror of
https://github.com/lima-vm/lima.git
synced 2026-10-28 11:44:35 +08:00
Merge pull request #5405 from SABITHSAHEB/wsl2-ssh-address-validate
wsl2: validate guest-reported address in getSSHAddress
This commit is contained in:
3 files changed
+73
-8
No files matched your search
@@ -0,0 +1,25 @@
|
||||
// SPDX-FileCopyrightText: Copyright The Lima Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package wsl2
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// routableGuestIP returns the trimmed output when it is a global unicast IP
|
||||
// address (private and ULA ranges included), or "" otherwise. The output comes
|
||||
// from a command run inside the WSL2 guest and becomes inst.SSHAddress, which
|
||||
// is passed to ssh/scp/rsync as the destination argument, so anything that is
|
||||
// not an address we can connect to is rejected here and the caller falls
|
||||
// through to the next probe. Besides non-address output this rejects the
|
||||
// unspecified, loopback (some distributions report 127.0.1.1), link-local and
|
||||
// multicast addresses.
|
||||
func routableGuestIP(out []byte) string {
|
||||
s := strings.TrimSpace(string(out))
|
||||
if ip := net.ParseIP(s); ip == nil || !ip.IsGlobalUnicast() {
|
||||
return ""
|
||||
}
|
||||
return s
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// SPDX-FileCopyrightText: Copyright The Lima Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package wsl2
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestRoutableGuestIP(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
out string
|
||||
want string
|
||||
}{
|
||||
{"ipv4", "192.168.5.10\n", "192.168.5.10"},
|
||||
{"ipv4 trailing space", "10.0.0.5 \n", "10.0.0.5"},
|
||||
{"ipv6", "fd00::1\n", "fd00::1"},
|
||||
{"loopback rejected", "127.0.1.1\n", ""},
|
||||
{"ipv6 loopback rejected", "::1", ""},
|
||||
{"unspecified rejected", "0.0.0.0\n", ""},
|
||||
{"ipv6 unspecified rejected", "::", ""},
|
||||
{"link-local rejected", "169.254.1.1\n", ""},
|
||||
{"ipv6 link-local rejected", "fe80::1", ""},
|
||||
{"multicast rejected", "224.0.0.1\n", ""},
|
||||
{"broadcast rejected", "255.255.255.255", ""},
|
||||
{"empty rejected", "", ""},
|
||||
{"ssh option injection rejected", "-oProxyCommand=calc.exe\n", ""},
|
||||
{"ssh flag injection rejected", "-J attacker.example:22", ""},
|
||||
{"hostname rejected", "attacker.example.com", ""},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equal(t, routableGuestIP([]byte(tt.out)), tt.want)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -269,23 +268,25 @@ func getSSHAddress(ctx context.Context, instName string) (string, error) {
|
||||
cmd := exec.CommandContext(ctx, "wsl.exe", "-d", distroName, "bash", "-c", `hostname -I | cut -d ' ' -f1`)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
return strings.TrimSpace(string(out)), nil
|
||||
if addr := routableGuestIP(out); addr != "" {
|
||||
return addr, nil
|
||||
}
|
||||
}
|
||||
// Alpine
|
||||
cmd = exec.CommandContext(ctx, "wsl.exe", "-d", distroName, "sh", "-c", `ip route get 1 | awk '{gsub("^.*src ",""); print $1; exit}'`)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
return strings.TrimSpace(string(out)), nil
|
||||
if addr := routableGuestIP(out); addr != "" {
|
||||
return addr, nil
|
||||
}
|
||||
}
|
||||
// fallback
|
||||
cmd = exec.CommandContext(ctx, "wsl.exe", "-d", distroName, "hostname", "-i")
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
ip := net.ParseIP(strings.TrimSpace(string(out)))
|
||||
// some distributions use "127.0.1.1" as the host IP, but we want something that we can route to here
|
||||
if ip != nil && !ip.IsLoopback() {
|
||||
return strings.TrimSpace(string(out)), nil
|
||||
if addr := routableGuestIP(out); addr != "" {
|
||||
return addr, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("failed to get hostname for instance %#q, err: %w (out=%#q)", instName, err, string(out))
|
||||
return "", fmt.Errorf("failed to get a routable address for instance %#q, err: %w (out=%#q)", instName, err, string(out))
|
||||
}
|
||||
Reference in new issue
Block a user