Remove SIGTTOU handler before restoring foreground process group

When fish exits, it tries to restore the foreground process group.
However this may actually steal control of the fg process group
from another process. Fix this by clearing the SIGTTOU handler so
that tcsetpgrp() will fail.

Credit to @mqudsi for awesome debugging.

Fixes #7060
This commit is contained in:
ridiculousfish 2020-05-31 14:11:39 -07:00
parent 03208acb60
commit 3ae91f197d
4 changed files with 8 additions and 5 deletions

View file

@ -2100,10 +2100,13 @@ void save_term_foreground_process_group() {
initial_fg_process_group = tcgetpgrp(STDIN_FILENO);
}
void restore_term_foreground_process_group() {
void restore_term_foreground_process_group_for_exit() {
if (initial_fg_process_group != -1) {
// This is called during shutdown and from a signal handler. We don't bother to complain on
// failure because doing so is unlikely to be noticed.
// However we want this to fail if we are not the tty owner (#7060), so clear our SIGTTOU
// handler to allow it to fail properly. Note that we are about to exit.
(void)signal(SIGTTOU, SIG_DFL);
(void)tcsetpgrp(STDIN_FILENO, initial_fg_process_group);
}
}

View file

@ -684,8 +684,8 @@ void configure_thread_assertions_for_testing();
void setup_fork_guards(void);
/// Save the value of tcgetpgrp so we can restore it on exit.
void save_term_foreground_process_group(void);
void restore_term_foreground_process_group(void);
void save_term_foreground_process_group();
void restore_term_foreground_process_group_for_exit();
/// Return whether we are the child of a fork.
bool is_forked_child(void);

View file

@ -528,7 +528,7 @@ int main(int argc, char **argv) {
event_fire_generic(parser, L"fish_exit", &event_args);
restore_term_mode();
restore_term_foreground_process_group();
restore_term_foreground_process_group_for_exit();
if (g_profiling_active) {
parser.emit_profiling(s_profiling_output_filename);

View file

@ -235,7 +235,7 @@ static void fish_signal_handler(int sig, siginfo_t *info, void *context) {
case SIGTERM:
/// Handle sigterm. The only thing we do is restore the front process ID, then die.
restore_term_foreground_process_group();
restore_term_foreground_process_group_for_exit();
signal(SIGTERM, SIG_DFL);
raise(SIGTERM);
break;