summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLauri Aarnio <Lauri.Aarnio@iki.fi>2008-09-15 23:21:00 +0300
committerLauri Leukkunen <lle@rahina.org>2008-09-27 00:02:42 +0300
commitc1bd7545ad08fe18eedb1dd4b9d57866e8e05058 (patch)
tree38b961d9e5ec5e325cbb8c92fcbe8de365540024
parentf0aa538c22327cb92ca58cce6148e8e0ec121541 (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.c1
-rw-r--r--preload/interface.master22
-rw-r--r--preload/libsb2.c102
-rw-r--r--preload/libsb2.h1
-rw-r--r--utils/sb2-show.c1
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"