The debian-private mailing list leak, part 1. Volunteers have complained about Blackmail. Lynchings. Character assassination. Defamation. Cyberbullying. Volunteers who gave many years of their lives are picked out at random for cruel social experiments. The former DPL's girlfriend Molly de Blanc is given volunteers to experiment on for her crazy talks. These volunteers never consented to be used like lab rats. We don't either. debian-private can no longer be a safe space for the cabal. Let these monsters have nowhere to hide. Volunteers are not disposable. We stand with the victims.

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

Linux ld.so patch (fwd)



Have we applied this patch?

John Goerzen, Running FREE Debian | Developer for Debian GNU/Linux
jgoerzen@southwind.net            | Asst. sysadmin, Wichita State CS Dept.
jgoerzen@gesundheit.cs.twsu.edu   | All opinions are stricly my own
jgoerzen@complete.org [Owner, the Communications Centre (complete.org)]
---------- Forwarded message ----------
Date: Mon, 21 Jul 1997 02:01:48 -0700
From: Alex Belits <abelits@PHOBOS.ILLTEL.DENVER.CO.US>
To: BUGTRAQ@NETSPACE.ORG
Subject: Linux ld.so patch

On Fri, 18 Jul 1997, KSR[T] wrote:

> Our advisory contained one serious piece of mis-information.  The latest
> version of ld.so that we tested (1.9.2) still appeared to be
> vulnerable to this overflow.
>
> We strongly recommend that anyone running linux install the patch
> distributed with the advisory, or wait for your vendor to release
> an updated ld.so package and install that as soon as possible.
>
> The patch is available from our web site (http://www.dec.net/ksrt).
>
> We apologize for any confusion this might have caused.
>

  Since other overflows were found in ld.so of both elf and a.out, I've
made a patch that converts vsprintf() into vsnprintf() and included fixed
version of the original patch and suggested fix about 11-th item in
libraries list. The patch is against ld.so 1.9.2 distribution.

--
Alex
diff -ru ld.so-1.9.2/Config.mk ld.so-1.9.2-fixed/Config.mk
--- ld.so-1.9.2/Config.mk	Tue Mar 18 18:41:08 1997
+++ ld.so-1.9.2-fixed/Config.mk	Fri Jul 18 01:09:43 1997
@@ -2,7 +2,7 @@
 #ARCH = m68k
 #ARCH = sparc
 #DEBUG = true
-#AOUT_SUPPORT = true
+AOUT_SUPPORT = true
 
 LDSO_ADDR = 62f00020
 LDSO_ENTRY = "0x$(LDSO_ADDR)"
@@ -19,8 +19,8 @@
 RANLIB = ranlib
 
 ifeq ($(ARCH),i386)
-AOUTCC = /usr/i486-linuxaout/bin/gcc
-#AOUTCC = gcc -b i486-linuxaout
+#AOUTCC = /usr/i486-linuxaout/bin/gcc
+AOUTCC = gcc -b i486-linuxaout
 AOUTLD = /usr/i486-linuxaout/bin/ld -m i386linux
 endif
 ifeq ($(ARCH),m68k)
diff -ru ld.so-1.9.2/d-link/boot1.c ld.so-1.9.2-fixed/d-link/boot1.c
--- ld.so-1.9.2/d-link/boot1.c	Tue Mar 18 18:01:16 1997
+++ ld.so-1.9.2-fixed/d-link/boot1.c	Fri Jul 18 01:05:14 1997
@@ -114,10 +114,12 @@
 
 #define ALLOW_ZERO_PLTGOT
 
+#define ELF_LDSO_IMAGE "/lib/ld-linux.so.1"
+
 static char * _dl_malloc_addr, *_dl_mmap_zero;
 char * _dl_library_path = 0; /* Where we look for libraries */
 char *_dl_preload = 0; /* Things to be loaded before the libs. */
-char *_dl_progname = "/lib/ld-linux.so.1";
+char *_dl_progname = ELF_LDSO_IMAGE;
 static char * _dl_not_lazy = 0;
 static char * _dl_warn = 0; /* Used by ldd */
 static char * _dl_trace_loaded_objects = 0;
@@ -171,6 +173,45 @@
 #endif
 
 /*
+ *	Stop argv0 overflowing vsprintf, but also try to stop false positives
+ *	We obey the following rule
+ *
+ *	If namesize < 256  keep
+ *	If name from last / < 256 use that
+ *	else use ELF_LDSO_IMAGE
+ *
+ *	This ensures /very/long/stupid/nfs/path/we/often/get/foobarcmd
+ *	comes out at least as.  
+ *
+ *	foobarcmd: someerror
+ *
+ *	Even if we fix vsprintf to be vsnprintf (which we should), this
+ *	ought to be kept to help make real size limited errors clearer.
+ */
+ 
+static char *argv_remap(char *ptr)
+{
+	char *tmp;
+	if(strlen(ptr)<256)
+		return ptr;
+	if(!*ptr)
+		return ptr;
+	tmp=ptr+strlen(ptr)-1;
+	/*
+	 *	Walk back down the chain until we find a slash
+	 */
+	while(tmp>=ptr && *tmp!='/')
+		tmp--;
+	/*
+	 *	No slash, or too long after slash and Im not playing so nyah
+	 */
+	if(*tmp!='/')
+		return ELF_LDSO_IMAGE;
+	if(strlen(tmp)>256)	/* Not off by 1 .. strlen includes the / */
+		return ELF_LDSO_IMAGE;
+	return tmp+1;
+}
+/*
  * This stub function is used by some debuggers.  The idea is that they
  * can set an internal breakpoint on it, so that we are notified when the
  * address mapping is changed in some way.
@@ -507,7 +548,7 @@
   }
 
   if (argv[0])
-    _dl_progname = argv[0];
+    _dl_progname = argv_remap(argv[0]);
 
   /* Now we need to figure out what kind of options are selected.
    Note that for SUID programs we ignore the settings in LD_LIBRARY_PATH */
Only in ld.so-1.9.2-fixed/d-link: boot1.c.orig
Only in ld.so-1.9.2/d-link: ld-linux.so
Only in ld.so-1.9.2/d-link/libdl: libdl.so
diff -ru ld.so-1.9.2/d-link/vsprintf.c ld.so-1.9.2-fixed/d-link/vsprintf.c
--- ld.so-1.9.2/d-link/vsprintf.c	Wed Oct  9 12:17:21 1996
+++ ld.so-1.9.2-fixed/d-link/vsprintf.c	Mon Jul 21 01:16:35 1997
@@ -127,11 +127,13 @@
 	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
 
 	char buf[1024];
+	char *endbuf;
 	va_list(args);
 
 	va_start(args, fmt);
+	endbuf=buf+1023;
 
-	for (str=buf ; *fmt ; ++fmt) {
+	 for (str=buf ; *fmt && str < endbuf ; ++fmt) {
 		if (*fmt != '%') {
 			*str++ = *fmt;
 			continue;
@@ -191,10 +193,11 @@
 		switch (*fmt) {
 		case 'c':
 			if (!(flags & LEFT))
-				while (--field_width > 0)
+				while (--field_width > 0 && str < endbuf)
 					*str++ = ' ';
-			*str++ = (unsigned char) va_arg(args, int);
-			while (--field_width > 0)
+			if (str < endbuf)
+			  *str++ = (unsigned char) va_arg(args, int);
+			while (--field_width > 0 && str < endbuf)
 				*str++ = ' ';
 			continue;
 
@@ -206,11 +209,11 @@
 			len = _dl_strlen(s);
 
 			if (!(flags & LEFT))
-				while (len < field_width--)
+				while (len < field_width-- && str < endbuf)
 					*str++ = ' ';
-			for (i = 0; i < len; ++i)
+			for (i = 0; i < len && str < endbuf; ++i)
 				*str++ = *s++;
-			while (len < field_width--)
+			while (len < field_width-- && str < endbuf)
 				*str++ = ' ';
 			continue;
 
@@ -219,9 +222,12 @@
 				field_width = 2*sizeof(void *);
 				flags |= ZEROPAD;
 			}
-			str = number(str,
-				(unsigned long) va_arg(args, void *), 16,
-				field_width, precision, flags);
+
+			if (field_width <= endbuf-str){
+			           str = number(str,
+				     (unsigned long) va_arg(args, void *), 16,
+				     field_width, precision, flags);
+			}
 			continue;
 
 
@@ -254,9 +260,9 @@
 
 		default:
 			if (*fmt != '%')
-				*str++ = '%';
+				if (str < endbuf) *str++ = '%';
 			if (*fmt)
-				*str++ = *fmt;
+				if (str < endbuf) *str++ = *fmt;
 			else
 				--fmt;
 			continue;
@@ -272,7 +278,17 @@
 			num = va_arg(args, int);
 		else
 			num = va_arg(args, unsigned int);
-		str = number(str, num, base, field_width, precision, flags);
+		if (field_width != -1) {
+                        if (field_width <= endbuf-str) { 
+			     str = number(str, num, base,
+					  field_width, precision, flags);
+			}
+		}else{
+                        if (100 <= endbuf-str) { 
+			     str = number(str, num, base,
+					  field_width, precision, flags);
+			}
+		}
 	}
 	*str = '\0';
 	_dl_write(fd, buf, str-buf);
diff -ru ld.so-1.9.2/ld-so/fdprintf.c ld.so-1.9.2-fixed/ld-so/fdprintf.c
--- ld.so-1.9.2/ld-so/fdprintf.c	Sat May 25 22:07:21 1996
+++ ld.so-1.9.2-fixed/ld-so/fdprintf.c	Mon Jul 21 01:01:45 1997
@@ -9,7 +9,7 @@
 #include <stdarg.h>
 #include <unistd.h>
 
-extern int vsprintf(char * buf, const char * fmt, va_list args);
+extern int vsnprintf(char * buf, size_t size, const char * fmt, va_list args);
 
 int fdprintf(int fd, const char *fmt, ...)
 {
@@ -18,7 +18,7 @@
 	char buf[1024];
 
 	va_start(args, fmt);
-	i=vsprintf(buf,fmt,args);
+	i=vsnprintf(buf,1024, fmt,args);
 	va_end(args);
 	write(fd, buf, i);
 
diff -ru ld.so-1.9.2/ld-so/ld.so.c ld.so-1.9.2-fixed/ld-so/ld.so.c
--- ld.so-1.9.2/ld-so/ld.so.c	Mon Jan  6 20:51:06 1997
+++ ld.so-1.9.2-fixed/ld-so/ld.so.c	Sun Jul 20 23:29:35 1997
@@ -149,6 +149,46 @@
 }
 #endif
 
+/*
+ *	Stop argv0 overflowing vsprintf, but also try to stop false positives
+ *	We obey the following rule
+ *
+ *	If namesize < 256  keep
+ *	If name from last / < 256 use that
+ *	else use LDSO_NAME
+ *
+ *	This ensures /very/long/stupid/nfs/path/we/often/get/foobarcmd
+ *	comes out at least as.  
+ *
+ *	foobarcmd: someerror
+ *
+ *	Even if we fix vsprintf to be vsnprintf (which we should), this
+ *	ought to be kept to help make real size limited errors clearer.
+ */
+ 
+static char *argv_remap(char *ptr)
+{
+	char *tmp;
+	if(strlen(ptr)<256)
+		return ptr;
+	if(!*ptr)
+		return ptr;
+	tmp=ptr+strlen(ptr)-1;
+	/*
+	 *	Walk back down the chain until we find a slash
+	 */
+	while(tmp>=ptr && *tmp!='/')
+		tmp--;
+	/*
+	 *	No slash, or too long after slash and Im not playing so nyah
+	 */
+	if(*tmp!='/')
+		return LDSO_IMAGE;
+	if(strlen(tmp)>256)	/* Not off by 1 .. strlen includes the / */
+		return LDSO_IMAGE;
+	return tmp+1;
+}
+
 void
 shared_loader(int func, ...)
 {
@@ -205,12 +245,14 @@
 	save_mapinfo(mapinfo);
 #endif
 	argv0 = va_arg(ap, char *);
+	argv0 = argv_remap(argv0);
 	__environ = va_arg(ap, char **);
 	__SHARED_LIBRARIES__ = va_arg(ap, struct libentry **);
 	_SHARABLE_CONFLICTS__ = va_arg(ap, struct fixuplist *);
 	if (func == FUNC_LINK_AND_CALLBACK)
 	  callback = va_arg(ap, callbackptr);
 	va_end(ap);
+	
 	break;
     default:
 	/* you want me to do what? */
@@ -226,7 +268,8 @@
     /* find out who we are, in case somebody wants to know */
     if (!argv0 && !(argv0 = getenv(LDD_ARGV0)))
 	argv0 = LDSO_IMAGE;
-
+    argv0=argv_remap(argv0);
+    
     /* hmm, you want your own configuration, do you? */
     if (getuid() == geteuid() && getgid() == getegid())
     {
@@ -322,6 +365,11 @@
 		.text section. This is passed to ldpreload() below */
 	    if (preload || callback)
 	    {
+	    	if(nlibs==10)
+	    	{
+	    		fdprintf(2, "%s: too many preloads\n",argv0);
+	    		exit(EXIT_FATAL);
+	    	}
 	        libs[nlibs] = alloca(strlen(buffer)+1);
 	        strcpy(libs[nlibs], buffer);
 	        nlibs++;
Only in ld.so-1.9.2-fixed/ld-so: ld.so.c.orig
diff -ru ld.so-1.9.2/ld-so/strerror.c ld.so-1.9.2-fixed/ld-so/strerror.c
--- ld.so-1.9.2/ld-so/strerror.c	Sat May 25 13:30:33 1996
+++ ld.so-1.9.2-fixed/ld-so/strerror.c	Mon Jul 21 01:04:52 1997
@@ -41,12 +41,12 @@
 
   if (errnum < 0 || errnum >= _sys_nerr)
     {
-      static char unknown_error[] = "Unknown error 000000000000000000000";
+      static char unknown_error[36] = "Unknown error 000000000000000000000";
       static char fmt[] = "Unknown error %d";
 #ifdef __linux__
-      sprintf(unknown_error, fmt, errnum);
+      snprintf(unknown_error, 36, fmt, errnum);
 #else
-      size_t len = sprintf(unknown_error, fmt, errnum);
+      size_t len = snprintf(unknown_error, 36, fmt, errnum);
       if (len < sizeof(fmt) - 2)
 	return NULL;
       unknown_error[len] = '\0';
diff -ru ld.so-1.9.2/ld-so/vsprintf.c ld.so-1.9.2-fixed/ld-so/vsprintf.c
--- ld.so-1.9.2/ld-so/vsprintf.c	Sat May 25 22:07:18 1996
+++ ld.so-1.9.2-fixed/ld-so/vsprintf.c	Mon Jul 21 01:11:20 1997
@@ -104,13 +104,14 @@
 	return str;
 }
 
-int vsprintf(char *buf, const char *fmt, va_list args)
+int vsnprintf(char *buf, size_t maxsize, const char *fmt, va_list args)
 {
 	int len;
 	unsigned long num;
 	int i, base;
 	char * str;
 	const char *s;
+	char *endbuf;
 
 	int flags;		/* flags to number() */
 
@@ -119,7 +120,10 @@
 				   number of chars for from string */
 	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
 
-	for (str=buf ; *fmt ; ++fmt) {
+	if (maxsize == 0) return 0;
+	endbuf = buf + maxsize - 1;
+
+        for (str=buf ; *fmt && str < endbuf ; ++fmt) {
 		if (*fmt != '%') {
 			*str++ = *fmt;
 			continue;
@@ -179,10 +183,11 @@
 		switch (*fmt) {
 		case 'c':
 			if (!(flags & LEFT))
-				while (--field_width > 0)
+				while (--field_width > 0 && str < endbuf)
 					*str++ = ' ';
-			*str++ = (unsigned char) va_arg(args, int);
-			while (--field_width > 0)
+			if (str < endbuf)
+				*str++ = (unsigned char) va_arg(args, int);
+			while (--field_width > 0 && str < endbuf)
 				*str++ = ' ';
 			continue;
 
@@ -194,11 +199,11 @@
 			len = strlen(s);
 
 			if (!(flags & LEFT))
-				while (len < field_width--)
+				while (len < field_width-- && str < endbuf)
 					*str++ = ' ';
-			for (i = 0; i < len; ++i)
+			for (i = 0; i < len && str < endbuf; ++i)
 				*str++ = *s++;
-			while (len < field_width--)
+			while (len < field_width-- && str < endbuf)
 				*str++ = ' ';
 			continue;
 
@@ -207,9 +212,12 @@
 				field_width = 2*sizeof(void *);
 				flags |= ZEROPAD;
 			}
-			str = number(str,
-				(unsigned long) va_arg(args, void *), 16,
-				field_width, precision, flags);
+
+			if (field_width <= endbuf-str){
+				str = number(str,
+				  (unsigned long) va_arg(args, void *), 16,
+				  field_width, precision, flags);
+			}
 			continue;
 
 
@@ -242,9 +250,9 @@
 
 		default:
 			if (*fmt != '%')
-				*str++ = '%';
+				if (str < endbuf) *str++ = '%';
 			if (*fmt)
-				*str++ = *fmt;
+				if (str < endbuf) *str++ = *fmt;
 			else
 				--fmt;
 			continue;
@@ -260,19 +268,29 @@
 			num = va_arg(args, int);
 		else
 			num = va_arg(args, unsigned int);
-		str = number(str, num, base, field_width, precision, flags);
+		if (field_width != -1) {
+			if (field_width <= endbuf-str) { 
+			    str = number(str, num, base,
+					 field_width, precision, flags);
+			}
+		}else{
+			if (100 <= endbuf-str) { 
+			    str = number(str, num, base,
+					 field_width, precision, flags);
+			}
+		}
 	}
 	*str = '\0';
 	return str-buf;
 }
 
-int sprintf(char * buf, const char *fmt, ...)
+int snprintf(char * buf, size_t size, const char *fmt, ...)
 {
 	va_list args;
 	int i;
 
 	va_start(args, fmt);
-	i=vsprintf(buf,fmt,args);
+	i=vsnprintf(buf,size,fmt,args);
 	va_end(args);
 	return i;
 }
Only in ld.so-1.9.2/man: ld.so.info
Only in ld.so-1.9.2/test: etestf
Only in ld.so-1.9.2/test: etesti
Only in ld.so-1.9.2/util: elf-ok
Only in ld.so-1.9.2/util: ldconfig
Only in ld.so-1.9.2/util: ldd
Only in ld.so-1.9.2/util: lddstub