]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
login: use correct terminal fd during setup
authorTobias Stoeckmann <tobias@stoeckmann.org>
Thu, 21 Sep 2023 18:15:46 +0000 (20:15 +0200)
committerTobias Stoeckmann <tobias@stoeckmann.org>
Thu, 21 Sep 2023 18:23:14 +0000 (20:23 +0200)
The function get_terminal_name iterates through standard file
descriptors until it finds a terminal. This means that it's not
guaranteed that STDIN_FILENO (i.e. 0) is actually a terminal.

Do not modify permissions on possible files. Instead, retrieve
the file descriptor which was used by get_terminal_name as well.

Proof of Concept (as root):

1. Create a temporary file with a mode different than TTYPERM.
```
install -m 700 /dev/null /tmp/test
ls -l /tmp/test
-rwx------ 1 root root 0 Sep 21 20:15 /tmp/test
```

2. Run login within a terminal with adjusted stdin.
```
login < /tmp/test
host login:
            Hangup
```

3. Check permissions of input file.
```
ls -l /tmp/test
-rw------- 1 root root 0 Sep 21 20:15 /tmp/test
```

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
login-utils/login.c

index 129f3cfa2e3bc30e5aa99f2b50e19619a54dd54d..31a7adb07bc404a912a4c3f4fade4e08b52bc3c4 100644 (file)
@@ -515,10 +515,12 @@ static void init_tty(struct login_context *cxt)
        struct stat st;
        struct termios tt, ttt;
        struct winsize ws;
+       int fd;
 
        cxt->tty_mode = (mode_t) getlogindefs_num("TTYPERM", TTY_MODE);
 
        get_terminal_name(&cxt->tty_path, &cxt->tty_name, &cxt->tty_number);
+       fd = get_terminal_stdfd();
 
        /*
         * In case login is suid it was possible to use a hardlink as stdin
@@ -531,7 +533,7 @@ static void init_tty(struct login_context *cxt)
        if (!cxt->tty_path || !*cxt->tty_path ||
            lstat(cxt->tty_path, &st) != 0 || !S_ISCHR(st.st_mode) ||
            (st.st_nlink > 1 && strncmp(cxt->tty_path, "/dev/", 5) != 0) ||
-           access(cxt->tty_path, R_OK | W_OK) != 0) {
+           access(cxt->tty_path, R_OK | W_OK) != 0 || fd == -EINVAL) {
 
                syslog(LOG_ERR, _("FATAL: bad tty"));
                sleepexit(EXIT_FAILURE);
@@ -548,14 +550,14 @@ static void init_tty(struct login_context *cxt)
        /* The TTY size might be reset to 0x0 by the kernel when we close the stdin/stdout/stderr file
         * descriptors so let's save the size now so we can reapply it later */
        memset(&ws, 0, sizeof(struct winsize));
-       if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0)
+       if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
                syslog(LOG_WARNING, _("TIOCGWINSZ ioctl failed: %m"));
 
-       tcgetattr(0, &tt);
+       tcgetattr(fd, &tt);
        ttt = tt;
        ttt.c_cflag &= ~HUPCL;
 
-       if ((fchown(0, 0, 0) || fchmod(0, cxt->tty_mode)) && errno != EROFS) {
+       if ((fchown(fd, 0, 0) || fchmod(fd, cxt->tty_mode)) && errno != EROFS) {
 
                syslog(LOG_ERR, _("FATAL: %s: change permissions failed: %m"),
                                cxt->tty_path);
@@ -563,7 +565,7 @@ static void init_tty(struct login_context *cxt)
        }
 
        /* Kill processes left on this tty */
-       tcsetattr(0, TCSANOW, &ttt);
+       tcsetattr(fd, TCSANOW, &ttt);
 
        /*
         * Let's close file descriptors before vhangup
@@ -581,7 +583,7 @@ static void init_tty(struct login_context *cxt)
        open_tty(cxt->tty_path);
 
        /* restore tty modes */
-       tcsetattr(0, TCSAFLUSH, &tt);
+       tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
 
        /* Restore tty size */
        if ((ws.ws_row > 0 || ws.ws_col > 0)