From: Goswin Brederlow <goswin.brederlow@student.uni-tuebingen.de>
Subject: Bug#129345: patch to prevent a loop between libdl and libsafe causing libdl to crash
To: 129345@bugs.debian.org
Date: 01 Sep 2002 23:54:35 +0200
Reply-To: Goswin Brederlow <goswin.brederlow@student.uni-tuebingen.de>,
	129345@bugs.debian.org
Resent-From: Goswin Brederlow <goswin.brederlow@student.uni-tuebingen.de>


-------
[D. Coe edited this patch slightly -- moved an unrelated change into the
Makefile itself [it changed the debugging comments only], and corrected a 
spelling error and reworded the comments.  The original patch is in the 
bug tracking system, if you want to see it as submitted by Goswin.]
-------
-------
D. Coe subsequently modified the patch further, because in some cases
the initializations did not occur (e.g. when IO_vfscanf or memcpy was
called from ps or top (likely one of the libraries they use).  maybe
they do something that disables libsafe's library globals initialization?


In any case, I've adopted both strategise in this new patch; the addresses
are preloaded as Goswin had coded, but they are also individually checked
each time needed (as was the case before Goswin's patch), and are initialized
at that point if necessary.  Hopefully this will let ps and top work
and also continue to work around the libdl problem.
-------

Hi,

if libsafe is invoked from inside libdl (or only inside dlerror()?)
and a real_XXX function is not yet looked up it will reenter
libdl. That causes memory corruption resulting in a read from 0x0 and
thus segfault.

The patch below makes libsafe cache all needed symbols once upon
init. That not only causes less lookups than before but should prevent
fatal loops. Failures of the initial lookups might not be reported
correctly but terminate in some odd way if the functions needed to
report are not yet looked up.

MfG
        Goswin

----------------------------------------------------------------------
diff -Nurd libsafe-2.0-16/src/intercept.c libsafe-2.0-16-mrvn/src/intercept.c
--- libsafe-2.0-16/src/intercept.c	2002-05-31 19:37:34.000000000 +0200
+++ libsafe-2.0-16-mrvn/src/intercept.c	2002-09-01 23:44:55.000000000 +0200
@@ -128,14 +128,29 @@
 }
 
 
-/* Starting with version 2.0, we keep a single global copy of the pointer to
- * the real memcpy() function.  This allows us to call
- * getLibraryFunction("memcpy") just once instead of multiple times, since
- * memcpy() is needed in four different functions below.
+/* Starting with Debian version 2.0-16-2, we keep a global copy of the pointer
+ * to each real functions.  Otherwise a getLibraryFunction might
+ * be triggered from inside dlsym() and cause memory corruption reulting in a
+ * segfault.
  */
-static memcpy_t real_memcpy = NULL;
-
-
+static memcpy_t      real_memcpy = NULL;
+static _IO_vfscanf_t real_IO_vfscanf = NULL;
+static vfprintf_t    real_vfprintf = NULL;
+static vsnprintf_t   real_vsnprintf = NULL;
+static vsprintf_t    real_vsprintf = NULL;
+static gets_t        real_gets = NULL;
+static getwd_t       real_getwd = NULL;
+static realpath_t    real_realpath = NULL;
+static stpcpy_t      real_stpcpy = NULL;
+static strcat_t      real_strcat = NULL;
+static strcpy_t      real_strcpy = NULL;
+static strncat_t     real_strncat = NULL;
+static strncpy_t     real_strncpy = NULL;
+static wcscpy_t      real_wcscpy = NULL;
+static wcpcpy_t      real_wcpcpy = NULL;
+#ifndef MISSING_WCSNLEN
+static wcscat_t      real_wcscat = NULL;
+#endif
 /*
  * -------------- system library implementations -------------------
  * Here is the story: if a C source file includes <string.h> and is
@@ -150,7 +165,6 @@
  */
 char *strcpy(char *dest, const char *src)
 {
-    static strcpy_t real_strcpy = NULL;
     size_t max_size, len;
 
     if (!real_memcpy)
@@ -182,7 +196,6 @@
 
 char *strncpy(char *dest, const char *src, size_t n)
 {
-    static strncpy_t real_strncpy = NULL;
     size_t max_size, len;
 
     if (!real_strncpy)
@@ -206,7 +219,6 @@
 
 char *stpcpy(char *dest, const char *src)
 {
-    static stpcpy_t real_stpcpy = NULL;
     size_t max_size, len;
 
     if (!real_memcpy)
@@ -239,7 +251,6 @@
 #ifndef MISSING_WCSNLEN
 wchar_t *wcscpy(wchar_t *dest, const wchar_t *src)
 {
-    static wcscpy_t real_wcscpy = NULL;
     size_t max_bytes, max_wchars, len;
 
     if (!real_wcscpy)
@@ -280,7 +291,6 @@
 
 wchar_t *wcpcpy(wchar_t *dest, const wchar_t *src)
 {
-    static wcpcpy_t real_wcpcpy = NULL;
     size_t max_bytes, max_wchars, len;
 
     if (!real_wcpcpy)
@@ -347,7 +357,6 @@
 
 char *strcat(char *dest, const char *src)
 {
-    static strcat_t real_strcat = NULL;
     size_t max_size;
     uint dest_len, src_len;
 
@@ -379,7 +388,6 @@
 
 char *strncat(char *dest, const char *src, size_t n)
 {
-    static strncat_t real_strncat = NULL;
     size_t max_size;
     uint dest_len, src_len;
 
@@ -408,7 +416,6 @@
 #ifndef MISSING_WCSNLEN
 wchar_t *wcscat(wchar_t *dest, const wchar_t *src)
 {
-    static wcscat_t real_wcscat = NULL;
     size_t max_bytes;
     uint dest_len, src_len;
 
@@ -861,7 +868,6 @@
  */
 int vfprintf(FILE *fp, const char *format, va_list ap)
 {
-    static vfprintf_t real_vfprintf = NULL;
     int res;
     char *p, *pnum;
     int c = -1;		/* Next var arg to be used */
@@ -1026,7 +1032,6 @@
  */
 int _IO_vfprintf(FILE *fp, const char *format, va_list ap)
 {
-    static vfprintf_t real_vfprintf = NULL;
     int res;
     char *p, *pnum;
     int c = -1;		/* Next var arg to be used */
@@ -1189,8 +1194,6 @@
 
 int sprintf(char *str, const char *format, ...)
 {
-    static vsprintf_t real_vsprintf = NULL;
-    static vsnprintf_t real_vsnprintf = NULL;
     size_t max_size;
     va_list ap;
     int res;
@@ -1239,7 +1242,6 @@
 
 int snprintf(char *str, size_t size, const char *format, ...)
 {
-    static vsnprintf_t real_vsnprintf = NULL;
     size_t max_size;
     va_list ap;
     int res;
@@ -1286,8 +1288,6 @@
 
 int vsprintf(char *str, const char *format, va_list ap)
 {
-    static vsprintf_t real_vsprintf = NULL;
-    static vsnprintf_t real_vsnprintf = NULL;
     size_t max_size;
     int res;
 
@@ -1325,7 +1325,6 @@
 
 int vsnprintf(char *str, size_t size, const char *format, va_list ap)
 {
-    static vsnprintf_t real_vsnprintf = NULL;
     size_t max_size;
     int res;
 
@@ -1361,7 +1360,6 @@
 
 char *getwd(char *buf)
 {
-    static getwd_t real_getwd = NULL;
     size_t max_size;
     char *res;
 
@@ -1386,7 +1384,6 @@
 
 char *gets(char *s)
 {
-    static gets_t real_gets = NULL;
     size_t max_size, len;
 
     if (!real_gets)
@@ -1412,7 +1409,6 @@
 
 char *realpath(char *path, char resolved_path[])
 {
-    static realpath_t real_realpath = NULL;
     size_t max_size, len;
     char *res;
     char buf[MAXPATHLEN + 1];
@@ -1445,7 +1441,6 @@
 
 int _IO_vfscanf (_IO_FILE *s, const char *format, _IO_va_list argptr, int *errp)
 {
-    static _IO_vfscanf_t real_IO_vfscanf = NULL;
     int res, save_count;
     caddr_t ra_array[MAXLEVELS], fp_array[MAXLEVELS];
 
@@ -1529,6 +1524,25 @@
 	
 	fclose(fp);
     }
+
+    real_memcpy = (memcpy_t) getLibraryFunction("memcpy");
+    real_IO_vfscanf = (_IO_vfscanf_t) getLibraryFunction("_IO_vfscanf");
+    real_vfprintf = (vfprintf_t) getLibraryFunction("vfprintf");
+    real_vsnprintf = (vsnprintf_t) getLibraryFunction("vsnprintf");
+    real_vsprintf = (vsprintf_t) getLibraryFunction("vsprintf");
+    real_gets = (gets_t) getLibraryFunction("gets");
+    real_getwd = (getwd_t) getLibraryFunction("getwd");
+    real_realpath = (realpath_t) getLibraryFunction("realpath");
+    real_stpcpy = (stpcpy_t) getLibraryFunction("stpcpy");
+    real_strcat = (strcat_t) getLibraryFunction("strcat");
+    real_strcpy = (strcpy_t) getLibraryFunction("strcpy");
+    real_strncat = (strncat_t) getLibraryFunction("strncat");
+    real_strncpy = (strncpy_t) getLibraryFunction("strncpy");
+    real_wcscpy = (wcscpy_t) getLibraryFunction("wcscpy");
+    real_wcpcpy = (wcpcpy_t) getLibraryFunction("wcpcpy");
+#ifndef MISSING_WCSNLEN
+    real_wcscat = (wcscat_t) getLibraryFunction("wcscat");
+#endif
 }
 
 
