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