[ale] KSR[T] Advisory #2: ld.so

KSR[T] ksrt at DEC.NET
Thu Jul 17 20:15:21 EDT 1997


                                                          KSR[T] Advisory #002
                                                          Date:   Jul 16, 1997
                                                          ID #:   lin-ldso-002

Operating System(s): Linux

Affected Program:    ld.so / ld-linux.so

Problem Description: ld.so is the run-time linker used by dynamically linked
                     executables(a.out).  Inside the error reporting function
                     there is a call to vsprintf, which doesn't check the size
                     of the string it is storing in an automatic buffer.

                     The ELF version of run-time linker(ld-linux.so) is
                     vulnerable to an almost identical stack overwrite.

Compromise:          A local user that can execute any dynamically linked
                     setuid binary and can force ld.so to error, can execute
                     arbitrary code as root.

Patch/Fix:           Upgrade your ld.so to the latest version, or apply the
                     patch below provided by Alan Cox.

---- cut here ----
--- ld.so-1.7.14/d-link/boot1.c Thu Dec 14 19:08:19 1995
+++ ld.so-1.7.14-fixed/d-link/boot1.c   Wed Jul 16 15:37:11 1997
@@ -108,10 +108,12 @@
 #include "syscall.h"
 #include "string.h"

+#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;
@@ -165,6 +167,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.
@@ -487,7 +528,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 */
--- ld.so-1.7.14/ld-so/ld.so.c  Tue Nov 14 19:15:02 1995
+++ ld.so-1.7.14-fixed/ld-so/ld.so.c    Tue Jun 24 10:55:54 1997
@@ -151,6 +151,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, ...)
 {
@@ -207,12 +247,14 @@
        save_mapinfo(mapinfo);
 #endif
        argv0 = va_arg(ap, char *);
+       argv0 = arg_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? */
@@ -228,7 +270,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())
     {
@@ -328,6 +371,11 @@
                .text section. This is passed to ldpreload() below */
            if (preload || callback)
            {
+               if(nlibs==11)
+               {
+                       fdprintf(2, "%s: too many preloads\n",argv[0]);
+                       exit(EXIT_FATAL);
+               }
                libs[nlibs] = alloca(strlen(buffer)+1);
                strcpy(libs[nlibs], buffer);
                nlibs++;
---- cut here ----

-----
KSR[T] Website : http://www.dec.net/ksrt
E-mail: ksrt at dec.net






More information about the Ale mailing list