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 apatch 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
For all of you who are testing off the Portable CVS tree. Let point out a new 'feature' that was just brought over from the OpenBSD tree: - markus at cvs.openbsd.org 2001/01/16 19:20:06 [key.c ssh-rsa.c] make "ssh-rsa" key format for ssh2 confirm to the ietf-drafts; from galb at vandyke.com. note that you have to delete older ssh2-rsa keys, since they are in the wrong format, too. they must be removed from .ssh/authorized_keys2 and .ssh/known_hosts2, etc. (cd; grep -v ssh-rsa .ssh/authorized_keys2 > TMP && mv TMP .ssh/authorized_keys2) additionally, we now check that BN_num_bits(rsa->n) >= 768. So keep this in mind. =) This has bitten me in a the ass already while trying to submit the whole ball of wax. I believe this means that if you use the standard key generation of OpenSSH you need to regenerate your keys. (Which I can't do quite yet. =) - Ben
thanks! commited. On Wed, Jan 17, 2001 at 08:19:07PM -0500, Andrew Pimlott wrote:> 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 > >