mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Merge pull request #6438 from gystemd:tcsetpgrp_SIGTTOU
PiperOrigin-RevId: 392774712
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user