4857545 2000-03-02  19:41  /299 rader/ Postmaster
Mottagare: Bugtraq (import) <10084>
Ärende: [XFree86 3.3.6] fix for race conditions in xterm logfile handling
------------------------------------------------------------
Approved-By: aleph1@SECURITYFOCUS.COM
Delivered-To: bugtraq@lists.securityfocus.com
Delivered-To: BUGTRAQ@SECURITYFOCUS.COM
Mime-Version: 1.0
Content-Type: multipart/signed; micalg=pgp-sha1 
             protocol="application/pgp-signature"; boundary="y0Ed1hDcWxc3B7cn"
Content-Disposition: inline
User-Agent: Mutt/1.1.5i
Message-ID:  <20000301183950.D14657@ecn.purdue.edu>
Date:         Wed, 1 Mar 2000 18:39:51 -0500
Reply-To: Branden Robinson <branden@ECN.PURDUE.EDU>
Sender: Bugtraq List <BUGTRAQ@SECURITYFOCUS.COM>
From: Branden Robinson <branden@ECN.PURDUE.EDU>
X-To:         patch@xfree86.org
X-cc:         dickey@clark.net, wakkerma@debian.org, BUGTRAQ@SECURITYFOCUS.COM
To: BUGTRAQ@SECURITYFOCUS.COM

--y0Ed1hDcWxc3B7cn
Content-Type: multipart/mixed; boundary="w2JjAQZceEVGylhD"
Content-Disposition: inline


--w2JjAQZceEVGylhD
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Morton Welinder <terra@DIKU.DK> reported problems with potential race
conditions in xterm's log file handling to BugTraq.  Via a detour
involving Olaf Kirch and the Debian security team, it made its way to
me.

Here's a possible fix.  Olaf had a different one, but it is
applicable only to Linux distributions that use Red Hat's utempter
apparatus, which I understand is a kind of clone of utmpd.  My fix
tries to solve things closer to the root of the problem and
(hopefully) will work on any architecture xterm builds on.

Here's the lowdown:

Tekproc.c: There's a logging feature here that doesn't use the creat_as()
           function defined in misc.c.  Changed O_TRUNC to O_EXCL when
           opening the logfile, which has a timestamp in its name, so it
           seems excusable to fail on an existing file.
main.c: Instead of logging to xterm.debug.log, which is an easily guessable
        name for a symlink race attack, a datestamp in the same
        manner as Tekproc.c is appended.  If the call to creat_as() fails,
        the log file is not opened.  Also, when I tested this patch,
        defining DEBUG uncovered an existing error: setfileno() is not a C
        library function in Linux as far as I can tell.  I replaced this
        call with an fclose and a redirection of the stderr stream.  While
        I was at it I added a #include for the header file that the getpt()
        function is protyped in to try and silence a compiler warning.  I
        then found out that glibc doesn't actually have a prototype for it
        in their header files (contrary to their documentation).  Oops.
        This last part has nothing to do with the security fix, I just hate
        compiler warnings.
misc.c: The function creat_as() is used to try an ensure a safe logfile
        opening.  I changed it a bit.  It now returns an int instead of a
        void, reporting whether it's safe to proceed operating on the file
        or not.  Changed O_APPEND to O_EXCL; this seems to make sense now
        that the logfile names are more unique.  The safe creation of the
        logfile takes place within a child process so I modified the wait()
        and waitpid() calls to check the exit status accordingly.  Modified
        StartLog() function to check the return value of creat_as().
resize.c: Added a #include to shut up a compiler warning.  This one
worked.  xterm.h: Changed prototype of creat_as() to match its new
definition.

I'd appreciate any comments or suggestions for improvement of this
patch.

I should also note that unless a vendor has taken steps to change this, the
#defines that activate the logging code aren't even on, except on OS/2.  So
these race conditions don't pose a danger to most users.  Nevertheless, it
seems worthwhile to try to fix problems that get written up on Bugtraq.

--=20
G. Branden Robinson            |     I am sorry, but what you have mistaken
Debian GNU/Linux               |     for malicious intent is nothing more
branden@ecn.purdue.edu         |     than sheer incompetence!
roger.ecn.purdue.edu/~branden/ |     -- J. L. Rizzo II

