libhugetlbfs redefines shmget() so that it can transparently optionally
add the hugepage flag.  Unfortunately, it uses dlsym() to to find the
next shmget() to call in the dynamic library call chain.  This does not
work on statically-linked executables.  Even if the executable is linked
against -ldl, dlsym() in a statically-linked executable does not return
a reference to the glibc shmget() library routine.

Work around this by making all references to libdl weak, and testing
for its presence.  If libdl symbols are not not present, assume static
linking, and directly make the shmget syscall.

Making the dl* symbols weak does not affect dynamic executables as
libdl.so is:
* Automatically added to the library dependency list when liked with
  -lhugetlbfs
* Mapped into the programs address space when used with LD_PRELOAD.

Based on a patch originally authored by Dean Luick <lu...@cray.com>.

Signed-off-by: Andrew Hastings <a...@cray.com> on behalf of Cray Inc.
---
Changes from V1:
- Add code to support platforms such as ia32 that use the SYS_ipc
  syscall instead of SYS_shmget.
Tested on x86_64 (32- and 64-bit) and ia32.

Changes from V2:
- Add to the libhugetlbfs test Makefile support for static linking.
- Build a static version of the shmoverride_linked test.
- Correct runtests.py to run all cases of shmoverride:  with and without
  LD_PRELOAD, with and without HUGETLB_SHM, with and without prelinking.

-Andrew Hastings
 Cray Inc.

 shm.c              |   71 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 tests/Makefile     |   33 +++++++++++++++++++++++-
 tests/run_tests.py |    4 ++
 3 files changed, 103 insertions(+), 5 deletions(-)

diff -ruNp libhugetlbfs-2.11/shm.c libhugetlbfs-2.11-shm/shm.c
--- libhugetlbfs-2.11/shm.c     2010-12-16 11:38:22.000000000 -0600
+++ libhugetlbfs-2.11-shm/shm.c 2011-01-05 15:53:54.000000000 -0600
@@ -28,6 +28,61 @@
 #include <sys/types.h>
 #include "libhugetlbfs_internal.h"
 #include "hugetlbfs.h"
