ssh-add bug

Andrew Pimlott andrew at pimlott.ne.mediaone.net
Thu Jan 18 12:19:07 EST 2001


There is an amusing bug in ssh-add that causes it to go into an
infinite loop.  I am using openssh 1.2.3, and noticed that when I
ran "ssh-add < /dev/null" in my X startup scripts, but didn't have
ssh-askpass installed, ssh-add started spewing errors into my
.xsession-errors and didn't stop.

I found that what happens is:  ssh-add forks and attempts to exec
ssh-askpass.  The exec-ed process is supposed to pass back the
passphrase on stdout.  However, when the exec fails, the child
ssh-add process exits and--if stdout was not a terminal--flushes its
stdio buffers, which happen to contain a "Need passphrase" message.
As a result, the parent ssh-add sees what it interprets as a
passphrase coming back from the child.  It tries to use this to
decript the key, fails, and tries the whole thing over again.

You can reproduce by moving ssh-askpass to another name (setting
SSH_ASKPASS=nowhere should also do) and running "ssh-add < /dev/null
> /dev/null".  A strace showing this folly is at the end.  I think a
patch that fixes this is

--- ssh-add.c.orig	Wed Jan 17 20:09:29 2001
+++ ssh-add.c	Wed Jan 17 20:14:07 2001
@@ -59,6 +59,9 @@
 	int p[2], status;
 	char buf[1024];
 
+	/* make sure child doesn't accidentally blab to stdout */
+	if (fflush(stdout) != 0)
+		fatal("ssh_askpass: fflush: %s", strerror(errno));
 	if (askpass == NULL)
 		fatal("internal error: askpass undefined");
 	if (pipe(p) < 0)

(untested because I don't have all the libraries on this machine to
recompile).

Andrew

Strace output:

pipe([4, 5])                            = 0
fork()                                  = 16582
[pid 19607] close(5)                    = 0
[pid 19607] read(4,  <unfinished ...>
[pid 16582] close(4)                    = 0
[pid 16582] dup2(5, 1)                  = 1
[pid 16582] execve("/usr/bin/ssh-askpass", ["/usr/bin/ssh-askpass", "Bad passphr
ase, try again"], [/* 20 vars */]) = -1 ENOENT (No such file or directory)
[pid 16582] write(2, "ssh_askpass: exec(/usr/bin/ssh-a"..., 66) = 66
[pid 16582] write(2, "\r\n", 2)         = 2
[pid 16582] write(1, "Need passphrase for /home/pimlot"..., 48) = 48
[pid 16582] munmap(0x40018000, 4096)    = 0
[pid 16582] _exit(255)                  = ?
<... read resumed> "Need passphrase for /home/pimlot"..., 1024) = 48
--- SIGCHLD (Child exited) ---
close(4)                                = 0
wait4(16582, [WIFEXITED(s) && WEXITSTATUS(s) == 255], 0, NULL) = 16582
open("/home/pimlott/.ssh/identity", O_RDONLY) = 4
fstat(4, {st_mode=S_IFREG|0600, st_size=529, ...}) = 0
getuid()                                = 1000
getuid()                                = 1000
lseek(4, 0, SEEK_END)                   = 529
lseek(4, 0, SEEK_SET)                   = 0
read(4, "SSH PRIVATE KEY FILE FORMAT 1.1\n"..., 529) = 529
close(4)                                = 0
pipe([4, 5])                            = 0
fork()                                  = 16583






More information about the openssh-unix-dev mailing list