--w2JjAQZceEVGylhD Content-Type: text/plain; charset=us-ascii
Content-Description: xterm_logging_race_fixes.diff
Content-Disposition: attachment;
filename="031_xterm_logging_race_fixes.diff"
Content-Transfer-Encoding: quoted-printable

--- xc/programs/xterm/Tekproc.c.orig	Wed Mar  1 09:10:52 2000
+++ xc/programs/xterm/Tekproc.c	Wed Mar  1 11:54:58 2000
@@ -1726,7 +1726,8 @@
=20
 	    setgid(screen->gid);
 	    setuid(screen->uid);
-	    tekcopyfd =3D open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+	    /* Close the window of opportunity by opening with O_EXCL. */
+	    tekcopyfd =3D open(buf, O_WRONLY | O_CREAT | O_EXCL, 0666);
 	    if (tekcopyfd < 0)
 		_exit(1);
 	    sprintf(initbuf, "%c%c%c%c",
--- xc/programs/xterm/main.c.orig	Wed Mar  1 09:18:05 2000
+++ xc/programs/xterm/main.c	Wed Mar  1 13:05:34 2000
@@ -119,7 +119,11 @@
 #define BSDLY	0
 #define VTDLY	0
 #define FFDLY	0
+#else /* MINIX */
+#ifdef DEBUG
+#include <time.h>
 #endif
+#endif /* MINIX */
=20
 #ifdef att
 #define ATT
@@ -179,6 +183,7 @@
 #undef  HAS_LTCHARS
 #if __GLIBC__ >=3D 2
 #include <pty.h>
+#include <stdlib.h> /* getpt() */
 #endif
 #endif
=20
@@ -1748,10 +1753,20 @@
 	/* Set up stderr properly.  Opening this log file cannot be
 	 done securely by a privileged xterm process (although we try),
 	 so the debug feature is disabled by default. */
+	time_t tstamp;
+	struct tm *tstruct;
+	char dbglogfile[35];
 	int i =3D -1;
 	if(debug) {
-	        creat_as (getuid(), getgid(), "xterm.debug.log", 0666);
-		i =3D open ("xterm.debug.log", O_WRONLY | O_TRUNC, 0666);
+		time(&tstamp);
+		tstruct =3D localtime(&tstamp);
+		sprintf(dbglogfile, "xterm.debug.log.%d-%02d-%02d.%02d:%02d:%02d",
+			tstruct->tm_year + 1900, tstruct->tm_mon + 1,
+			tstruct->tm_mday, tstruct->tm_hour,
+			tstruct->tm_min, tstruct->tm_sec);
+		if(creat_as (getuid(), getgid(), dbglogfile, 0666)) {
+			i =3D open (dbglogfile, O_WRONLY | O_TRUNC, 0666);
+		}
 	}
 	if(i >=3D 0) {
 #if defined(USE_SYSV_TERMIO) && !defined(SVR4) && !defined(linux)
@@ -1772,7 +1787,8 @@
 #ifndef linux
 		stderr->_file =3D i;
 #else
-		setfileno(stderr, i);
+		fclose(stderr);
+		stderr =3D fdopen(i, "w"); /* you can do this with glibc */
 #endif
 #endif	/* USE_SYSV_TERMIO */
=20
--- xc/programs/xterm/misc.c.orig	Wed Mar  1 09:19:17 2000
+++ xc/programs/xterm/misc.c	Wed Mar  1 12:20:40 2000
@@ -34,6 +34,9 @@
 #include <ctype.h>
 #include <pwd.h>
=20
+#include <sys/types.h>
+#include <sys/wait.h>
+
 #include <X11/Xatom.h>
 #include <X11/cursorfont.h>
=20
@@ -506,21 +509,26 @@
 #if defined(ALLOWLOGGING) || defined(DEBUG)
=20
 /*
- * create a file only if we could with the permissions of the real
user id.
+ * Create a file only if we could with the permissions of the real user id.
  * We could emulate this with careful use of access() and following
  * symbolic links, but that is messy and has race conditions.
  * Forking is messy, too, but we can't count on setreuid() or saved set-ui=
ds
  * being available.
  *
- * Note:  when called for user logging, we have ensured that the
real and
+ * Note: When called for user logging, we have ensured that the real
and
  * effective user ids are the same, so this remains as a convenience
funct= ion
  * for the debug logs.
+ *
+ * Returns 1 if we can proceed to open the file in relative safety, 0
+ * otherwise.
  */
-void
+int
 creat_as(int uid, int gid, char *pathname, int mode)
 {
     int fd;
     int pid;
+    int retval =3D 0;
+    int childstat;
 #ifndef HAVE_WAITPID
     int waited;
     SIGNAL_T (*chldfunc) (int);
@@ -534,19 +542,19 @@
     case 0:			/* child */
 	setgid(gid);
 	setuid(uid);
-	fd =3D open(pathname, O_WRONLY|O_CREAT|O_APPEND, mode);
+	fd =3D open(pathname, O_WRONLY|O_CREAT|O_EXCL, mode);
 	if (fd >=3D 0) {
 	    close(fd);
 	    _exit(0);
 	} else
 	    _exit(1);
     case -1:			/* error */
-	return;
+	return retval;
     default:			/* parent */
 #ifdef HAVE_WAITPID
-	waitpid(pid, NULL, 0);
+	waitpid(pid, &childstat, 0);
 #else
-	waited =3D wait(NULL);
+	waited =3D wait(&childstat);
 	signal(SIGCHLD, chldfunc);
 	/*
 	  Since we had the signal handler uninstalled for a while,
@@ -558,6 +566,8 @@
 		Cleanup(0);
 	while ( (waited=3Dnonblocking_wait()) > 0);
 #endif
+	if(WIFEXITED(childstat)) retval =3D 1;
+	return retval;
     }
 }
 #endif
@@ -673,19 +683,17 @@
 #endif
 	} else {
 		if(access(screen->logfile, F_OK) !=3D 0) {
-		    if (errno =3D=3D ENOENT)
-			creat_as(screen->uid, screen->gid,
-				 screen->logfile, 0644);
-		    else
-			return;
+		    if (errno !=3D ENOENT) return;
 		}
=20
+		if(!(creat_as(screen->uid, screen->gid, screen->logfile, 0644))
+		    return;
 		if(access(screen->logfile, F_OK) !=3D 0
 		   || access(screen->logfile, W_OK) !=3D 0)
 		    return;
 		if((screen->logfd =3D open(screen->logfile, O_WRONLY | O_APPEND,
 					 0644)) < 0)
-			return;
+		    return;
 	}
 	screen->logstart =3D CURRENT_EMU_VAL(screen, Tbptr, bptr);
 	screen->logging =3D TRUE;
--- xc/programs/xterm/resize.c.orig	Wed Mar  1 12:53:48 2000
+++ xc/programs/xterm/resize.c	Wed Mar  1 13:00:21 2000
@@ -282,6 +282,7 @@
 #endif
 #else
 #include <curses.h>
+#include <term.h> /* tgetent() */
 #endif /* HAVE_TERMCAP_H  */
 #endif
=20
--- xc/programs/xterm/xterm.h.orig	Wed Mar  1 11:53:37 2000
+++ xc/programs/xterm/xterm.h	Wed Mar  1 11:54:22 2000
@@ -223,6 +223,7 @@
 extern int XStrCmp (char *s1, char *s2);
 extern int xerror (Display *d, XErrorEvent *ev);
 extern int xioerror (Display *dpy);
+extern int creat_as (int uid, int gid, char *pathname, int mode);
 extern void Bell (int which, int percent);
 extern void Changename (char *name);
 extern void Changetitle (char *name);
@@ -241,7 +242,6 @@
 extern void Setenv (char *var, char *value);
 extern void SysError (int i);
 extern void VisualBell (void);
-extern void creat_as (int uid, int gid, char *pathname, int mode);
 extern void do_dcs (Char *buf, size_t len);
 extern void do_osc (Char *buf, int len);
 extern void do_xevents (void);

--w2JjAQZceEVGylhD--

--y0Ed1hDcWxc3B7cn
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.1 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iEYEARECAAYFAji9qkYACgkQ6kxmHytGonwJrgCfXQVKtJwB7e+eltj3y2Zh5hsX
7TQAn2G67wPYW1lpbzSh38vFwDE/B2QB
=vpRj
-----END PGP SIGNATURE-----

--y0Ed1hDcWxc3B7cn--
(4857545) ------------------------------------------(Ombruten)

4861174 2000-03-03  20:45  /30 rader/ Postmaster
Mottagare: Bugtraq (import) <10098>
Ärende: Re: [XFree86 3.3.6] fix for race conditions in xterm logfil 
------------------------------------------------------------
             handling
Approved-By: aleph1@SECURITYFOCUS.COM
Delivered-To: bugtraq@lists.securityfocus.com
Delivered-To: BUGTRAQ@securityfocus.com
Mime-Version: 1.0
X-Sender: jk@mail.espy.org
Content-Type: text/plain; charset="us-ascii"
Message-ID:  <p04310104b4e4bc630df8@[206.163.71.146]>
Date:         Thu, 2 Mar 2000 16:52:09 -0800
Reply-To: Joel Klecker <jk@ESPY.ORG>
Sender: Bugtraq List <BUGTRAQ@SECURITYFOCUS.COM>
From: Joel Klecker <jk@ESPY.ORG>
X-To:         Branden Robinson <branden@ECN.PURDUE.EDU> 
             BUGTRAQ@SECURITYFOCUS.COM
To: BUGTRAQ@SECURITYFOCUS.COM
In-Reply-To:  <20000301183950.D14657@ecn.purdue.edu>

At 18:39 -0500 2000-03-01, Branden Robinson wrote:
>        call with an fclose and a redirection of the stderr stream.  While
>        I was at it I added a #include for the header file that the getpt()
>        function is protyped in to try and silence a compiler warning.  I
>        then found out that glibc doesn't actually have a prototype for it
>        in their header files (contrary to their documentation).

Yes it does, getpt() is a GNU extension, therefore you have to define
the _GNU_SOURCE macro in order to get the prototype.
--
Joel Klecker (aka Espy)                    Debian GNU/Linux Developer
<URL:mailto:jk@espy.org>                 <URL:mailto:espy@debian.org>
<URL:http://web.espy.org/>               <URL:http://www.debian.org/>
(4861174) ------------------------------------------(Ombruten)

4870821 2000-03-07  10:30  /34 rader/ Postmaster
Mottagare: Bugtraq (import) <10132>
Ärende: Re: [XFree86 3.3.6] fix for race conditions in xterm logfil 
------------------------------------------------------------
             handling
Approved-By: aleph1@SECURITYFOCUS.COM
Delivered-To: bugtraq@lists.securityfocus.com
Delivered-To: BUGTRAQ@securityfocus.com
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Message-ID:  <20000306103505.E16488@monad.swb.de>
Date:         Mon, 6 Mar 2000 10:35:05 +0100
Reply-To: Olaf Kirch <okir@CALDERA.DE>
Sender: Bugtraq List <BUGTRAQ@SECURITYFOCUS.COM>
From: Olaf Kirch <okir@CALDERA.DE>
X-To:         BUGTRAQ@SECURITYFOCUS.COM
To: BUGTRAQ@SECURITYFOCUS.COM
In-Reply-To:  <20000301183950.D14657@ecn.purdue.edu>; fro 
             branden@ecn.purdue.edu on Wed, Mar 01, 2000 at 06:39:51PM -0500

On Wed, Mar 01, 2000 at 06:39:51PM -0500, Branden Robinson wrote:
> Here's a possible fix.  Olaf had a different one, but it is applicable only
> to Linux distributions that use Red Hat's utempter apparatus, which I
> understand is a kind of clone of utmpd.

Just to clarify this a little; the patch I did was not for this
specifiy problem; it's purpose is to do away with the setuid root
requirement for xterm altogether. The only two reasons for requiring
a setuid root bit on xterm are ptys (taken care of by /dev/pts
nowadays), and utmp management (which we're currently doing using
utempter). The same holds for kterm and kconsole, as well as the
gnome counterparts I assume.

Olaf
--
Olaf Kirch         |  --- o --- Nous sommes du soleil we love when we play
okir@monad.swb.de  |    / | \   sol.dhoop.naytheet.ah kin.ir.samse.qurax
okir@caldera.de    +-------------------- Why Not?! -----------------------
         UNIX, n.: Spanish manufacturer of fire extinguishers.
(4870821) ------------------------------------------(Ombruten)