ssh/tailssh: fix SSH on busybox systems

This involved the following:

1. Pass the su command path as first of args in call to unix.Exec to make sure that busybox sees the correct program name.
   Busybox is a single executable userspace that implements various core userspace commands in a single binary. You'll
   see it used via symlinking, so that for example /bin/su symlinks to /bin/busybox. Busybox knows that you're trying
   to execute /bin/su because argv[0] is '/bin/su'. When we called unix.Exec, we weren't including the program name for
   argv[0], which caused busybox to fail with 'applet not found', meaning that it didn't know which command it was
   supposed to run.
2. Tell su to whitelist the SSH_AUTH_SOCK environment variable in order to support ssh agent forwarding.
3. Run integration tests on alpine, which uses busybox.
4. Increment CurrentCapabilityVersion to allow turning on SSH V2 behavior from control.

Fixes #12849

Signed-off-by: Percy Wegmann <percy@tailscale.com>
This commit is contained in:
Percy Wegmann
2024-08-05 17:09:34 -05:00
committed by Percy Wegmann
parent 7675c3ebf2
commit 7d83056a1b
5 changed files with 59 additions and 38 deletions

View File

@@ -399,7 +399,7 @@ func tryExecLogin(dlogf logger.Logf, ia incubatorArgs) error {
return nil
}
loginArgs := ia.loginArgs(loginCmdPath)
dlogf("logging in with %s %+v", loginCmdPath, loginArgs)
dlogf("logging in with %+v", loginArgs)
// If Exec works, the Go code will not proceed past this:
err = unix.Exec(loginCmdPath, loginArgs, os.Environ())
@@ -435,13 +435,18 @@ func trySU(dlogf logger.Logf, ia incubatorArgs) (handled bool, err error) {
defer sessionCloser()
}
loginArgs := []string{"-l", ia.localUser}
loginArgs := []string{
su,
"-w", "SSH_AUTH_SOCK", // pass through SSH_AUTH_SOCK environment variable to support ssh agent forwarding
"-l",
ia.localUser,
}
if ia.cmd != "" {
// Note - unlike the login command, su allows using both -l and -c.
loginArgs = append(loginArgs, "-c", ia.cmd)
}
dlogf("logging in with %s %q", su, loginArgs)
dlogf("logging in with %+v", loginArgs)
// If Exec works, the Go code will not proceed past this:
err = unix.Exec(su, loginArgs, os.Environ())
@@ -473,9 +478,15 @@ func findSU(dlogf logger.Logf, ia incubatorArgs) string {
return ""
}
// First try to execute su -l <user> -c true to make sure su supports the
// necessary arguments.
err = exec.Command(su, "-l", ia.localUser, "-c", "true").Run()
// First try to execute su -w SSH_AUTH_SOCK -l <user> -c true
// to make sure su supports the necessary arguments.
err = exec.Command(
su,
"-w", "SSH_AUTH_SOCK",
"-l",
ia.localUser,
"-c", "true",
).Run()
if err != nil {
dlogf("su check failed: %s", err)
return ""