Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src defend against malicious line in ut_line, which could cause ...



details:   https://anonhg.NetBSD.org/src/rev/0462999be8d1
branches:  trunk
changeset: 535379:0462999be8d1
user:      itojun <itojun%NetBSD.org@localhost>
date:      Fri Aug 16 20:21:48 2002 +0000

description:
defend against malicious line in ut_line, which could cause unwanted
writes to anything under /dev.  revoke setuid/gid privs earlier.
From: xs%kittenz.org@localhost

diffstat:

 lib/libutil/ttymsg.c              |   28 ++++--
 libexec/utmp_update/utmp_update.c |   33 +++++--
 sbin/dump/optr.c                  |    9 +-
 usr.bin/wall/wall.c               |   30 +++++--
 usr.bin/write/write.c             |  159 +++++++++++++++++++++++++------------
 5 files changed, 173 insertions(+), 86 deletions(-)

diffs (truncated from 586 to 300 lines):

diff -r cc05482b8104 -r 0462999be8d1 lib/libutil/ttymsg.c
--- a/lib/libutil/ttymsg.c      Fri Aug 16 18:05:19 2002 +0000
+++ b/lib/libutil/ttymsg.c      Fri Aug 16 20:21:48 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ttymsg.c,v 1.15 2000/07/05 11:46:42 ad Exp $   */
+/*     $NetBSD: ttymsg.c,v 1.16 2002/08/16 20:21:48 itojun Exp $       */
 
 /*
  * Copyright (c) 1989, 1993
@@ -38,7 +38,7 @@
 #if 0
 static char sccsid[] = "@(#)ttymsg.c   8.2 (Berkeley) 11/16/93";
 #else
-__RCSID("$NetBSD: ttymsg.c,v 1.15 2000/07/05 11:46:42 ad Exp $");
+__RCSID("$NetBSD: ttymsg.c,v 1.16 2002/08/16 20:21:48 itojun Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
@@ -67,8 +67,8 @@
 char *
 ttymsg(struct iovec *iov, int iovcnt, const char *line, int tmout)
 {
-       static char device[MAXNAMLEN] = _PATH_DEV;
        static char errbuf[1024];
+       char device[MAXNAMLEN];
        int cnt, fd, left, wret;
        struct iovec localiov[6];
        sigset_t nset;
@@ -81,12 +81,16 @@
        if (iovcnt > sizeof(localiov) / sizeof(localiov[0]))
                return ("too many iov's (change code in libutil/ttymsg.c)");
 
-       (void)strncpy(device + sizeof(_PATH_DEV) - 1, line,
-           sizeof(device) - sizeof(_PATH_DEV));
-       if (strchr(device + sizeof(_PATH_DEV) - 1, '/')) {
-               /* A slash is an attempt to break security... */
-               (void) snprintf(errbuf, sizeof(errbuf), "'/' in \"%s\"",
-                   device);
+       if (strlcpy(device, _PATH_DEV, sizeof(device)) >= sizeof(device) ||
+           strlcat(device, line, sizeof(device)) >= sizeof(device)) {
+               (void) snprintf(errbuf, sizeof(errbuf), "%s: path too long",
+                   line);
+               return (errbuf);
+       }
+       if (strcspn(line, "./") != strlen(line)) {
+               /* A slash or dot is an attempt to break security... */
+               (void) snprintf(errbuf, sizeof(errbuf), "'/' or '.' in \"%s\"",
+                   line);
                return (errbuf);
        }
 
@@ -101,6 +105,12 @@
                    "%s: %s", device, strerror(errno));
                return (errbuf);
        }
+       if (!isatty(fd)) {
+               (void) snprintf(errbuf, sizeof(errbuf),
+                   "%s: not a tty device", device);
+               (void) close(fd);
+               return (errbuf);
+       }
 
        for (cnt = left = 0; cnt < iovcnt; ++cnt)
                left += iov[cnt].iov_len;
diff -r cc05482b8104 -r 0462999be8d1 libexec/utmp_update/utmp_update.c
--- a/libexec/utmp_update/utmp_update.c Fri Aug 16 18:05:19 2002 +0000
+++ b/libexec/utmp_update/utmp_update.c Fri Aug 16 20:21:48 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: utmp_update.c,v 1.3 2002/08/09 10:01:53 soren Exp $     */
+/*     $NetBSD: utmp_update.c,v 1.4 2002/08/16 20:21:48 itojun Exp $    */
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -41,6 +41,7 @@
 #include <stdio.h>
 #include <vis.h>
 #include <err.h>
