Merge pull request #6438 from gystemd:tcsetpgrp_SIGTTOU

PiperOrigin-RevId: 392774712
This commit is contained in:
gVisor bot
2021-08-24 16:43:51 -07:00
2 changed files with 88 additions and 5 deletions
+10 -5
View File
@@ -489,11 +489,6 @@ func (tg *ThreadGroup) SetForegroundProcessGroup(tty *TTY, pgid ProcessGroupID)
tg.signalHandlers.mu.Lock()
defer tg.signalHandlers.mu.Unlock()
// TODO(gvisor.dev/issue/6148): "If tcsetpgrp() is called by a member of a
// background process group in its session, and the calling process is not
// blocking or ignoring SIGTTOU, a SIGTTOU signal is sent to all members of
// this background process group."
// tty must be the controlling terminal.
if tg.tty != tty {
return -1, linuxerr.ENOTTY
@@ -516,6 +511,16 @@ func (tg *ThreadGroup) SetForegroundProcessGroup(tty *TTY, pgid ProcessGroupID)
return -1, linuxerr.EPERM
}
signalAction := tg.signalHandlers.actions[linux.SIGTTOU]
// If the calling process is a member of a background group, a SIGTTOU
// signal is sent to all members of this background process group.
// We need also need to check whether it is ignoring or blocking SIGTTOU.
ignored := signalAction.Handler == linux.SIG_IGN
blocked := tg.leader.signalMask == linux.SignalSetOf(linux.SIGTTOU)
if tg.processGroup.id != tg.processGroup.session.foreground.id && !ignored && !blocked {
tg.leader.sendSignalLocked(SignalInfoPriv(linux.SIGTTOU), true)
}
tg.processGroup.session.foreground.id = pgid
return 0, nil
}
+78
View File
@@ -1640,6 +1640,84 @@ TEST_F(JobControlTest, DISABLED_SetForegroundProcessGroup) {
ASSERT_NO_ERRNO(res);
}
// This test verifies if a SIGTTOU signal is sent to the calling process's group
// when tcsetpgrp is called by a background process
TEST_F(JobControlTest, SetForegroundProcessGroupSIGTTOUBackground) {
auto res = RunInChild([=]() {
TEST_PCHECK(setsid() >= 0);
TEST_PCHECK(!ioctl(replica_.get(), TIOCSCTTY, 0));
pid_t grandchild = fork();
if (!grandchild) {
// Assign a different pgid to the child so it will result as
// a background process.
TEST_PCHECK(!setpgid(grandchild, getpid()));
TEST_PCHECK(!tcsetpgrp(replica_.get(), getpgid(0)));
// We should never reach this.
_exit(1);
}
int wstatus;
TEST_PCHECK(waitpid(grandchild, &wstatus, WSTOPPED) == grandchild);
TEST_PCHECK(WSTOPSIG(wstatus) == SIGTTOU);
});
ASSERT_NO_ERRNO(res);
}
// This test verifies that a SIGTTOU signal is not delivered to
// a background process which calls tcsetpgrp and is ignoring SIGTTOU
TEST_F(JobControlTest, SetForegroundProcessGroupSIGTTOUIgnored) {
auto res = RunInChild([=]() {
TEST_PCHECK(setsid() >= 0);
TEST_PCHECK(!ioctl(replica_.get(), TIOCSCTTY, 0));
pid_t grandchild = fork();
if (!grandchild) {
// Ignore SIGTTOU so the child in background won't
// be stopped when it will call tcsetpgrp
struct sigaction sa = {};
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(SIGTTOU, &sa, NULL);
// Assign a different pgid to the child so it will result as
// a background process.
TEST_PCHECK(!setpgid(grandchild, getpid()));
TEST_PCHECK(!tcsetpgrp(replica_.get(), getpgid(0)));
_exit(0);
}
int wstatus;
TEST_PCHECK(waitpid(grandchild, &wstatus, WSTOPPED) == grandchild);
TEST_PCHECK(WSTOPSIG(wstatus) != SIGTTOU);
TEST_PCHECK(WIFEXITED(wstatus));
});
ASSERT_NO_ERRNO(res);
}
// This test verifies that a SIGTTOU signal is not delivered to
// a background process which calls tcsetpgrp and is blocking SIGTTOU
TEST_F(JobControlTest, SetForegroundProcessGroupSIGTTOUBlocked) {
auto res = RunInChild([=]() {
TEST_PCHECK(setsid() >= 0);
TEST_PCHECK(!ioctl(replica_.get(), TIOCSCTTY, 0));
pid_t grandchild = fork();
if (!grandchild) {
// Block SIGTTOU so the child in background won't
// be stopped when it will call tcsetpgrp
sigset_t signal_set;
sigemptyset(&signal_set);
sigaddset(&signal_set, SIGTTOU);
sigprocmask(SIG_BLOCK, &signal_set, NULL);
// Assign a different pgid to the child so it will result as
// a background process.
TEST_PCHECK(!setpgid(grandchild, getpid()));
TEST_PCHECK(!tcsetpgrp(replica_.get(), getpgid(0)));
_exit(0);
}
int wstatus;
TEST_PCHECK(waitpid(grandchild, &wstatus, WSTOPPED) == grandchild);
TEST_PCHECK(WSTOPSIG(wstatus) != SIGTTOU);
});
ASSERT_NO_ERRNO(res);
}
TEST_F(JobControlTest, SetForegroundProcessGroupWrongTTY) {
pid_t pid = getpid();
ASSERT_THAT(ioctl(replica_.get(), TIOCSPGRP, &pid),