don't call INIT() from close hook

it was observed that it is a bad idea to initialize the entire
infrastructure used by proxychains from the close hook,
because the following scenario will lead to a deadlock:

- it is possible that the dynlinker executes the initializer code of
  other shared libs first
- if that code directly or indirectly calls malloc()
- which calls close() if it decided to use an mmap based allocation
- will now call our close(), which does
- call pthread_once which requires a lock
- creates a thread which calls malloc()
- which in turn calls our close() another time
- and our close is still in locked state.

so it seems the only save thing to do is to just get the address
of the original close function, and call that when we're in a
pre-init state.
this may hold for other functions that do lazy initialization as well,
however for those just calling the original function is probably
undesired since that could result in unproxified connections.
it will be needed to analyze on a per-function basis what the best
thing to do is, and finally rely only on the execution of the init
function from the gcc initializer.

should fix #119
This commit is contained in:
rofl0r 2016-05-26 10:48:32 +01:00
parent aea9172653
commit 8870140ff0

View File

@ -93,7 +93,7 @@ static void* load_sym(char* symname, void* proxyfunc) {
#define INIT() init_lib_wrapper(__FUNCTION__) #define INIT() init_lib_wrapper(__FUNCTION__)
#define SETUP_SYM(X) do { true_ ## X = load_sym( # X, X ); } while(0) #define SETUP_SYM(X) do { if (! true_ ## X ) true_ ## X = load_sym( # X, X ); } while(0)
#include "allocator_thread.h" #include "allocator_thread.h"
@ -304,7 +304,10 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
/******* HOOK FUNCTIONS *******/ /******* HOOK FUNCTIONS *******/
int close(int fd) { int close(int fd) {
INIT(); if(!init_l) {
SETUP_SYM(close);
return true_close(fd);
}
/* prevent rude programs (like ssh) from closing our pipes */ /* prevent rude programs (like ssh) from closing our pipes */
if(fd != req_pipefd[0] && fd != req_pipefd[1] && if(fd != req_pipefd[0] && fd != req_pipefd[1] &&
fd != resp_pipefd[0] && fd != resp_pipefd[1]) { fd != resp_pipefd[0] && fd != resp_pipefd[1]) {