From 9daceae87876a8f9e408ecf6e5e4c345b5d3bee5 Mon Sep 17 00:00:00 2001 From: Jan Dubois Date: Wed, 13 Oct 2021 15:49:37 -0700 Subject: [PATCH 1/2] Compatibility with qemu 2.11.1 (Ubuntu 18.04 LTS) * `-accel help` writes to stderr, not stdout * `-netdev help` is not implemented The -netdev info is only used to detect vde support, which isn't used on Linux, so this doesn't affect Lima. Signed-off-by: Jan Dubois --- pkg/qemu/qemu.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/pkg/qemu/qemu.go b/pkg/qemu/qemu.go index ac944f9af65..67d885a2d9f 100644 --- a/pkg/qemu/qemu.go +++ b/pkg/qemu/qemu.go @@ -165,14 +165,22 @@ func inspectFeatures(exe string) (*features, error) { return nil, fmt.Errorf("failed to run %v: stdout=%q, stderr=%q", cmd.Args, stdout.String(), stderr.String()) } f.AccelHelp = stdout.Bytes() + // on older versions qemu will write "help" output to stderr + if len(f.AccelHelp) == 0 { + f.AccelHelp = stderr.Bytes() + } cmd = exec.Command(exe, "-M", "none", "-netdev", "help") cmd.Stdout = &stdout cmd.Stderr = &stderr if err := cmd.Run(); err != nil { - return nil, fmt.Errorf("failed to run %v: stdout=%q, stderr=%q", cmd.Args, stdout.String(), stderr.String()) + logrus.Warnf("failed to run %v: stdout=%q, stderr=%q", cmd.Args, stdout.String(), stderr.String()) + } else { + f.NetdevHelp = stdout.Bytes() + if len(f.NetdevHelp) == 0 { + f.NetdevHelp = stderr.Bytes() + } } - f.NetdevHelp = stdout.Bytes() return &f, nil } From 0763bede3e2c1cf3a88be13e61ebf05463d28d2f Mon Sep 17 00:00:00 2001 From: Jan Dubois Date: Wed, 13 Oct 2021 16:24:31 -0700 Subject: [PATCH 2/2] Compatibility with OpenSSH 7.1p1 (Ubuntu 18.04 LTS) The feature to add algorithms to the front of the default set by using a leading `^` has been added in OpenSSH 8.0 and cause an error on earlier versions. Specifying a different cipher is just a (minor) performance tweak, not a requirement. Signed-off-by: Jan Dubois --- go.mod | 1 + go.sum | 1 + pkg/sshutil/sshutil.go | 67 +++++++++++++++++++++++++++++++++--------- 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index 2376218d9a3..db0aaf5185c 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/cheggaaa/pb/v3 v3.0.8 github.com/containerd/containerd v1.5.7 github.com/containerd/continuity v0.2.0 + github.com/coreos/go-semver v0.3.0 github.com/digitalocean/go-qemu v0.0.0-20210326154740-ac9e0b687001 github.com/diskfs/go-diskfs v1.2.0 github.com/docker/go-units v0.4.0 diff --git a/go.sum b/go.sum index f1e67ec5eee..13a5d821e68 100644 --- a/go.sum +++ b/go.sum @@ -247,6 +247,7 @@ github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmeka github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= diff --git a/pkg/sshutil/sshutil.go b/pkg/sshutil/sshutil.go index 3700585edcf..4276d64de2a 100644 --- a/pkg/sshutil/sshutil.go +++ b/pkg/sshutil/sshutil.go @@ -1,14 +1,18 @@ package sshutil import ( + "bytes" "errors" "fmt" "io/fs" "os" "os/exec" "path/filepath" + "regexp" "strings" + "sync" + "github.com/coreos/go-semver/semver" "github.com/lima-vm/lima/pkg/lockutil" "github.com/lima-vm/lima/pkg/osutil" "github.com/lima-vm/lima/pkg/store/dirnames" @@ -102,6 +106,15 @@ func DefaultPubKeys(loadDotSSH bool) ([]PubKey, error) { return res, nil } +var sshInfo struct { + sync.Once + // aesAccelerated is set to true when AES acceleration is available. + // Available on almost all modern Intel/AMD processors. + aesAccelerated bool + // openSSHVersion is set to the version of OpenSSH, or semver.New("0.0.0") if the version cannot be determined. + openSSHVersion semver.Version +} + func CommonArgs(useDotSSH bool) ([]string, error) { configDir, err := dirnames.LimaConfigDir() if err != nil { @@ -159,16 +172,24 @@ func CommonArgs(useDotSSH bool) ([]string, error) { "-F", "/dev/null", ) - // By default, `ssh` choose chacha20-poly1305@openssh.com, even when AES accelerator is available. - // (OpenSSH_8.1p1, macOS 11.6, MacBookPro 2020, Core i7-1068NG7) - // - // We prioritize AES algorithms when AES accelerator is available. - if aesAccelerated { - logrus.Debugf("AES accelerator seems available, prioritizing aes128-gcm@openssh.com and aes256-gcm@openssh.com") - args = append(args, "-o", "Ciphers=^aes128-gcm@openssh.com,aes256-gcm@openssh.com") - } else { - logrus.Debugf("AES accelerator does not seem available, prioritizing chacha20-poly1305@openssh.com") - args = append(args, "-o", "Ciphers=^chacha20-poly1305@openssh.com") + sshInfo.Do(func() { + sshInfo.aesAccelerated = detectAESAcceleration() + sshInfo.openSSHVersion = detectOpenSSHVersion() + }) + + // Only OpenSSH version 8.0 and later support adding ciphers to the front of the default set + if !sshInfo.openSSHVersion.LessThan(*semver.New("8.0.0")) { + // By default, `ssh` choose chacha20-poly1305@openssh.com, even when AES accelerator is available. + // (OpenSSH_8.1p1, macOS 11.6, MacBookPro 2020, Core i7-1068NG7) + // + // We prioritize AES algorithms when AES accelerator is available. + if sshInfo.aesAccelerated { + logrus.Debugf("AES accelerator seems available, prioritizing aes128-gcm@openssh.com and aes256-gcm@openssh.com") + args = append(args, "-o", "Ciphers=^aes128-gcm@openssh.com,aes256-gcm@openssh.com") + } else { + logrus.Debugf("AES accelerator does not seem available, prioritizing chacha20-poly1305@openssh.com") + args = append(args, "-o", "Ciphers=^chacha20-poly1305@openssh.com") + } } return args, nil } @@ -195,7 +216,25 @@ func SSHArgs(instDir string, useDotSSH bool) ([]string, error) { return args, nil } -// aesAccelerated is set to true when AES acceleration is available. -// -// Available on almost all modern Intel/AMD processors. -var aesAccelerated = detectAESAcceleration() +func detectOpenSSHVersion() semver.Version { + var ( + v semver.Version + stderr bytes.Buffer + ) + cmd := exec.Command("ssh", "-V") + cmd.Stderr = &stderr + if err := cmd.Run(); err != nil { + logrus.Warnf("failed to run %v: stderr=%q", cmd.Args, stderr.String()) + } else { + regex := regexp.MustCompile(`^OpenSSH_(\d+\.\d+)(?:p(\d+))?\b`) + matches := regex.FindSubmatch(stderr.Bytes()) + if len(matches) == 3 { + if len(matches[2]) == 0 { + matches[2] = []byte("0") + } + v = *semver.New(fmt.Sprintf("%s.%s", matches[1], matches[2])) + } + } + logrus.Debugf("OpenSSH version %s detected", v) + return v +}