Subject: xsrc/7260: proposed fix for xtrans vulnerability
To: None <gnats-bugs@gnats.netbsd.org>
From: Matthieu Herrb <matthieu@bluenote.laas.fr>
List: netbsd-bugs
Date: 03/27/1999 17:21:52
>Number:         7260
>Category:       xsrc
>Synopsis:       proposed fix for xtrans vulnerability
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    gnats-admin (GNATS administrator)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Mar 27 08:35:01 1999
>Last-Modified:
>Originator:     Matthieu Herrb
>Organization:
	
>Release:        NetBSD-current 03/23/1999
>Environment:
	
System: NetBSD bluenote 1.3K NetBSD 1.3K (BLUENOTE) #0: Thu Mar 25 20:50:46 CET 1999 matthieu@bluenote:/local/NetBSD/src/sys/arch/i386/compile/BLUENOTE i386


>Description:
"in.telnetd" <telnetd@DOEMILL.SHOCKING.COM> has reported on
bugtraq a vulnerability in xtrans, which allow any user to
change the modes of any directory to 1777.

The included patch is a proposed fix. I also sent it to XFree86
developper's list.

>How-To-Repeat:

ln -s /root /tmp/.X11-unix
xinit

>Fix:
Index: xc/lib/xtrans/Xtransint.h
===================================================================
RCS file: /cvs/X11/xc/lib/xtrans/Xtransint.h,v
retrieving revision 1.1.1.2
diff -u -r1.1.1.2 Xtransint.h
--- xc/lib/xtrans/Xtransint.h	1998/11/28 08:26:08	1.1.1.2
+++ xc/lib/xtrans/Xtransint.h	1999/03/26 08:20:27
@@ -455,6 +455,12 @@
 #endif
 );
 
+static int trans_mkdir (
+#if NeedFunctionPrototypes
+    char *,		/* path */
+    int			/* mode */
+#endif
+);
 
 /*
  * Some XTRANSDEBUG stuff
Index: xc/lib/xtrans/Xtranslcl.c
===================================================================
RCS file: /cvs/X11/xc/lib/xtrans/Xtranslcl.c,v
retrieving revision 1.1.1.4
diff -u -r1.1.1.4 Xtranslcl.c
--- xc/lib/xtrans/Xtranslcl.c	1999/01/08 17:31:44	1.1.1.4
+++ xc/lib/xtrans/Xtranslcl.c	1999/03/26 08:20:32
@@ -444,9 +444,11 @@
 #else
     mode = 0777;
 #endif
-
-    mkdir(X_STREAMS_DIR, mode);
-    chmod(X_STREAMS_DIR, mode);
+    if (trans_mkdir(X_STREAMS_DIR, mode) == -1) {
+	PRMSG (1, "PTSOpenServer: mkdir(%s) failed, errno = %d\n",
+	       X_STREAMS_DIR, errno, 0);
+	return(-1);
+    }
 
     if( (fd=open(server_path, O_RDWR)) >= 0 ) {
 #if 0
@@ -724,9 +726,11 @@
 #else
     mode = 0777;
 #endif
-
-    mkdir(X_STREAMS_DIR, mode);
-    chmod(X_STREAMS_DIR, mode);
+    if (trans_mkdir(X_STREAMS_DIR, mode) == -1) {
+	PRMSG (1, "NAMEDOpenServer: mkdir(%s) failed, errno = %d\n",
+	       X_STREAMS_DIR, errno, 0);
+	return(-1);
+    }
 
     if(stat(server_path, &sbuf) != 0) {
 	if (errno == ENOENT) {
@@ -1044,10 +1048,18 @@
     mode = 0777;
 #endif
 
-    mkdir(X_STREAMS_DIR, mode); /* "/dev/X" */
-    chmod(X_STREAMS_DIR, mode);
-    mkdir(X_ISC_DIR, mode); /* "/dev/X/ISCCONN" */
-    chmod(X_ISC_DIR, mode);
+    /* "/dev/X" */
+    if (trans_mkdir(X_STREAMS_DIR, mode) == -1) {
+	PRMSG (1, "ISCOpenServer: mkdir(%s) failed, errno = %d\n",
+	       X_STREAMS_DIR, errno, 0);
+	return(-1);
+    }
+    /* "/dev/X/ISCCONN" */
+    if (trans_mkdir(X_ISC_DIR, mode) == -1) {
+	PRMSG (1, "ISCOpenServer: mkdir(%s) failed, errno = %d\n",
+	       X_ISC_DIR, errno, 0);
+	return(-1);
+    }
     
     unlink(server_path);
     