+#include <fcntl.h>
 #include <pwd.h>
 #include <utmpx.h>
 #include <stdlib.h>
@@ -56,8 +57,14 @@
        size_t len;
        struct passwd *pwd;
        struct stat st;
+       int fd;
+       uid_t euid;
 
-       if (argc != 1) {
+       euid = geteuid();
+       if (seteuid(getuid()) == -1)
+               err(1, "seteuid");
+
+       if (argc != 2) {
                (void)fprintf(stderr, "Usage: %s <vis-utmpx-entry>\n",
                        getprogname());
                exit(1);
@@ -90,18 +97,20 @@
                errx(1, "Current user `%s' does not match `%s' in utmpx entry",
                    pwd->pw_name, utx->ut_name);
 
-       if (stat(utx->ut_line, &st) == -1)
+       fd = open(utx->ut_line, O_RDONLY, 0);
+       if (fd == -1)
+               err(1, "Cannot open `%s'", utx->ut_line);
+       if (fstat(fd, &st) == -1)
                err(1, "Cannot stat `%s'", utx->ut_line);
-
-       if (!S_ISCHR(st.st_mode))
-               errx(1, "%s: Not a character device", utx->ut_line);
+       if (st.st_uid != getuid())
+               errx(1, "%s: Is not owned by you", utx->ut_line);
+       if (!isatty(fd))
+               errx(1, "%s: Not a tty device", utx->ut_line);
+       close(fd);
+       if (access(utx->ut_line, W_OK|R_OK) == -1)
+               err(1, "%s", utx->ut_line);
 
-       /*
-        * to check if the tty is writable here is problematic. First we
-        * don't even know if it is a tty, secondly we are setuid so it
-        * is not trivial to use access
-        */
-
+       (void)seteuid(euid);
        pututxline(utx);
 
        return 0;
diff -r cc05482b8104 -r 0462999be8d1 sbin/dump/optr.c
--- a/sbin/dump/optr.c  Fri Aug 16 18:05:19 2002 +0000
+++ b/sbin/dump/optr.c  Fri Aug 16 20:21:48 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: optr.c,v 1.26 2002/08/02 02:07:09 christos Exp $       */
+/*     $NetBSD: optr.c,v 1.27 2002/08/16 20:21:49 itojun Exp $ */
 
 /*-
  * Copyright (c) 1980, 1988, 1993
@@ -38,7 +38,7 @@
 #if 0
 static char sccsid[] = "@(#)optr.c     8.2 (Berkeley) 1/6/94";
 #else
-__RCSID("$NetBSD: optr.c,v 1.26 2002/08/02 02:07:09 christos Exp $");
+__RCSID("$NetBSD: optr.c,v 1.27 2002/08/16 20:21:49 itojun Exp $");
 #endif
 #endif /* not lint */
 
@@ -272,11 +272,16 @@
        int lmsg = 1;
        FILE *f_tty;
 
+       if (strcspn(tty, "./") != strlen(tty))
+               return;
+
        (void)strncpy(t, _PATH_DEV, sizeof(t) - 1);
        (void)strncat(t, tty, sizeof(t) - sizeof(_PATH_DEV) - 1);
        t[sizeof(t) - 1] = '\0';
 
        if ((f_tty = fopen(t, "w")) != NULL) {
+               if (!isatty(fileno(f_tty)))
+                       return;
                setbuf(f_tty, buf);
                (void) fprintf(f_tty,
                    "\n\
diff -r cc05482b8104 -r 0462999be8d1 usr.bin/wall/wall.c
--- a/usr.bin/wall/wall.c       Fri Aug 16 18:05:19 2002 +0000
+++ b/usr.bin/wall/wall.c       Fri Aug 16 20:21:48 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: wall.c,v 1.19 2002/08/02 01:52:13 christos Exp $       */
+/*     $NetBSD: wall.c,v 1.20 2002/08/16 20:21:49 itojun Exp $ */
 
 /*
  * Copyright (c) 1988, 1990, 1993
@@ -43,7 +43,7 @@
 #if 0
 static char sccsid[] = "@(#)wall.c     8.2 (Berkeley) 11/16/93";
 #endif
-__RCSID("$NetBSD: wall.c,v 1.19 2002/08/02 01:52:13 christos Exp $");
+__RCSID("$NetBSD: wall.c,v 1.20 2002/08/16 20:21:49 itojun Exp $");
 #endif /* not lint */
 
 /*
@@ -57,6 +57,7 @@
 #include <sys/uio.h>
 
 #include <err.h>
+#include <errno.h>
 #include <paths.h>
 #include <pwd.h>
 #include <stdio.h>
@@ -71,7 +72,7 @@
 int    main(int, char **);
 
 int nobanner;
-int mbufsize;
+size_t mbufsize;
 char *mbuf;
 
 /* ARGSUSED */
@@ -81,8 +82,14 @@
        int ch;
        struct iovec iov;
        char *p;
-       struct passwd *pep = getpwnam("nobody");
+       struct passwd *pep;
        struct utmpentry *ep;
+       gid_t egid;
+
+       egid = getegid();
+       if (setegid(getgid()) == -1)
+               err(1, "setegid");
+       pep = getpwnam("nobody");
 
        while ((ch = getopt(argc, argv, "n")) != -1)
                switch (ch) {
@@ -107,6 +114,7 @@
        iov.iov_base = mbuf;
        iov.iov_len = mbufsize;
        (void)getutentries(NULL, &ep);
+       (void)setegid(egid);
        for (; ep; ep = ep->next)
                if ((p = ttymsg(&iov, 1, ep->line, 60*5)) != NULL)
                        warnx("%s", p);
@@ -116,7 +124,7 @@
 void
 makemsg(const char *fname)
 {
-       register int ch, cnt;
+       int ch, cnt;
        struct tm *lt;
        struct passwd *pw;
        struct stat sbuf;
@@ -127,9 +135,11 @@
        char *p, *tty, tmpname[32], lbuf[100], hostname[MAXHOSTNAMELEN+1];
 
        (void)snprintf(tmpname, sizeof tmpname, "%s/wall.XXXXXX", _PATH_TMP);
-       if ((fd = mkstemp(tmpname)) == -1 || !(fp = fdopen(fd, "r+")))
+       if ((fd = mkstemp(tmpname)) == -1)
                err(1, "can't open temporary file");
        (void)unlink(tmpname);
+       if (!(fp = fdopen(fd, "r+")))
+               err(1, "can't open temporary file");
 
        if (!nobanner) {
                if (!(whom = getlogin()))
@@ -179,10 +189,12 @@
 
        if (fstat(fd, &sbuf))
                err(1, "can't stat temporary file");
+       if (sbuf.st_size > SIZE_T_MAX)
+               errx(1, "file too big");
        mbufsize = sbuf.st_size;
-       if (!(mbuf = malloc((u_int)mbufsize)))
+       if (!(mbuf = malloc(mbufsize)))
                err(1, "malloc");
-       if (fread(mbuf, sizeof(*mbuf), mbufsize, fp) != mbufsize)
+       if (fread(mbuf, 1, mbufsize, fp) != mbufsize)
                err(1, "can't read temporary file");
-       (void)close(fd);
+       (void)fclose(fp);
 }
diff -r cc05482b8104 -r 0462999be8d1 usr.bin/write/write.c
--- a/usr.bin/write/write.c     Fri Aug 16 18:05:19 2002 +0000
+++ b/usr.bin/write/write.c     Fri Aug 16 20:21:48 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: write.c,v 1.20 2002/08/02 01:59:44 christos Exp $      */
+/*     $NetBSD: write.c,v 1.21 2002/08/16 20:21:49 itojun Exp $        */
 
 /*
  * Copyright (c) 1989, 1993
@@ -46,7 +46,7 @@
 #if 0
 static char sccsid[] = "@(#)write.c    8.2 (Berkeley) 4/27/95";
 #else
-__RCSID("$NetBSD: write.c,v 1.20 2002/08/02 01:59:44 christos Exp $");
+__RCSID("$NetBSD: write.c,v 1.21 2002/08/16 20:21:49 itojun Exp $");
 #endif
 #endif /* not lint */
 
@@ -64,25 +64,34 @@
 #include <pwd.h>
 #include <unistd.h>
 #include <err.h>
+#include <errno.h>
 
 #include "utmpentry.h"
 
 void done(int);
-void do_write(const char *, const char *, const uid_t);
+void do_write(int, const char *, const uid_t);
 void wr_fputs(char *);
-void search_utmp(char *, char *, char *, uid_t, int);
-int term_chk(const char *, int *, time_t *, int);
+int search_utmp(char *, char *, uid_t);
+int term_chk(uid_t, const char *, int *, time_t *, int);
 int utmp_chk(const char *, const char *);
 int main(int, char **);
 
+static gid_t   saved_egid;
+
 int



Home | Main Index | Thread Index | Old Index