+#include <sys/syscall.h>
+
+#if defined(SYS_shmget) || defined(SYS_ipc)
+#define HAVE_SHMGET_SYSCALL
+#endif
+
+#ifdef HAVE_SHMGET_SYSCALL
+/*
+ * The calls to dlsym() and dlerror() in the shmget() wrapper below force
+ * a dependency on libdl.so.  This does not work for static executables
+ * as the glibc dynamic library implementation does not automatically
+ * have static dl* function stubs linked into static executables.
+ *
+ * Work around this problem by adding a weak attribute to the declarations
+ * of dlsym() and dlerror().  (The declaration is otherwise the same as in
+ * <dlfcn.h>).  This allows a static executable to be linked without -ldl.
+ * If &dlsym is NULL then this is a static executable and a call to the
+ * system shmget() may be performed without worry as there is no dynamic
+ * call chain.
+ */
+extern void *dlsym (void *__restrict __handle, __const char *__restrict __name)
+               __attribute__((weak)) __THROW __nonnull ((2));
+extern char *dlerror (void) __attribute__((weak)) __THROW;
+
+
+/* call syscall shmget through the generic syscall mechanism */
+static int syscall_shmget(key_t key, size_t size, int shmflg)
+{
+#ifdef SYS_shmget
+       return syscall(SYS_shmget, key, size, shmflg);
+#else
+       /*
+        * Some platforms do not have have a direct shmget syscall.  Instead,
+        * all SysV IPC calls are funneled through the ipc() system call.
+        *
+        * ipc() is expected to only be used by libc implementors, so using
+        * it has not been smoothed out.  There is no function declaration.
+        * The needed define for SHMGET is in linux/ipc.h, but that file
+        * also includes a conflicting definition of ipc_perm.  So,
+        * just define the needed items here.
+        *
+        * When compiling -m32 on x86_64, the ipc glibc wrapper does not
+        * exist.  Instead, just use SYS_ipc.
+        *
+        * The ipc system call below does not set the IPC_64 version flag
+        * with SHMGET because that would have required more private defines
+        * and the version number is not used for the SHMGET call.
+        */
+       #define SHMGET 23
+
+       return syscall(SYS_ipc, SHMGET, key, size, shmflg, (void *)NULL, 0L);
+#endif
+}
+
+#endif /* HAVE_SHMGET_SYSCALL */
 
 int shmget(key_t key, size_t size, int shmflg)
 {
@@ -40,10 +95,18 @@ int shmget(key_t key, size_t size, int s
 
        /* Get a handle to the "real" shmget system call */
        if (!real_shmget) {
-               real_shmget = dlsym(RTLD_NEXT, "shmget");
-               if ((error = dlerror()) != NULL) {
-                       ERROR("%s", error);
-                       return -1;
+#ifdef HAVE_SHMGET_SYSCALL
+               if (&dlsym == NULL) {
+                       /* in a static executable, call shmget directly */
+                       real_shmget = syscall_shmget;
+               } else
+#endif /* HAVE_SHMGET_SYSCALL */
+               {
+                       real_shmget = dlsym(RTLD_NEXT, "shmget");
+                       if ((error = dlerror()) != NULL) {
+                               ERROR("%s", error);
+                               return -1;
+                       }
                }
        }
 
diff -ruNp libhugetlbfs-2.11/tests/Makefile libhugetlbfs-2.11-shm/tests/Makefile
--- libhugetlbfs-2.11/tests/Makefile    2010-12-16 11:38:22.000000000 -0600
+++ libhugetlbfs-2.11-shm/tests/Makefile        2011-01-14 14:38:58.357087000 
-0600
@@ -27,7 +27,9 @@ BADTOOLCHAIN = bad-toolchain.sh
 
 CFLAGS = -O2 -Wall -g
 CPPFLAGS = -I..
-LDLIBS = -Wl,--no-as-needed -ldl -lpthread -lhugetlbfs_privutils
+STATIC_LIBHUGE = -Wl,--whole-archive -lhugetlbfs -Wl,--no-whole-archive
+STATIC_LDLIBS = -Wl,--no-as-needed -lpthread
+LDLIBS = $(STATIC_LDLIBS) -ldl -lhugetlbfs_privutils
 LDFLAGS32 = -L../obj32
 LDFLAGS64 = -L../obj64
 INSTALL = install
@@ -71,6 +73,19 @@ ifdef CC64
 ALLTESTS += $(TESTS_64:%=obj64/%)
 endif
 
+# For now, build only one test as a static binary.
+# Can be changed once libhugetlbfs has better support for static linking.
+# Also, some tests should be changed to use syscall() instead of
+#  dlsym() / rtld_next().
+ifdef CC32
+#ALLTESTS += $(LIB_TESTS:%=obj32/%_static) $(STRESS_TESTS:%=obj32/%_static)
+ALLTESTS += obj32/shmoverride_linked_static
+endif
+ifdef CC64
+#ALLTESTS += $(LIB_TESTS:%=obj64/%_static) $(STRESS_TESTS:%=obj64/%_static)
+ALLTESTS += obj64/shmoverride_linked_static
+endif
+
 objs_needing_wrappers = \
        $(foreach W,$(WRAPPERS:%.sh=%),$(filter $(1)/$(W),$(ALLTESTS)))
 WRAPPERS32 = $(addsuffix .sh,$(call objs_needing_wrappers,obj32))
@@ -120,6 +135,14 @@ $(LIB_TESTS:%=obj64/%) $(LIB_TESTS_64:%=
        @$(VECHO) LD64 "(lib test)" $@
        $(CC64) $(LDFLAGS) $(LDFLAGS64) -o $@ $^ $(LDLIBS) -lhugetlbfs
 
+$(LIB_TESTS:%=obj32/%_static): %_static: %.o obj32/testutils.o 
obj32/libtestutils.o
+       @$(VECHO) LD32 "(lib test)" $@
+       $(CC32) -static $(LDFLAGS) $(LDFLAGS32) -o $@ $^ $(STATIC_LDLIBS) 
$(STATIC_LIBHUGE)
+
+$(LIB_TESTS:%=obj64/%_static) $(LIB_TESTS_64:%=obj64/%_static): %_static: %.o 
obj64/testutils.o obj64/libtestutils.o
+       @$(VECHO) LD64 "(lib test)" $@
+       $(CC64) -static $(LDFLAGS) $(LDFLAGS64) -o $@ $^ $(STATIC_LDLIBS) 
$(STATIC_LIBHUGE)
+
 $(NOLIB_TESTS:%=obj32/%): %: %.o obj32/testutils.o
        @$(VECHO) LD32 "(nolib test)" $@
        $(CC32) $(LDFLAGS) $(LDFLAGS32) -o $@ $^ $(LDLIBS)
@@ -172,6 +195,14 @@ $(STRESS_TESTS:%=obj64/%): %: %.o obj64/
        @$(VECHO) LD64 "(lib test)" $@
        $(CC64) $(LDFLAGS) $(LDFLAGS64) -o $@ $^ $(LDLIBS) -lhugetlbfs
 
+$(STRESS_TESTS:%=obj32/%_static): %_static: %.o obj32/testutils.o
+       @$(VECHO) LD32 "(lib test)" $@
+       $(CC32) -static $(LDFLAGS) $(LDFLAGS32) -o $@ $^ $(STATIC_LDLIBS) 
$(STATIC_LIBHUGE)
+
+$(STRESS_TESTS:%=obj64/%_static): %_static: %.o obj64/testutils.o
+       @$(VECHO) LD64 "(lib test)" $@
+       $(CC64) -static $(LDFLAGS) $(LDFLAGS64) -o $@ $^ $(STATIC_LDLIBS) 
$(STATIC_LIBHUGE)
+
 obj32/xB.%: $(SCRIPTS32).xB $(HUGETLBFS_LD) obj32/%.o obj32/testutils.o
        @$(VECHO) LD32 "(xB test)" $@
        @mkdir -p obj32
diff -ruNp libhugetlbfs-2.11/tests/run_tests.py 
libhugetlbfs-2.11-shm/tests/run_tests.py
--- libhugetlbfs-2.11/tests/run_tests.py        2010-12-16 11:38:22.000000000 
-0600
+++ libhugetlbfs-2.11-shm/tests/run_tests.py    2011-01-14 14:40:13.263279000 
-0600
@@ -597,7 +597,11 @@ def functional_tests():
 
     # Test overriding of shmget()
     do_shm_test("shmoverride_linked")
+    do_shm_test("shmoverride_linked", HUGETLB_SHM="yes")
+    do_shm_test("shmoverride_linked_static")
+    do_shm_test("shmoverride_linked_static", HUGETLB_SHM="yes")
     do_shm_test("shmoverride_unlinked", LD_PRELOAD="libhugetlbfs.so")
+    do_shm_test("shmoverride_unlinked", LD_PRELOAD="libhugetlbfs.so", 
HUGETLB_SHM="yes")
 
     # Test hugetlbfs filesystem quota accounting
     do_test("quota.sh")

------------------------------------------------------------------------------
Protect Your Site and Customers from Malware Attacks
Learn about various malware tactics and how to avoid them. Understand 
malware threats, the impact they can have on your business, and how you 
can protect your company and customers by using code signing.
http://p.sf.net/sfu/oracle-sfdevnl
_______________________________________________
Libhugetlbfs-devel mailing list
Libhugetlbfs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libhugetlbfs-devel

Reply via email to