Bugtraq mailing list archives

ncurses 4.1 security bug


From: dps () IO STARGATE CO UK (Duncan Simpson)
Date: Tue, 7 Jul 1998 20:06:11 +0100


ncurses version 4.1 fails to drop priviledges before opening the
termcap database and you can set any file(s) you like. I am not sure
any setuid program allows an exploit but this is not good in any case.
Here is a patch that stops that game. (Using the patch requires
autoconf because I have not supplied diffs against the configure
script).

Terminfo information can be put anywhere by an environment variable
and it will follow symlinks. This seems less dangerous but also wants
plugging. There are 3 version of each plug supplied: setfsuid, setreuid
and seteuid plus saved ids.

You can define KEEP_PRIVS if you still wish to take the risk.

Duncan (-:


--- ncurses/read_termcap.c.dist Tue Jul  7 18:40:52 1998
+++ ncurses/read_termcap.c      Tue Jul  7 19:23:34 1998
@@ -43,6 +43,14 @@
 #include <term.h>
 #include <tic.h>
 #include <term_entry.h>
+#include <unistd.h>
+
+#ifdef HAVE_FSUID_H
+#include <sys/fsuid.h>
+#endif /* HAVE_FSUID_H */
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */

 #if HAVE_FCNTL_H
 #include <fcntl.h>
@@ -397,6 +405,10 @@
        int tc_not_resolved;
        int current;
        int lineno;
+#ifndef KEEP_PRIVS
+       uid_t fsuid;
+       gid_t fsgid;
+#endif /* KEEP_PRIVS */

        /*
         * Return with ``loop detected'' error if we've recurred more than
@@ -442,7 +454,43 @@
                        if (fd >= 0) {
                                (void)lseek(fd, (off_t)0, SEEK_SET);
                        } else {
+#ifndef KEEP_PRIVS
+#ifdef HAVE_SETFSUID
+                               /* drop privs to make sure file allowed */
+                               fsuid=setfsuid(getuid());
+                               fsgid=setfsgid(getgid());
+#else
+                               fsuid=getuid();
+                               fsgid=getgid();
+#ifdef HAVE_SETREUID
+                               /* Swap real and effective uid */
+                               setreuid(geteuid(), getuid());
+                               serregid(getegid(), getgid());
+#else
+                               seteuid(getuid()); /* Saved ids or broken */
+                               setegid(getgid());
+#endif /* HAVE_SETREUID */
+#endif /* HACE_SETFSUID */
+#endif /* KEEP PRIVS */
                                fd = open(db_array[current], O_RDONLY, 0);
+#ifndef KEEP_PRIVS
+#ifdef HAVE_SETFSUID
+                               /* Safe to restore them now */
+                               uid=setfsuid(fsuid);
+                               gid=setfsgid(fsgid);
+#else
+#ifdef HAVE_SETREUID
+                               /* Swap real and effective uid */
+                               setreuid(geteuid(), getuid());
+                               serregid(getegid(), getgid());
+#else
+                               seteuid(fsuid); /* Saved ids or broken */
+                               setegid(fsgid);
+#endif /* HAVE_SETREUID */
+#endif /* HACE_SETFSUID */
+
+#endif /* KEEP PRIVS */
+
                                if (fd < 0) {
                                        /* No error on unfound file. */
                                        if (errno == ENOENT)
--- configure.in.old    Tue Jul  7 18:52:52 1998
+++ configure.in        Tue Jul  7 19:15:12 1998
@@ -396,6 +396,9 @@
 ttyent.h \
 unistd.h \
 values.h \
+sys/types.h \
+sys/fsuid.h \
+errno.h \
 )

 # check for HPUX's ANSI compiler
@@ -460,6 +463,12 @@
 usleep \
 vfscanf \
 vsscanf \
+setfsuid \
+setfsgid \
+setreuid \
+setregid \
+seteuid \
+setuid \
 )

 if test $ac_cv_func_sigaction = yes; then
--- ncurses/read_entry.c.dist   Tue Jul  7 19:48:08 1998
+++ ncurses/read_entry.c        Tue Jul  7 19:52:03 1998
@@ -31,6 +31,12 @@
 #if HAVE_FCNTL_H
 #include <fcntl.h>
 #endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_FSUID_H
+#include <sys/fsuid.h>
+#endif
 #include <sys/stat.h>

 #include <term.h>
@@ -83,8 +89,49 @@
     int                name_size, bool_count, num_count, str_count, str_size;
     int                i, fd, numread;
     char       buf[MAX_ENTRY_SIZE];
-
-    if ((fd = open(filename, O_RDONLY)) < 0)
+#ifndef KEEP_PRIVS
+       uid_t fsuid;
+       gid_t fsgid;
+#endif /* KEEP_PRIVS */
+
+#ifndef KEEP_PRIVS
+#ifdef HAVE_SETFSUID
+                               /* drop privs to make sure file allowed */
+                               fsuid=setfsuid(getuid());
+                               fsgid=setfsgid(getgid());
+#else
+                               fsuid=getuid();
+                               fsgid=getgid();
+#ifdef HAVE_SETREUID
+                               /* Swap real and effective uid */
+                               setreuid(geteuid(), getuid());
+                               serregid(getegid(), getgid());
+#else
+                               seteuid(getuid()); /* Saved ids or broken */
+                               setegid(getgid());
+#endif /* HAVE_SETREUID */
+#endif /* HACE_SETFSUID */
+#endif /* KEEP PRIVS */
+    fd=open(filename, O_RDONLY);
+#ifndef KEEP_PRIVS
+#ifdef HAVE_SETFSUID
+                               /* drop privs to make sure file allowed */
+                               fsuid=setfsuid(getuid());
+                               fsgid=setfsgid(getgid());
+#else
+                               fsuid=getuid();
+                               fsgid=getgid();
+#ifdef HAVE_SETREUID
+                               /* Swap real and effective uid */
+                               setreuid(geteuid(), getuid());
+                               serregid(getegid(), getgid());
+#else
+                               seteuid(getuid()); /* Saved ids or broken */
+                               setegid(getgid());
+#endif /* HAVE_SETREUID */
+#endif /* HACE_SETFSUID */
+#endif /* KEEP PRIVS */
+    if (fd<0)
        return(0);

     T(("read terminfo %s", filename));



Current thread: