ncurses 4.1 security bug

From: Duncan Simpson (dpsat_private)
Date: Tue Jul 07 1998 - 12:06:11 PDT

  • Next message: Perry E. Metzger: "Re: ncurses 4.1 security bug"

    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));
    



    This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 14:02:14 PDT