@@ -1072,8 +1084,11 @@
      */
 #define X_UNIX_DIR	"/tmp/.X11-unix"
     
-    mkdir(X_UNIX_DIR, mode);
-    chmod(X_UNIX_DIR, mode);
+    if (trans_mkdir(X_UNIX_DIR, mode) == -1) {
+	PRMSG (1, "ISCOpenServer: mkdir(%s) failed, errno = %d\n",
+	       X_UNIX_DIR, errno, 0);
+	return(-1);
+    }
     
     unlink(server_unix_path);
     
Index: xc/lib/xtrans/Xtranssock.c
===================================================================
RCS file: /cvs/X11/xc/lib/xtrans/Xtranssock.c,v
retrieving revision 1.1.1.4
diff -u -r1.1.1.4 Xtranssock.c
--- xc/lib/xtrans/Xtranssock.c	1999/01/08 17:31:46	1.1.1.4
+++ xc/lib/xtrans/Xtranssock.c	1999/03/26 08:20:38
@@ -946,8 +946,11 @@
 #else
     mode = 0777;
 #endif
-    mkdir (UNIX_DIR, mode);
-    chmod (UNIX_DIR, mode);
+    if (trans_mkdir(UNIX_DIR, mode) == -1) {
+	PRMSG (1, "SocketUNIXCreateListener: mkdir(%s) failed, errno = %d\n",
+	       UNIX_DIR, errno, 0);
+	return TRANS_CREATE_LISTENER_FAILED;
+    }
 #endif
 
     sockname.sun_family = AF_UNIX;
@@ -1041,8 +1044,11 @@
 #else
 	mode = 0777;
 #endif
-	mkdir (UNIX_DIR, mode);
-	chmod (UNIX_DIR, mode);
+        if (trans_mkdir(UNIX_DIR, mode) == -1) {
+            PRMSG (1, "SocketUNIXResetListener: mkdir(%s) failed, errno = %d\n",
+	    UNIX_DIR, errno, 0);
+	    return TRANS_RESET_FAILURE;
+        }
 #endif
 
 	close (ciptr->fd);
Index: xc/lib/xtrans/Xtransutil.c
===================================================================
RCS file: /cvs/X11/xc/lib/xtrans/Xtransutil.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 Xtransutil.c
--- xc/lib/xtrans/Xtransutil.c	1997/09/05 09:02:43	1.1.1.1
+++ xc/lib/xtrans/Xtransutil.c	1999/03/26 08:20:40
@@ -465,3 +465,32 @@
 
     return (1);
 }
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+static int 
+trans_mkdir(char *path, int mode)
+{
+    struct stat buf;
+
+    if (mkdir(path, mode) == 0) {
+	/* I don't know why this is done, but  it was in the original 
+	   xtrans code */
+	chmod(path, mode);
+	return 0;
+    }
+    /* If mkdir failed with EEXIST, test if it is a directory with 
+       the right modes, else fail */
+    if (errno == EEXIST) {
+	if (stat(path, &buf) != 0) {
+	    return -1;
+	}
+	if (S_ISDIR(buf.st_mode) && ((buf.st_mode & ~S_IFMT) == mode)) {
+	    return 0;
+	}
+    }
+    /* In all other cases, fail */
+    return -1;
+}

>Audit-Trail:
>Unformatted: