]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
write, mesg: add S_ISCHR() check for terminal device paths
authorKarel Zak <kzak@redhat.com>
Tue, 7 Apr 2026 11:49:02 +0000 (13:49 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 7 Apr 2026 11:49:02 +0000 (13:49 +0200)
Verify that the target path is a character device before proceeding.
This hardens both utilities against symlink-to-regular-file attacks
as a defense-in-depth measure.

Note that the TOCTOU race condition between stat() and freopen()/open()
is only theoretical -- on modern Linux systems /dev/pts/ is a
kernel-managed devpts filesystem where unprivileged users cannot create
or replace entries, and the setgid tty privilege only grants write
access to terminal devices, not to arbitrary files.

term-utils/mesg.c
term-utils/write.c

index e51f659a60b510c10c8926ef1aa3be302c63bb01..d3eea67117d280aae2b55df31a97c9aa49c233f9 100644 (file)
@@ -142,6 +142,8 @@ int main(int argc, char *argv[])
        if (!*argv) {
                if (stat(tty, &sb))
                        err(MESG_EXIT_FAILURE, _("stat of %s failed"), tty);
+               if (!S_ISCHR(sb.st_mode))
+                       errx(MESG_EXIT_FAILURE, _("%s: not a character device"), tty);
                if (sb.st_mode & (S_IWGRP | S_IWOTH)) {
                        puts(_("is y"));
                        return IS_ALLOWED;
@@ -154,6 +156,8 @@ int main(int argc, char *argv[])
                err(MESG_EXIT_FAILURE, _("cannot open %s"), tty);
        if (fstat(fd, &sb))
                err(MESG_EXIT_FAILURE, _("stat of %s failed"), tty);
+       if (!S_ISCHR(sb.st_mode))
+               errx(MESG_EXIT_FAILURE, _("%s: not a character device"), tty);
 
        switch (rpmatch(argv[0])) {
        case RPMATCH_YES:
index 3784f0300e46b379b43776bf77a4fb8481283c1e..feb6751a2e3f6431adcb48febd72e4cd3a62db41 100644 (file)
@@ -114,6 +114,11 @@ static int check_tty(const char *tty, int *tty_writeable, time_t *tty_atime, int
                        warn("%s", tty);
                return 1;
        }
+       if (!S_ISCHR(s.st_mode)) {
+               if (showerror)
+                       warnx(_("%s: not a character device"), tty);
+               return 1;
+       }
        if (getuid() == 0)      /* root can always write */
                *tty_writeable = 1;
        else {