Differences From
Artifact [1b97491783]:
4 4 * $ cc -fPIC -pie nkvd.c -Wl,-E -onkvd -ldl
5 5 * [-D_NO_GNU [-D_LIBC=…]] [-D_CONF_HOME=…]
6 6 * $ export LD_PRELOAD=nkvd.so <dissident>
7 7 *
8 8 * ! NOTE: for unknown reasons, nkvd currently only works
9 9 * when built without optimizations. it's probably that
10 10 * wrecker Trotsky's fault. i'm working on it.
11 + * - partial solution on GCC: using #pragma to disable
12 + * optimization around the sensitive code. unclear if
13 + * this bug affects other compilers.
14 + * - bizarre complication: the bug can only be reproduced
15 + * if the -O flag itself is present; turning on the
16 + * same individual optimization flags that -O<x> is
17 + * supposed to represent does not trigger the problem.
18 + * - conclusion: compiler devils.
11 19 *
12 20 * ! WARNING: test this program thoroughly before you start
13 21 * exporting it from your shellrcs; if things get fucked,
14 22 * you may not be able to execute any binaries with the
15 23 * variable set, and will need to log in as root or boot
16 24 * off a rescue disk to fix the problem. LD_PRELOAD is
17 25 * not a toy. you have been warned.
................................................................................
102 110 *
103 111 * TODO: exempt xdg dirs beginning with ~/. from proscription
104 112 * in nkvd_interdict_all=1 mode
105 113 */
106 114
107 115 #include <stdarg.h>
108 116 #include <unistd.h>
109 -#include <sys/stat.h>
110 117 #include <sys/types.h>
111 118 #include <fcntl.h>
112 119 #include <limits.h>
113 120 #include <stdlib.h>
114 121 #include <pwd.h>
115 122 #ifdef _NO_GNU
116 123 /* the POSIX version of basename is a goddamn mess and
................................................................................
119 126 # define SYMSRC hnd
120 127 #else
121 128 /* glibc's basename() is imported from <string.h> via
122 129 * the following directive. i have no idea how this
123 130 * magic works unless they're abusing asm declarations */
124 131 # define _GNU_SOURCE /* for basename() */
125 132 # define __USE_GNU /* for RTLD_NEXT */
126 -# define SYMSRC RTLD_NEXT
133 +# ifdef _USE_RTLD_NEXT
134 +# define SYMSRC RTLD_NEXT
135 +# else
136 +# define SYMSRC hnd
137 +# endif
127 138 #endif
128 139 #include <string.h>
129 140 #include <dlfcn.h>
141 +#include <stdio.h>
130 142
131 143 #ifndef _LIBC
132 -# define _LIBC "libc.so"
144 +# define _LIBC "libc.so.6"
133 145 #endif
134 146
135 147 #ifndef _CONF_HOME
136 148 # define _CONF_HOME ".config"
137 149 #endif
138 150
139 151
................................................................................
280 292 # endif
281 293 return (mode == whitelist);
282 294 # ifdef _NO_GNU
283 295 }
284 296 # endif
285 297 }
286 298
287 -#define STAT_PARAMS const char* volatile path, struct stat* statbuf
288 -#define XSTAT_PARAMS int ver, const char* volatile path, struct stat* statbuf
299 +#pragma GCC push_options
300 +#pragma GCC optimize ("O0")
301 +
302 +#define STAT_PARAMS const char* volatile path, struct stat* volatile statbuf
303 +#define XSTAT_PARAMS int volatile ver, const char* volatile path, struct stat* volatile statbuf
289 304 #define decl_stat_ptr(nm) static int (*libc_##nm) (STAT_PARAMS)
290 305 #define decl_xstat_ptr(nm) static int (*libc_##nm) (XSTAT_PARAMS)
291 306
292 307 static int (*libc_open) (const char*,int,...);
293 308 static int (*libc_unlink)(const char*);
294 309
295 310 decl_stat_ptr(stat);
................................................................................
300 315 #ifndef _NO_GNU
301 316 decl_xstat_ptr(xstat);
302 317 decl_xstat_ptr(xstat64);
303 318 decl_xstat_ptr(lxstat);
304 319 decl_xstat_ptr(lxstat64);
305 320 #endif
306 321
307 -int nkvd_stat(int (*fn)(STAT_PARAMS), STAT_PARAMS) {
322 +int nkvd_stat(int (*volatile fn)(STAT_PARAMS), STAT_PARAMS) {
323 + printf(bold("nkvd") " stat: %p\n", fn);
308 324 if (intercept) {
309 325 size_t plen = strlen(path);
310 326 char gulag[redir_len + plen];
311 327 if (interrogate(path, plen, gulag)) {
312 328 return (*fn)(gulag,statbuf);
313 329 }
314 330 }
315 331 return (*fn)(path,statbuf);
316 332 }
317 333
318 -int nkvd_xstat(int (*fn)(XSTAT_PARAMS), XSTAT_PARAMS) {
334 +int nkvd_xstat(int (*volatile fn)(XSTAT_PARAMS), XSTAT_PARAMS) {
335 + printf(bold("nkvd") " xstat: %p\n", fn);
319 336 if (intercept) {
320 337 size_t plen = strlen(path);
321 338 char gulag[redir_len + plen];
322 339 if (interrogate(path, plen, gulag)) {
323 340 return (*fn)(ver,gulag,statbuf);
324 341 }
325 342 }
................................................................................
336 353
337 354 #ifndef _NO_GNU
338 355 def_xstat_fn(__xstat,xstat);
339 356 def_xstat_fn(__xstat64,xstat64);
340 357 def_xstat_fn(__lxstat,lxstat);
341 358 def_xstat_fn(__lxstat64,lxstat64);
342 359 #endif
360 +
361 +#pragma GCC pop_options
343 362
344 363 int unlink(const char* volatile path) {
345 364 if (intercept) {
346 365 size_t plen = strlen(path);
347 366 char gulag[redir_len + plen];
348 367 if (interrogate(path, plen, gulag)) {
349 368 return (*libc_unlink)(gulag);
................................................................................
369 388 return (*libc_open)(path, flags, m);
370 389 }
371 390
372 391 int nkvd_init(int argc, const char** argv) {
373 392 wiretap_argc = argc;
374 393 wiretap_argv = argv;
375 394
376 -# ifdef _NO_GNU
377 - /* RTLD_NEXT is unfortunately a glibc extension, so in
378 - * the _NO_GNU case we need to load open() via other
379 - * means. */
395 +# ifndef _USE_RTLD_NEXT
396 + /* RTLD_NEXT is buggy as hell so we avoid it by default */
380 397 void* SYMSRC = dlopen(_LIBC,RTLD_LAZY);
381 398 if (SYMSRC == NULL)
382 - fail(-2,"compiled in non-glibc mode and cannot load "
399 + fail(-2,"compiled in non-RTLD_NEXT mode and cannot load "
383 400 "libc from " bold(_LIBC) "; please recompile "
384 - " and specify your libc with -D_LIBC= on the"
401 + " and specify your libc with -D_LIBC= on the "
385 402 "compile command line.");
386 403 # endif
387 404
388 405 # define load_fn(fn,pfx) libc_##fn = dlsym(SYMSRC, #pfx #fn)
389 406 load_fn(open,); load_fn(unlink,);
390 407 load_fn(stat,); load_fn(lstat,);
391 408 load_fn(stat64,); load_fn(lstat64,);