Package: gcl
Version: 2.6.7-36.1
Followup-For: Bug #487435

The attached patch fixes gcl's personality(ADDR_NO_RANDOMIZE)
code. (BTW, this randomization seems to have become enabled by default
Debian's 2.6.25 amd64 kernels).

- gcl tries to figure out at build time whether the randomized sbrk
  work-around is needed. But such things should be either checked at
  run-time or applied unconditionally. (The buildd could still be
  running an old kernel, or the user might have a paranoid setup, etc.)
  So I patched the configure.in script. The new logic is:

   - check if ADDR_NO_RANDOMIZE is defined in the system headers. If
     not, define it ourselves. [This was the cause of this FTBS, gcl
     #defined it unconditionally, while glibc now has it as an enum
     value.]

   - check if personality(ADDR_NO_RANDOMIZE) compiles and is accepted
     by the kernel.

   - if it works, use it unconditionally.

   - if it does not work, check if address randomization is in
     effect. Refuse to build if it is.

  Currently, debian/rules does not try to regenerate configure,
  referering the some bug with autoconf and emacsen-common. I'll leave
  that part to you :)

- I replaced the code in o/main.c with the equivalent code from sbcl,
  which seems more robust (it protects against an infinite loop on
  broken kernels, and doesn't rely on the value of argv[0]).

  (Also, both the configure script and main.c tried to use
  personality(-1) to get the current personality. This fails on 64-bit
  systems, the correct call is personality(0xffffffffUL)).

- When compiling with profiling, I added a call to gprof_cleanup()
  before exec'ing, otherwise the build would fail with SIGPROF.

All programs requiring gcl should probably be rebuild when this is
fixed.


-- System Information:
Debian Release: lenny/sid
  APT prefers unstable
  APT policy: (500, 'unstable'), (1, 'experimental')
Architecture: amd64 (x86_64)

Kernel: Linux 2.6.25-2-amd64 (SMP w/1 CPU core)
Locale: LANG=nl_BE.UTF-8, LC_CTYPE=nl_BE.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages gcl depends on:
ii  debconf                   1.5.22         Debian configuration management sy
ii  emacs [emacsen]           22.2+2-2       The GNU Emacs editor (metapackage)
ii  emacs22-gtk [emacsen]     22.2+2-2       The GNU Emacs editor (with GTK use
ii  gcc                       4:4.3.1-2      The GNU C compiler
ii  libc6                     2.7-12         GNU C Library: Shared libraries
ii  libgmp3c2                 2:4.2.2+dfsg-3 Multiprecision arithmetic library
ii  libice6                   2:1.0.4-1      X11 Inter-Client Exchange library
ii  libncurses5               5.6+20080713-1 shared libraries for terminal hand
ii  libreadline5              5.2-3          GNU readline and history libraries
ii  libsm6                    2:1.0.3-2      X11 Session Management library
ii  libx11-6                  2:1.1.4-2      X11 client-side library
ii  libxaw7                   2:1.0.4-2      X11 Athena Widget library
ii  libxext6                  2:1.0.4-1      X11 miscellaneous extension librar
ii  libxmu6                   2:1.0.4-1      X11 miscellaneous utility library
ii  libxt6                    1:1.0.5-3      X11 toolkit intrinsics library
ii  tcl8.4                    8.4.19-2       Tcl (the Tool Command Language) v8
ii  tk8.4                     8.4.19-2       Tk toolkit for Tcl and X11, v8.4 -

gcl recommends no packages.

Versions of packages gcl suggests:
pn  gcl-doc                       <none>     (no description available)

-- debconf information:
  gcl/default_gcl_ansi:
  gcl/default_gcl_prof:
--- a/configure.in
+++ b/configure.in
@@ -1000,78 +1000,51 @@
 		AC_MSG_RESULT([no: WARNING you must be able to emulate sbrk: as on mingw or macosx]))
 
 if test "$HAVE_SBRK" = "1" ; then
-	AC_MSG_CHECKING([for randomized sbrk])
-	AC_TRY_RUN([#include <unistd.h>
-		    #include <stdio.h>
-		    int main() {
+	AC_CHECK_HEADER(sys/personality.h, true,
+		   AC_MSG_ERROR(sys/personality.h not found))
+
+	AC_MSG_CHECKING([for ADDR_NO_RANDOMIZE constant])
+	AC_TRY_RUN([#include <sys/personality.h>
+         	    #include <stdio.h>
+		    int main(int argc,char *argv[],char *envp[]) {
 			FILE *f;
 			if (!(f=fopen("conftest1","w")))
 				return -1;
-			fprintf(f,"%u",sbrk(0));
+			fprintf(f,"%x",ADDR_NO_RANDOMIZE);
 			return 0;
 			}],
-			SBRK=`cat conftest1`,SBRK=0,SBRK=0)
-	if test "$SBRK" = "0" ; then
-		AC_MSG_RESULT(cannot trap sbrk)
-		exit 1
+			ADDR_NO_RANDOMIZE=`cat conftest1`,ADDR_NO_RANDOMIZE=0,ADDR_NO_RANDOMIZE=0)
+	if test "$ADDR_NO_RANDOMIZE" = "0" ; then
+		AC_MSG_RESULT([no, assuming 0x40000])
+		AC_DEFINE_UNQUOTED(ADDR_NO_RANDOMIZE,0x40000)
+	else
+		AC_MSG_RESULT([yes])
 	fi
-	AC_TRY_RUN([#include <unistd.h>
+
+	AC_MSG_CHECKING([for personality(ADDR_NO_RANDOMIZE) support])
+	AC_TRY_RUN([#include <sys/personality.h>
 		    #include <stdio.h>
-		    int main() {
+		    int main(int argc,char *argv[]) {
 			FILE *f;
 			if (!(f=fopen("conftest1","w")))
 				return -1;
-			fprintf(f,"%u",sbrk(0));
+			long retval = personality(ADDR_NO_RANDOMIZE);
+			long newpers = personality(0xffffffffUL);
+			fprintf(f,"%d",retval != -1 && newpers & ADDR_NO_RANDOMIZE);
 			return 0;
 			}],
-			SBRK1=`cat conftest1`,SBRK1=0,SBRK1=0)
-	if test "$SBRK1" = "0" ; then
-		AC_MSG_RESULT(cannot trap sbrk)
-		exit 1
-	fi
-	
-	if test "$SBRK" != "$SBRK1" ; then
+			NEED_NONRANDOM_SBRK=`cat conftest1`,NEED_NONRANDOM_SBRK=0,NEED_NONRANDOM_SBRK=0)
+
+	if test "$NEED_NONRANDOM_SBRK" = 1 ; then
 		AC_MSG_RESULT(yes)
-#		AC_CHECK_HEADER(linux/personality.h, true,
-#			   AC_MSG_ERROR(linux/personality.h not found))
-#		AC_TRY_RUN([#include <syscall.h>
-#			    #include <linux/personality.h>
-#	         	    #include <stdio.h>
-#			    #include <unistd.h>
-#			    int main(int argc,char *argv[],char *envp[]) {
-#				FILE *f;
-#				if (!(f=fopen("conftest1","w")))
-#					return -1;
-#				fprintf(f,"%x",ADDR_NO_RANDOMIZE);
-#				return 0;
-#				}],
-#				ADDR_NO_RANDOMIZE=`cat conftest1`,ADDR_NO_RANDOMIZE=0,ADDR_NO_RANDOMIZE=0)
-#		if test "$ADDR_NO_RANDOMIZE" = "0" ; then
-#			AC_MSG_RESULT(cannot get ADDR_NO_RANDOMIZE constant)
-#			exit 1
-#		fi
-#		AC_DEFINE_UNQUOTED(ADDR_NO_RANDOMIZE,$ADDR_NO_RANGOMIZE)
-#
-# Many boxes do not have the definition yet
-#
-		ADDR_NO_RANDOMIZE=0x40000
-		AC_DEFINE_UNQUOTED(ADDR_NO_RANDOMIZE,$ADDR_NO_RANDOMIZE)
-		AC_MSG_CHECKING([for ADDR_NO_RANOMIZE constant])
-		AC_MSG_RESULT($ADDR_NO_RANDOMIZE)
-		AC_CHECK_HEADER(sys/personality.h, true,
-			   AC_MSG_ERROR(sys/personality.h not found))
-		AC_TRY_RUN([#include <syscall.h>
-			    #include <sys/personality.h>
-	         	    #include <stdio.h>
-			    #include <unistd.h>
-			    int main(int argc,char *argv[],char *envp[]) {
+		AC_DEFINE(NEED_NONRANDOM_SBRK)
+	else
+		AC_MSG_RESULT(no)
+		AC_MSG_CHECKING([for randomized sbrk])
+		AC_TRY_RUN([#include <unistd.h>
+			    #include <stdio.h>
+			    int main() {
 				FILE *f;
-				long pers;
-				pers=personality(-1);
-				if (!(pers & ADDR_NO_RANDOMIZE)) {
-				   personality(pers | ADDR_NO_RANDOMIZE);
-				   execve(*argv,argv,envp);
-                                }
 				if (!(f=fopen("conftest1","w")))
 					return -1;
 				fprintf(f,"%u",sbrk(0));
@@ -1082,18 +1055,10 @@
 			AC_MSG_RESULT(cannot trap sbrk)
 			exit 1
 		fi
-		AC_TRY_RUN([#include <syscall.h>
-			    #include <sys/personality.h>
+		AC_TRY_RUN([#include <unistd.h>
 			    #include <stdio.h>
-			    #include <unistd.h>
-			    int main(int argc,char * argv[],char *envp[]) {
+			    int main() {
 				FILE *f;
-				long pers;
-				pers=personality(-1);
-				if (!(pers & ADDR_NO_RANDOMIZE)) {
-				   personality(pers | ADDR_NO_RANDOMIZE);
-				   execve(*argv,argv,envp);
-                                }
 				if (!(f=fopen("conftest1","w")))
 					return -1;
 				fprintf(f,"%u",sbrk(0));
@@ -1104,17 +1069,16 @@
 			AC_MSG_RESULT(cannot trap sbrk)
 			exit 1
 		fi
-		AC_MSG_CHECKING([for randomized brk remedy])
 		if test "$SBRK" = "$SBRK1" ; then
-			AC_MSG_RESULT(yes)
-			AC_DEFINE(NEED_NONRANDOM_SBRK)
-		else
 			AC_MSG_RESULT(no)
-			echo "Cannot build with randomized sbrk"
+		else
+			AC_MSG_RESULT(yes)
+			echo "Cannot build with randomized sbrk. Your options:"
+			echo " - upgrade to a kernel/libc that knows about personality(ADDR_NO_RANDOMIZE)"
+			echo " - recompile your kernel with CONFIG_COMPAT_BRK (if it has that option)"
+			echo " - run sysctl kernel.randomize_va_space=0 before using gcl"
 			exit 1
-		fi 
-	else
-		AC_MSG_RESULT(no)
+		fi
 	fi
 fi
 
@@ -1150,7 +1114,7 @@
   FILE *fp;
 
 #ifdef NEED_NONRANDOM_SBRK
-  pers=personality(-1);
+  pers=personality(0xffffffffUL);
   if (!(pers & ADDR_NO_RANDOMIZE)) {
    personality(pers | ADDR_NO_RANDOMIZE);
    execve(*argv,argv,envp);
--- a/o/main.c
+++ b/o/main.c
@@ -133,12 +133,43 @@
 
 #ifdef NEED_NONRANDOM_SBRK
 	{
-	  long pers;
-	  pers=personality(-1);
-	  if (!(pers & ADDR_NO_RANDOMIZE)) {
-	    personality(pers | ADDR_NO_RANDOMIZE);
-	    execve(*argv,argv,envp);
-	  }	
+          /* adapted from SBCL */
+          int pers = personality(0xffffffffUL);
+          /* 0x40000 aka. ADDR_NO_RANDOMIZE */
+          if (!(pers & 0x40000)) {
+            int retval = personality(pers | 0x40000);
+            /* Allegedly some Linux kernels (the reported case was
+             * "hardened Linux 2.6.7") won't set the new personality,
+             * but nor will they return -1 for an error. So as a
+             * workaround query the new personality...
+             */
+            int newpers = personality(0xffffffffUL);
+            /* ... and don't re-execute if either the setting resulted
+             * in an error or if the value didn't change. Otherwise
+             * this might result in an infinite loop.
+             */
+            if (retval != -1 && newpers != pers) {
+              /* Use /proc/self/exe instead of trying to figure out
+               * the executable path from PATH and argv[0], since
+               * that's unreliable. We follow the symlink instead of
+               * executing the file directly in order to prevent top
+               * from displaying the name of the process as "exe". */
+              char runtime[PATH_MAX+1];
+              int i = readlink("/proc/self/exe", runtime, PATH_MAX);
+              if (i != -1) {
+                runtime[i] = '\0';
+#ifdef GCL_GPROF
+                gprof_cleanup();
+#endif
+                execve(runtime, argv, envp);
+              }
+            }
+            /* Either changing the personality or execve() failed. Either
+             * way we might as well continue, and hope that the random
+             * memory maps are ok this time around.
+             */
+            fprintf(stderr, "WARNING: Couldn't re-execute with the proper personality flags (maybe /proc isn't mounted?). Trying to continue anyway.\n");
+          }
 	}
 #endif
 

Reply via email to