nixcloud / ip2unix

Turn IP sockets into Unix domain sockets
GNU Lesser General Public License v3.0
361 stars 10 forks source link

cannot dynamically load position-independent executable #9

Closed etam closed 4 years ago

etam commented 4 years ago

I'm using openSUSE Tumbleweed (rolling release distro). It currently has gcc 9.3.1 and glibc 2.31.

I successfully built ip2unix version 2.1.1, but I get this error, when trying to use it:

ERROR: ld.so: object '/home/etam/tmp/ip2unix-2.1.1/build/ip2unix' from LD_PRELOAD cannot be preloaded (cannot dynamically load position-independent executable): ignored.
aszlig commented 4 years ago

The reason is that since glibc 2.30, it's no longer possible to dlopen/LD_PRELOAD PIE objects.

So to fix this, we need to split up the LD_PRELOAD library and the main executable.

aszlig commented 4 years ago

Fixed in 8e10ef2d1d76ba8835735eaab167e77de34df88a.

etam commented 4 years ago

Thanks for working on this, but it's still not working:

$ ./ip2unix -r in,path=/tmp/test.socket env
ERROR: ld.so: object './ip2unix' from LD_PRELOAD cannot be preloaded (cannot dynamically load executable): ignored.
...
LD_PRELOAD=./ip2unix
__IP2UNIX_RULES=i!!!!/tmp/test.socket&f!f!ff
etam commented 4 years ago

~I think it's because dladdr is in ip2unix.cc, which is compiled in the main executable, not in shared library (like in the example on StackOverflow you referenced in commit message).~ Edit: Nope. I was wrong. __ip2unix__ function is in shared library, so it should work.

etam commented 4 years ago

Another idea:

$ python3 ./scripts/gensyms.py ./src/preload.cc
{
  global: "__ip2unix__)(void"; [...]
  local: *;
};

Edit: nope again. I did this simple workaround, to make regex match, but still I have no idea, why it's not working for me.

diff --git a/src/ip2unix.cc b/src/ip2unix.cc
index f8a0ac6..c319a38 100644
--- a/src/ip2unix.cc
+++ b/src/ip2unix.cc
@@ -13,7 +13,7 @@

 extern char **environ;

-extern "C" const char *__ip2unix__(void);
+extern "C" const char *__ip2unix__(int);

 static std::optional<std::string> get_preload_libpath(void)
 {
@@ -33,7 +33,7 @@ static bool run_preload(std::vector<Rule> &rules, char *argv[])
     char *buf, *preload;
     std::optional<std::string> libpath;

-    libversion = __ip2unix__();
+    libversion = __ip2unix__(0);

     if (!(libpath = get_preload_libpath())) {
         return false;
diff --git a/src/preload.cc b/src/preload.cc
index 4104953..8660bbe 100644
--- a/src/preload.cc
+++ b/src/preload.cc
@@ -68,7 +68,7 @@ static void init_rules(void)
     g_rules = std::make_shared<std::vector<Rule>>(rules.value());
 }

-extern "C" const char *WRAP_SYM(__ip2unix__)(void)
+extern "C" const char* WRAP_SYM(__ip2unix__)(int i)
 {
     return VERSION;
 }
etam commented 4 years ago

Got any idea why there are different addresses 0x4252e0 <__ip2unix__@plt> and 0x7ffff7f5ad2f <__ip2unix__(int)>?

$ gdb --args ./ip2unix -r in,path=/tmp/test.socket env
[...]
Reading symbols from ./ip2unix...
(gdb) b get_preload_libpath
Breakpoint 1 at 0x42b064: file ../src/ip2unix.cc, line 22.
(gdb) r
Starting program: /home/etam/tmp/ip2unix/build/ip2unix -r in,path=/tmp/test.socket env

Breakpoint 1, get_preload_libpath () at ../src/ip2unix.cc:22
22          if (dladdr(reinterpret_cast<void*>(__ip2unix__), &info) < 0) {
(gdb) n
27          return std::string(info.dli_fname);
(gdb) p info
$1 = {
    dli_fname = 0x7fffffffdf97 "/home/etam/tmp/ip2unix/build/ip2unix",
    dli_fbase = 0x400000,
    dli_sname = 0x418878 "__ip2unix__",
    dli_saddr = 0x4252e0 <__ip2unix__@plt>
}
(gdb) p __ip2unix__
$2 = {const char *(int)} 0x7ffff7f5ad2f <__ip2unix__(int)>
etam commented 4 years ago

I got it! Here's the problem: https://stackoverflow.com/questions/5469274/what-does-plt-mean-here Here's the solution: use meson -Db_pie=true build