Refactor prepare_tty() & C:o, pass tty around

Most of the helper functions around TTYs assumed that STDIN_FILENO was
already set up and unique for the give TTY they operated on.  It turns
out it wasn't.  This patch refactors the open() of TTYs to ensure we
do not clobber our TTY settings with multiple calls to tcsetattr() for
the same TTY.

Took a while to track this one down.  Usually I don't run systems with
more than one TTY, but the Alpine system on my home server did, and boy
I've never been this close to giving up on computers, ever.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
This commit is contained in:
Joachim Nilsson
2020-04-27 01:30:34 +02:00
parent 484aa0ba97
commit b364492a8c
2 changed files with 28 additions and 74 deletions
+19 -33
View File
@@ -241,6 +241,25 @@ static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit
struct sigaction sa;
struct termios term;
char name[80];
int fd;
/* Detach from initial controlling TTY and become session leader */
vhangup();
setsid();
fd = open(tty, O_RDWR);
if (fd < 0) {
logit(LOG_ERR, "Failed opening %s: %m", tty);
_exit(1);
}
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
logit(LOG_WARNING, "Failed TIOCSCTTY on %s: %m", tty);
/*
* Reset to sane defaults in case of messup from prev. session
@@ -251,7 +270,6 @@ static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit
* Disable ISIG (INTR, QUIT, SUSP) before handing over to getty.
* It is up to the getty process to allow them again.
*/
tcdrain(STDIN_FILENO);
if (!tcgetattr(STDIN_FILENO, &term)) {
term.c_lflag &= ~ISIG;
term.c_cc[VEOF] = _POSIX_VDISABLE;
@@ -279,9 +297,6 @@ static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit
logit(LOG_WARNING, "%s: rlimit: Failed setting %s", tty, rlim2str(i));
}
/* Create new session and process group */
setsid();
/* Finit is responsible for the UTMP INIT_PROCESS record */
utmp_set_init(tty, 0);
if (!strncmp("/dev/", tty, 5))
@@ -374,7 +389,6 @@ pid_t run_getty(char *tty, char *baud, char *term, int noclear, int nowait, stru
speed = stty_parse_speed(baud);
logit(LOG_INFO, "Starting built-in getty on %s, speed %u", tty, speed);
prepare_tty(tty, speed, "tty", rlimit);
if (activate_console(noclear, nowait))
_exit(getty(tty, speed, term, NULL));
}
@@ -388,40 +402,12 @@ pid_t run_getty2(char *tty, char *cmd, char *args[], int noclear, int nowait, st
pid = fork();
if (!pid) {
int i, fd;
struct sigaction sa;
/* Reset signal handlers that were set by the parent process */
for (i = 1; i < NSIG; i++)
DFLSIG(sa, i, 0);
/* Detach from initial controlling TTY */
vhangup();
close(STDERR_FILENO);
close(STDOUT_FILENO);
close(STDIN_FILENO);
/* Attach TTY to console */
fd = open(tty, O_RDWR);
if (fd != STDIN_FILENO)
exit(1);
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
/* Dunno speed, tell stty() to not mess with it */
logit(LOG_INFO, "Starting external getty on %s, speed %u", tty, B0);
prepare_tty(tty, B0, "getty", rlimit);
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
_pe("Failed TIOCSCTTY");
if (activate_console(noclear, nowait))
_exit(execv(cmd, args));
close(fd);
vhangup();
exit(0);
}
+9 -41
View File
@@ -147,12 +147,6 @@ static void do_getty(char *tty, char *name, size_t len)
int ch;
char *np;
/*
* Clean up tty name.
*/
if (!strncmp(tty, _PATH_DEV, strlen(_PATH_DEV)))
tty += 5;
/*
* Display prompt.
*/
@@ -212,26 +206,16 @@ int getty(char *tty, speed_t speed, char *term, char *user)
{
const char cln[] = "\r\e[2K\n";
char name[30];
int fd;
/* Detach from initial controlling TTY */
vhangup();
fd = open(tty, O_RDWR);
if (fd < 0)
err(1, "Failed opening %s", tty);
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
warn("Failed TIOCSCTTY");
/*
* Clean up tty name.
*/
if (!strncmp(tty, _PATH_DEV, strlen(_PATH_DEV)))
tty += 5;
/* Set up TTY, re-enabling ISIG et al. */
stty(STDIN_FILENO, speed);
(void)write(STDOUT_FILENO, cln, strlen(cln));
(void)write(STDERR_FILENO, cln, strlen(cln));
/* The getty process is responsible for the UTMP login record */
utmp_set_login(tty, NULL);
@@ -248,35 +232,19 @@ int getty(char *tty, speed_t speed, char *term, char *user)
int sh(char *tty)
{
int fd;
char *arg0;
struct termios term;
char *args[2] = {
NULL,
NULL
};
char *arg0;
size_t len;
struct termios term;
/* Detach from initial controlling TTY */
vhangup();
fd = open(tty, O_RDWR);
if (fd < 0)
err(1, "Failed opening %s", tty);
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
warn("Failed TIOCSCTTY");
/* The getty process is usually responsible for the UTMP login record */
utmp_set_login(tty, NULL);
/* Set up TTY, re-enabling ISIG et al. */
stty(fd, B0);
close(fd);
stty(STDIN_FILENO, B0);
/* Start /bin/sh as a login shell, i.e. with a prefix '-' */
len = strlen(_PATH_BSHELL) + 2;