diff options
author | Lauri Aarnio <Lauri.Aarnio@iki.fi> | 2008-09-15 23:21:00 +0300 |
---|---|---|
committer | Lauri Leukkunen <lle@rahina.org> | 2008-09-27 00:02:42 +0300 |
commit | c1bd7545ad08fe18eedb1dd4b9d57866e8e05058 (patch) | |
tree | 38b961d9e5ec5e325cbb8c92fcbe8de365540024 | |
parent | f0aa538c22327cb92ca58cce6148e8e0ec121541 (diff) |
Workaround for a Linux/glibc memory allocation problem - ld.so (ld-linux.so.2) fails to execute dynamically linked programs (segfaults!), when called explicitly and stack limit has been set to infinity. This can be demonstrated by "ulimit -s unlimited; /lib/ld-linux.so /bin/bash" on ubuntu "hardy". - GNU make triggers this problem; it sets stack limit to infinity.. - This patch provides a workaround by wrapping the "setrlimit" calls, recording stack limit, and restoring the limit before exec is called.
-rw-r--r-- | luaif/sb_log.c | 1 | ||||
-rw-r--r-- | preload/interface.master | 22 | ||||
-rw-r--r-- | preload/libsb2.c | 102 | ||||
-rw-r--r-- | preload/libsb2.h | 1 | ||||
-rw-r--r-- | utils/sb2-show.c | 1 |
5 files changed, 126 insertions, 1 deletions
diff --git a/luaif/sb_log.c b/luaif/sb_log.c index 47e902a..ae8d9b8 100644 --- a/luaif/sb_log.c +++ b/luaif/sb_log.c @@ -17,6 +17,7 @@ #include <sys/socket.h> #include <fcntl.h> #include <string.h> +#include <sys/resource.h> #include <sb2.h> #include <config.h> diff --git a/preload/interface.master b/preload/interface.master index 44fbf63..efe2119 100644 --- a/preload/interface.master +++ b/preload/interface.master @@ -450,3 +450,25 @@ WRAP: char *mktemp(char *template) : \ returns_string \ return(ret?template:NULL) +-- +-- 9. Other wrappers (not directly related to path or exec mapping) +-- ------------------------------------------------------------- +-- + +-- setrlimit() and setrlimit64(): +-- There is a bug in Linux/glibc's ld.so interaction: ld.so segfaults +-- when it tries to execute programs "manually" when stack limit +-- has been set to infinity. We need to observe setrlimit() and change +-- the stack limit back before exec... +-- +-- [someone who wrote the glibc versions of setrlimit() didn't care +-- about X/Open compatibility, first argument of setrmit() is not an "int" +-- even if X/Open standard defines so!] +#if defined __USE_GNU && !defined __cplusplus +#define SETRLIMIT_ARG1_TYPE __rlimit_resource_t +#else +#define SETRLIMIT_ARG1_TYPE int +#endif +GATE: int setrlimit(SETRLIMIT_ARG1_TYPE resource, const struct rlimit *rlp) +GATE: int setrlimit64(SETRLIMIT_ARG1_TYPE resource, const struct rlimit64 *rlp) + diff --git a/preload/libsb2.c b/preload/libsb2.c index 25a5933..bac62ea 100644 --- a/preload/libsb2.c +++ b/preload/libsb2.c @@ -99,6 +99,16 @@ static char *strvec_to_string(char *const *argv) return(buf); } +/* setrlimit() and setrlimit64(): + * There is a bug in Linux/glibc's ld.so interaction: ld.so segfaults + * when it tries to execute programs "manually" when stack limit + * has been set to infinity. We need to observe setrlimit() and change + * the stack limit back before exec... +*/ +static int restore_stack_before_exec = 0; /* 0, 1 or 64 */ +static struct rlimit stack_limits_for_exec; +static struct rlimit64 stack_limits64_for_exec; + static int (*next_execve) (const char *filename, char *const argv [], char *const envp[]) = NULL; @@ -116,8 +126,29 @@ int sb_next_execve(const char *file, char *const *argv, char *const *envp) free(buf); } else { SB_LOG(SB_LOGLEVEL_DEBUG, - "EXEC: %s (failed to printing argv)", file); + "EXEC: %s (failed to print argv)", file); + } + } + + switch (restore_stack_before_exec) { + case 1: + SB_LOG(SB_LOGLEVEL_DEBUG, "EXEC: need to restore stack limit"); + + if (setrlimit(RLIMIT_STACK, &stack_limits_for_exec) < 0) { + SB_LOG(SB_LOGLEVEL_ERROR, + "setrlimit(stack) failed, " + "failed to restore limits before exec"); } + break; + case 64: + SB_LOG(SB_LOGLEVEL_DEBUG, "EXEC: need to restore stack limit"); + + if (setrlimit64(RLIMIT_STACK, &stack_limits64_for_exec) < 0) { + SB_LOG(SB_LOGLEVEL_ERROR, + "setrlimit64(stack) failed, " + "failed to restore limits before exec"); + } + break; } return next_execve(file, argv, envp); @@ -973,3 +1004,72 @@ char *tempnam_gate( SB_LOG(SB_LOGLEVEL_DEBUG, "%s: mktemp() failed", realfnname); return(NULL); } + +/* SETRLIMIT_ARG1_TYPE is defined in interface.master */ + +int setrlimit_gate( + int (*real_setrlimit_ptr)(SETRLIMIT_ARG1_TYPE resource, + const struct rlimit *rlp), + const char *realfnname, + SETRLIMIT_ARG1_TYPE resource, + const struct rlimit *rlp) +{ + SB_LOG(SB_LOGLEVEL_DEBUG, "%s: res=%d cur=%ld max=%ld", + realfnname, resource, (long)rlp->rlim_cur, (long)rlp->rlim_max); + + if ((resource == RLIMIT_STACK) && (rlp->rlim_cur == RLIM_INFINITY)) { + struct rlimit limit_now; + + if (getrlimit(RLIMIT_STACK, &limit_now) < 0) { + SB_LOG(SB_LOGLEVEL_ERROR, + "%s: getrlimit(stack) failed", realfnname); + } else { + if (limit_now.rlim_cur != RLIM_INFINITY) { + /* stack limit was not "unlimited", but we + * are going to set it to unlimited. */ + stack_limits_for_exec = limit_now; + restore_stack_before_exec = 1; + + SB_LOG(SB_LOGLEVEL_NOTICE, + "%s: Setting stack limit to infinity, " + "old limit stored for next exec", + realfnname); + } + } + } + return((*real_setrlimit_ptr)(resource,rlp)); +} + +int setrlimit64_gate( + int (*real_setrlimit64_ptr)(SETRLIMIT_ARG1_TYPE resource, + const struct rlimit64 *rlp), + const char *realfnname, + SETRLIMIT_ARG1_TYPE resource, + const struct rlimit64 *rlp) +{ + SB_LOG(SB_LOGLEVEL_DEBUG, "%s: res=%d cur=%ld max=%ld", + realfnname, resource, (long)rlp->rlim_cur, (long)rlp->rlim_max); + + if ((resource == RLIMIT_STACK) && (rlp->rlim_cur == RLIM64_INFINITY)) { + struct rlimit64 limit_now; + + if (getrlimit64(RLIMIT_STACK, &limit_now) < 0) { + SB_LOG(SB_LOGLEVEL_ERROR, + "%s: getrlimit64(stack) failed", realfnname); + } else { + if (limit_now.rlim_cur != RLIM64_INFINITY) { + /* stack limit was not "unlimited", but we + * are going to set it to unlimited. */ + stack_limits64_for_exec = limit_now; + restore_stack_before_exec = 64; + + SB_LOG(SB_LOGLEVEL_NOTICE, + "%s: Setting stack limit to infinity, " + "old limit stored for next exec", + realfnname); + } + } + } + return((*real_setrlimit64_ptr)(resource,rlp)); +} + diff --git a/preload/libsb2.h b/preload/libsb2.h index 0584208..b6c6038 100644 --- a/preload/libsb2.h +++ b/preload/libsb2.h @@ -71,6 +71,7 @@ #include <sys/socket.h> #include <sys/un.h> +#include <sys/resource.h> #include <glob.h> diff --git a/utils/sb2-show.c b/utils/sb2-show.c index 0bf1dd7..cdb11c5 100644 --- a/utils/sb2-show.c +++ b/utils/sb2-show.c @@ -11,6 +11,7 @@ #include <config_hardcoded.h> #include <sys/types.h> #include <sys/socket.h> +#include <sys/resource.h> #include "exported.h" #include "sb2.h" |