Bug#1052451: when receiving a SIGINT, unison should send it to the process group, not just to ssh
Control: reassign -1 unison-2.53 2.53.3-2
Control: retitle -1 when receiving a SIGINT, unison should send it to the process group, not just to ssh
A summary of the issue: I'm using a wrapper to ssh in order to
call ssh-add before the real ssh, when needed. When I run unison
and type Ctrl-C when a passphrase is asked by ssh-add, this kills
unison and my wrapper, but not ssh-add.
BTW, I've noticed that with svn (which uses my ssh wrapper in the
same way as unison), everything is OK. So this issue is specific
to the execution via unison.
In my wrapper, I've replaced "ssh-add" by "strace -o ~/str.out ssh-add",
so that I can now see more about the issue: with svn, ssh-add receives
the SIGINT, but not with unison!
In the ssh-add strace output when using svn:
[...]
openat(AT_FDCWD, "/dev/tty", O_RDWR) = 4
ioctl(4, TCGETS, {c_iflag=ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0
ioctl(4, TCGETS, {c_iflag=ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0
ioctl(4, TCSETSF, {c_iflag=ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0
ioctl(4, TCGETS, {c_iflag=ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0
rt_sigaction(SIGALRM, {sa_handler=0x55993f0238b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f305625a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGHUP, {sa_handler=0x55993f0238b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f305625a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGINT, {sa_handler=0x55993f0238b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f305625a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGPIPE, {sa_handler=0x55993f0238b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f305625a510}, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGQUIT, {sa_handler=0x55993f0238b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f305625a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGTERM, {sa_handler=0x55993f0238b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f305625a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGTSTP, {sa_handler=0x55993f0238b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f305625a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGTTIN, {sa_handler=0x55993f0238b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f305625a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGTTOU, {sa_handler=0x55993f0238b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f305625a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
write(4, "Enter passphrase for /home/vlefe"..., 49) = 49
read(4, 0x7ffd198c78cf, 1) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} ---
rt_sigreturn({mask=[]}) = -1 EINTR (Interrupted system call)
write(4, "\n", 1) = 1
[...]
In the ssh-add strace output when using unison:
[...]
openat(AT_FDCWD, "/dev/tty", O_RDWR) = 4
ioctl(4, TCGETS, {c_iflag=ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0
ioctl(4, TCGETS, {c_iflag=ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0
ioctl(4, TCSETSF, {c_iflag=ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0
ioctl(4, TCGETS, {c_iflag=ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0
rt_sigaction(SIGALRM, {sa_handler=0x55e65c2078b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGHUP, {sa_handler=0x55e65c2078b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGINT, {sa_handler=0x55e65c2078b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGPIPE, {sa_handler=0x55e65c2078b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGQUIT, {sa_handler=0x55e65c2078b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGTERM, {sa_handler=0x55e65c2078b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGTSTP, {sa_handler=0x55e65c2078b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGTTIN, {sa_handler=0x55e65c2078b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGTTOU, {sa_handler=0x55e65c2078b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
write(4, "Enter passphrase for /home/vlefe"..., 49) = 49
read(4,
and Ctrl-C does nothing, I suppose because SIGINT is ignored here.
In the unison-2.53-2.53.3 src/remote.ml file:
(* Signals generated by the terminal from user input are sent to all
processes in the foreground process group. This means that the ssh
child process will receive SIGINT at the same time as Unison and
close the connection before Unison has the chance to do cleanup with
the remote end. To make matters more complicated, the ssh process
must be in the foreground process group because interaction with the
user is done via the terminal (not via stdin, stdout) and background
processes can't read from the terminal (unless we'd set up a pty
like is done for the GUI).
Don't let these signals reach ssh by blocking them.
The signals could be ignored instead of being blocked because ssh
does not set handlers for SIGINT and SIGQUIT if they've been ignored
at startup. But this triggers an error in ssh. The interactive
passphrase reading function captures these signals for the purpose
of restoring terminal settings (echo). When receiving a signal, and
after restoring previous signal handlers, it resends the signal to
itself. But now the signal is ignored and instead of terminating,
the process will continue running as if passphrase reading function
had returned with an empty result.
Since the ssh process no longer receives the signals generated by
user input we have to make sure that it terminates when Unison does.
This usually happens due to its stdin and stdout being closed,
except for when it is interacting with the user via terminal. To get
around that, an [at_exit] handler is registered to send a SIGTERM
and SIGKILL to the ssh process. (Note, for [at_exit] handlers to
run, unison process must terminate normally, not be killed. For
SIGINT, this means that [Sys.catch_break true] (or an alternative
SIGINT handler) must be set before creating the ssh process.) *)
So, in my case, unison sends SIGINT only to my ssh wrapper. It should
send the signal to the process group in order to mimic what normally
happens with a Ctrl-C.
Then, if I type a character, e.g. "z", ssh-add gets an I/O error, but
it reopens /dev/tty for the next passphrase instead of exiting. I'm
not sure whether this is correct, but via Mutt, the terminal was still
working for ssh-add, so that fixing the issue in unison would be the
only good solution.
write(4, "Enter passphrase for /home/vlefe"..., 49) = 49
read(4, "z", 1) = 1
read(4, 0x7ffc8bf3e17f, 1) = -1 EIO (Input/output error)
write(4, "\n", 1) = 1
ioctl(4, TCGETS, {c_iflag=INLCR|ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0
ioctl(4, TCSETSF, {c_iflag=ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = -1 EIO (Input/output error)
rt_sigaction(SIGALRM, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, NULL, 8) = 0
rt_sigaction(SIGHUP, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, NULL, 8) = 0
rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, NULL, 8) = 0
rt_sigaction(SIGQUIT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, NULL, 8) = 0
rt_sigaction(SIGTERM, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, NULL, 8) = 0
rt_sigaction(SIGTSTP, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, NULL, 8) = 0
rt_sigaction(SIGTTIN, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, NULL, 8) = 0
rt_sigaction(SIGTTOU, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, NULL, 8) = 0
close(4) = 0
openat(AT_FDCWD, "/home/vlefevre/.ssh/id_rsa-android", O_RDONLY) = 4
newfstatat(4, "", {st_mode=S_IFREG|0600, st_size=1766, ...}, AT_EMPTY_PATH) = 0
getuid() = 1000
newfstatat(4, "", {st_mode=S_IFREG|0600, st_size=1766, ...}, AT_EMPTY_PATH) = 0
read(4, "-----BEGIN RSA PRIVATE KEY-----\n"..., 4096) = 1766
read(4, "", 2330) = 0
read(4, "", 4096) = 0
close(4) = 0
ioctl(0, TCGETS, 0x7ffc8bf3e7e0) = -1 ENOTTY (Inappropriate ioctl for device)
getpid() = 61437
openat(AT_FDCWD, "/dev/tty", O_RDWR) = 4
[...]
--
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
Reply to: