Index: nkvd.c ================================================================== --- nkvd.c +++ nkvd.c @@ -6,10 +6,18 @@ * $ export LD_PRELOAD=nkvd.so * * ! NOTE: for unknown reasons, nkvd currently only works * when built without optimizations. it's probably that * wrecker Trotsky's fault. i'm working on it. + * - partial solution on GCC: using #pragma to disable + * optimization around the sensitive code. unclear if + * this bug affects other compilers. + * - bizarre complication: the bug can only be reproduced + * if the -O flag itself is present; turning on the + * same individual optimization flags that -O is + * supposed to represent does not trigger the problem. + * - conclusion: compiler devils. * * ! WARNING: test this program thoroughly before you start * exporting it from your shellrcs; if things get fucked, * you may not be able to execute any binaries with the * variable set, and will need to log in as root or boot @@ -104,11 +112,10 @@ * in nkvd_interdict_all=1 mode */ #include #include -#include #include #include #include #include #include @@ -121,17 +128,22 @@ /* glibc's basename() is imported from via * the following directive. i have no idea how this * magic works unless they're abusing asm declarations */ # define _GNU_SOURCE /* for basename() */ # define __USE_GNU /* for RTLD_NEXT */ -# define SYMSRC RTLD_NEXT +# ifdef _USE_RTLD_NEXT +# define SYMSRC RTLD_NEXT +# else +# define SYMSRC hnd +# endif #endif #include #include +#include #ifndef _LIBC -# define _LIBC "libc.so" +# define _LIBC "libc.so.6" #endif #ifndef _CONF_HOME # define _CONF_HOME ".config" #endif @@ -282,12 +294,15 @@ # ifdef _NO_GNU } # endif } -#define STAT_PARAMS const char* volatile path, struct stat* statbuf -#define XSTAT_PARAMS int ver, const char* volatile path, struct stat* statbuf +#pragma GCC push_options +#pragma GCC optimize ("O0") + +#define STAT_PARAMS const char* volatile path, struct stat* volatile statbuf +#define XSTAT_PARAMS int volatile ver, const char* volatile path, struct stat* volatile statbuf #define decl_stat_ptr(nm) static int (*libc_##nm) (STAT_PARAMS) #define decl_xstat_ptr(nm) static int (*libc_##nm) (XSTAT_PARAMS) static int (*libc_open) (const char*,int,...); static int (*libc_unlink)(const char*); @@ -302,11 +317,12 @@ decl_xstat_ptr(xstat64); decl_xstat_ptr(lxstat); decl_xstat_ptr(lxstat64); #endif -int nkvd_stat(int (*fn)(STAT_PARAMS), STAT_PARAMS) { +int nkvd_stat(int (*volatile fn)(STAT_PARAMS), STAT_PARAMS) { + printf(bold("nkvd") " stat: %p\n", fn); if (intercept) { size_t plen = strlen(path); char gulag[redir_len + plen]; if (interrogate(path, plen, gulag)) { return (*fn)(gulag,statbuf); @@ -313,11 +329,12 @@ } } return (*fn)(path,statbuf); } -int nkvd_xstat(int (*fn)(XSTAT_PARAMS), XSTAT_PARAMS) { +int nkvd_xstat(int (*volatile fn)(XSTAT_PARAMS), XSTAT_PARAMS) { + printf(bold("nkvd") " xstat: %p\n", fn); if (intercept) { size_t plen = strlen(path); char gulag[redir_len + plen]; if (interrogate(path, plen, gulag)) { return (*fn)(ver,gulag,statbuf); @@ -338,10 +355,12 @@ def_xstat_fn(__xstat,xstat); def_xstat_fn(__xstat64,xstat64); def_xstat_fn(__lxstat,lxstat); def_xstat_fn(__lxstat64,lxstat64); #endif + +#pragma GCC pop_options int unlink(const char* volatile path) { if (intercept) { size_t plen = strlen(path); char gulag[redir_len + plen]; @@ -371,19 +390,17 @@ int nkvd_init(int argc, const char** argv) { wiretap_argc = argc; wiretap_argv = argv; -# ifdef _NO_GNU - /* RTLD_NEXT is unfortunately a glibc extension, so in - * the _NO_GNU case we need to load open() via other - * means. */ +# ifndef _USE_RTLD_NEXT + /* RTLD_NEXT is buggy as hell so we avoid it by default */ void* SYMSRC = dlopen(_LIBC,RTLD_LAZY); if (SYMSRC == NULL) - fail(-2,"compiled in non-glibc mode and cannot load " + fail(-2,"compiled in non-RTLD_NEXT mode and cannot load " "libc from " bold(_LIBC) "; please recompile " - " and specify your libc with -D_LIBC= on the" + " and specify your libc with -D_LIBC= on the " "compile command line."); # endif # define load_fn(fn,pfx) libc_##fn = dlsym(SYMSRC, #pfx #fn) load_fn(open,); load_fn(unlink,);