Fun With LD - Preload
Fun With LD - Preload
Kevin Pulo
[email protected]
Australian National University Supercomputing Facility, National Computational Infrastructure National Facility, Canberra, Australia 2009-01-23
Overview
1. Intro: Dynamic linking and LD_PRELOAD 2. Review: Existing LD_PRELOAD hacks 3. Code: Writing LD_PRELOAD hacks 4. Advanced: xlibtrace and xmultiwin
2 / 61
Part 1
1. Intro: Dynamic linking and LD_PRELOAD
2. Review: Existing LD_PRELOAD hacks 3. Code: Writing LD_PRELOAD hacks 4. Advanced: xlibtrace and xmultiwin
3 / 61
$LD_PRELOAD?
Ordinarily the dynamic linker loads shared libs in whatever order it needs them
4 / 61
$LD_PRELOAD?
Ordinarily the dynamic linker loads shared libs in whatever order it needs them $LD_PRELOAD is an environment variable containing a colon (or space) separated list of libraries that the dynamic linker loads before any others
4 / 61
$LD_PRELOAD?
Ordinarily the dynamic linker loads shared libs in whatever order it needs them $LD_PRELOAD is an environment variable containing a colon (or space) separated list of libraries that the dynamic linker loads before any others Entries containing / are treated as lenames Entries not containing / are searched for as usual
4 / 61
$LD_PRELOAD?
Ordinarily the dynamic linker loads shared libs in whatever order it needs them $LD_PRELOAD is an environment variable containing a colon (or space) separated list of libraries that the dynamic linker loads before any others Entries containing / are treated as lenames Entries not containing / are searched for as usual eg. LD_PRELOAD="libc.so.6" eg. LD_PRELOAD="/test/lib/libc.so.6"
4 / 61
$LD_PRELOAD?
Ordinarily the dynamic linker loads shared libs in whatever order it needs them $LD_PRELOAD is an environment variable containing a colon (or space) separated list of libraries that the dynamic linker loads before any others Entries containing / are treated as lenames Entries not containing / are searched for as usual eg. LD_PRELOAD="libc.so.6" eg. LD_PRELOAD="/test/lib/libc.so.6" man ld.so for full dynamic linker info
4 / 61
Okay so what?
Preloading a library means that its functions will be used before others of the same name in later libraries
5 / 61
Okay so what?
Preloading a library means that its functions will be used before others of the same name in later libraries Allows functions to be overridden/replaced/ intercepted
5 / 61
Okay so what?
Preloading a library means that its functions will be used before others of the same name in later libraries Allows functions to be overridden/replaced/ intercepted Program behaviour can be modied non-invasively
5 / 61
Okay so what?
Preloading a library means that its functions will be used before others of the same name in later libraries Allows functions to be overridden/replaced/ intercepted Program behaviour can be modied non-invasively ie. no recompile/relink necessary
5 / 61
Okay so what?
Preloading a library means that its functions will be used before others of the same name in later libraries Allows functions to be overridden/replaced/ intercepted Program behaviour can be modied non-invasively ie. no recompile/relink necessary Especially useful for closed-source programs
5 / 61
Okay so what?
Preloading a library means that its functions will be used before others of the same name in later libraries Allows functions to be overridden/replaced/ intercepted Program behaviour can be modied non-invasively ie. no recompile/relink necessary Especially useful for closed-source programs And when the modications dont belong in the program or the library
5 / 61
System-wide
export LD_PRELOAD="foobar.so" in /etc/prole
(unset LD_PRELOAD)
/etc/ld.so.preload
(loaded before $LD_PRELOAD, non-overridable)
6 / 61
System-wide
export LD_PRELOAD="foobar.so" in /etc/prole
(unset LD_PRELOAD)
/etc/ld.so.preload
(loaded before $LD_PRELOAD, non-overridable)
Affects all dynamically linked programs: be careful Consider selective use: LD_PRELOAD="foobar.so" someprogram (sh/bash) env LD_PRELOAD="foobar.so" someprogram (csh/any)
6 / 61
Issues
Affects dynamically linked programs only - not static
7 / 61
Issues
Affects dynamically linked programs only - not static Also affects child processes
7 / 61
Issues
Affects dynamically linked programs only - not static Also affects child processes setuid/setgid programs: only libs in standard paths that are also setuid/setgid will be preloaded
7 / 61
Issues
Affects dynamically linked programs only - not static Also affects child processes setuid/setgid programs: only libs in standard paths that are also setuid/setgid will be preloaded Can only override library functions, not system calls
(glibc wrappers are fair game)
7 / 61
Issues
Affects dynamically linked programs only - not static Also affects child processes setuid/setgid programs: only libs in standard paths that are also setuid/setgid will be preloaded Can only override library functions, not system calls
(glibc wrappers are fair game)
7 / 61
Part 2
1. Intro: Dynamic linking and LD_PRELOAD
8 / 61
9 / 61
Filesystem shenanigans
By intercepting libc functions that deal with the lesystem, the preload library can modify how the lesystem looks and behaves for programs.
10 / 61
Filesystem shenanigans
By intercepting libc functions that deal with the lesystem, the preload library can modify how the lesystem looks and behaves for programs. Anything thats passed or returns lenames/paths eg. open(), mkdir(), opendir(), stat(), etc
10 / 61
Filesystem shenanigans
By intercepting libc functions that deal with the lesystem, the preload library can modify how the lesystem looks and behaves for programs. Anything thats passed or returns lenames/paths eg. open(), mkdir(), opendir(), stat(), etc cow (File Link Copy-On-Write): http://www.xmailserver.org/cow.html Intercepts open() and friends, breaks hard-links when changing les.
10 / 61
cow demo
$
11 / 61
cow demo
$ ls -ld linux*
11 / 61
cow demo
$ ls -ld linux* drwxr-xr-x 21 4096 2009-01-17 15:37 linux-2.6.26.5 $
11 / 61
cow demo
$ ls -ld linux* drwxr-xr-x 21 4096 2009-01-17 15:37 linux-2.6.26.5 $ du -sk linux*
11 / 61
cow demo
$ ls -ld linux* drwxr-xr-x 21 4096 2009-01-17 15:37 linux-2.6.26.5 $ du -sk linux* 330592 linux-2.6.26.5 $
11 / 61
cow demo
$ ls -ld linux* drwxr-xr-x 21 4096 2009-01-17 15:37 linux-2.6.26.5 $ du -sk linux* 330592 linux-2.6.26.5 $ cp -al linux-2.6.26.5 linux-2.6.26.5-test $
11 / 61
cow demo
$ ls -ld linux* drwxr-xr-x 21 4096 2009-01-17 15:37 linux-2.6.26.5 $ du -sk linux* 330592 linux-2.6.26.5 $ cp -al linux-2.6.26.5 linux-2.6.26.5-test $ ls -ld linux*
11 / 61
cow demo
$ ls -ld linux* drwxr-xr-x 21 4096 2009-01-17 15:37 linux-2.6.26.5 $ du -sk linux* 330592 linux-2.6.26.5 $ cp -al linux-2.6.26.5 linux-2.6.26.5-test $ ls -ld linux* drwxr-xr-x 21 4096 2009-01-17 15:37 linux-2.6.26.5 drwxr-xr-x 21 4096 2009-01-17 15:38 linux-2.6.26.5-test $
11 / 61
cow demo
$ ls -ld linux* drwxr-xr-x 21 4096 2009-01-17 15:37 linux-2.6.26.5 $ du -sk linux* 330592 linux-2.6.26.5 $ cp -al linux-2.6.26.5 linux-2.6.26.5-test $ ls -ld linux* drwxr-xr-x 21 4096 2009-01-17 15:37 linux-2.6.26.5 drwxr-xr-x 21 4096 2009-01-17 15:38 linux-2.6.26.5-test $ du -sk linux*
11 / 61
cow demo
$ ls -ld linux* drwxr-xr-x 21 4096 2009-01-17 15:37 linux-2.6.26.5 $ du -sk linux* 330592 linux-2.6.26.5 $ cp -al linux-2.6.26.5 linux-2.6.26.5-test $ ls -ld linux* drwxr-xr-x 21 4096 2009-01-17 15:37 linux-2.6.26.5 drwxr-xr-x 21 4096 2009-01-17 15:38 linux-2.6.26.5-test $ du -sk linux* 330592 linux-2.6.26.5 5816 linux-2.6.26.5-test $
11 / 61
cow demo
$
12 / 61
cow demo
$ grep LOCALVERSION= linux*/.config
12 / 61
cow demo
$ grep LOCALVERSION= linux*/.config linux-2.6.26.5-test/.config:CONFIG_LOCALVERSION="" linux-2.6.26.5/.config:CONFIG_LOCALVERSION="" $
12 / 61
cow demo
$ grep LOCALVERSION= linux*/.config linux-2.6.26.5-test/.config:CONFIG_LOCALVERSION="" linux-2.6.26.5/.config:CONFIG_LOCALVERSION="" $ vim linux-2.6.26.5-test/.config
12 / 61
cow demo
$ grep LOCALVERSION= linux*/.config linux-2.6.26.5-test/.config:CONFIG_LOCALVERSION="" linux-2.6.26.5/.config:CONFIG_LOCALVERSION="" $ vim linux-2.6.26.5-test/.config $
12 / 61
cow demo
$ grep LOCALVERSION= linux*/.config linux-2.6.26.5-test/.config:CONFIG_LOCALVERSION="" linux-2.6.26.5/.config:CONFIG_LOCALVERSION="" $ vim linux-2.6.26.5-test/.config $ grep LOCALVERSION= linux*/.config
12 / 61
cow demo
$ grep LOCALVERSION= linux*/.config linux-2.6.26.5-test/.config:CONFIG_LOCALVERSION="" linux-2.6.26.5/.config:CONFIG_LOCALVERSION="" $ vim linux-2.6.26.5-test/.config $ grep LOCALVERSION= linux*/.config linux-2.6.26.5-test/.config:CONFIG_LOCALVERSION="-test" linux-2.6.26.5/.config:CONFIG_LOCALVERSION="-test" $
12 / 61
cow demo
$ grep LOCALVERSION= linux*/.config linux-2.6.26.5-test/.config:CONFIG_LOCALVERSION="" linux-2.6.26.5/.config:CONFIG_LOCALVERSION="" $
13 / 61
cow demo
$ grep LOCALVERSION= linux*/.config linux-2.6.26.5-test/.config:CONFIG_LOCALVERSION="" linux-2.6.26.5/.config:CONFIG_LOCALVERSION="" $ export LD_PRELOAD="libflcow.so:$LD_PRELOAD" $
13 / 61
cow demo
$ grep LOCALVERSION= linux*/.config linux-2.6.26.5-test/.config:CONFIG_LOCALVERSION="" linux-2.6.26.5/.config:CONFIG_LOCALVERSION="" $ export LD_PRELOAD="libflcow.so:$LD_PRELOAD" $ export FLCOW_PATH="$PWD" $
13 / 61
cow demo
$ grep LOCALVERSION= linux*/.config linux-2.6.26.5-test/.config:CONFIG_LOCALVERSION="" linux-2.6.26.5/.config:CONFIG_LOCALVERSION="" $ export LD_PRELOAD="libflcow.so:$LD_PRELOAD" $ export FLCOW_PATH="$PWD" $ vim linux-2.6.26.5-test/.config
13 / 61
cow demo
$ grep LOCALVERSION= linux*/.config linux-2.6.26.5-test/.config:CONFIG_LOCALVERSION="" linux-2.6.26.5/.config:CONFIG_LOCALVERSION="" $ export LD_PRELOAD="libflcow.so:$LD_PRELOAD" $ export FLCOW_PATH="$PWD" $ vim linux-2.6.26.5-test/.config $
13 / 61
cow demo
$ grep LOCALVERSION= linux*/.config linux-2.6.26.5-test/.config:CONFIG_LOCALVERSION="" linux-2.6.26.5/.config:CONFIG_LOCALVERSION="" $ export LD_PRELOAD="libflcow.so:$LD_PRELOAD" $ export FLCOW_PATH="$PWD" $ vim linux-2.6.26.5-test/.config $ grep LOCALVERSION= linux*/.config
13 / 61
cow demo
$ grep LOCALVERSION= linux*/.config linux-2.6.26.5-test/.config:CONFIG_LOCALVERSION="" linux-2.6.26.5/.config:CONFIG_LOCALVERSION="" $ export LD_PRELOAD="libflcow.so:$LD_PRELOAD" $ export FLCOW_PATH="$PWD" $ vim linux-2.6.26.5-test/.config $ grep LOCALVERSION= linux*/.config linux-2.6.26.5-test/.config:CONFIG_LOCALVERSION="-test" linux-2.6.26.5/.config:CONFIG_LOCALVERSION="" $
13 / 61
cow demo
$ grep LOCALVERSION= linux*/.config linux-2.6.26.5-test/.config:CONFIG_LOCALVERSION="" linux-2.6.26.5/.config:CONFIG_LOCALVERSION="" $ export LD_PRELOAD="libflcow.so:$LD_PRELOAD" $ export FLCOW_PATH="$PWD" $ vim linux-2.6.26.5-test/.config $ grep LOCALVERSION= linux*/.config linux-2.6.26.5-test/.config:CONFIG_LOCALVERSION="-test" linux-2.6.26.5/.config:CONFIG_LOCALVERSION="" $ du -sk linux*
13 / 61
cow demo
$ grep LOCALVERSION= linux*/.config linux-2.6.26.5-test/.config:CONFIG_LOCALVERSION="" linux-2.6.26.5/.config:CONFIG_LOCALVERSION="" $ export LD_PRELOAD="libflcow.so:$LD_PRELOAD" $ export FLCOW_PATH="$PWD" $ vim linux-2.6.26.5-test/.config $ grep LOCALVERSION= linux*/.config linux-2.6.26.5-test/.config:CONFIG_LOCALVERSION="-test" linux-2.6.26.5/.config:CONFIG_LOCALVERSION="" $ du -sk linux* 330592 linux-2.6.26.5 5856 linux-2.6.26.5-test $
13 / 61
14 / 61
14 / 61
Network shenanigans
By intercepting libc functions that deal with the network, the preload library can modify how the network looks and behaves for programs. eg. socket(), connect(), bind(), listen(), gethostbyname(), etc
15 / 61
Network shenanigans
By intercepting libc functions that deal with the network, the preload library can modify how the network looks and behaves for programs. eg. socket(), connect(), bind(), listen(), gethostbyname(), etc libshape: http://freshmeat.net/projects/libshape/ Limits the download rate of programs (ie. user-space network trafc rate-shaping). netjail: http://netjail.sourceforge.net/ Controls where and how programs may connect to the network. Useful for dealing with spyware, etc.
15 / 61
16 / 61
16 / 61
17 / 61
electricfence
Intercepts malloc() and friends, surrounds allocated memory with protected memory to catch buffer over/under-runs.
18 / 61
electricfence
Intercepts malloc() and friends, surrounds allocated memory with protected memory to catch buffer over/under-runs.
18 / 61
segv_handler
Signal handler for segfaults that produces a backtrace. Installs a signal handler for SIGSEGV and SIGBUS Signal handler basically just runs gdb on current process to dump backtrace into a logle (program is still free to use its own handler)
(lib could also intercept signal() to always force the backtrace)
19 / 61
Graphical augmentation
Since most graphical display is also done via libraries, it is also possible (though usually more complex) to intercept these graphical libraries to augment the display in various ways.
20 / 61
Graphical augmentation
Since most graphical display is also done via libraries, it is also possible (though usually more complex) to intercept these graphical libraries to augment the display in various ways. libglfps: http://users.dakotacom.net/~donut/programs/libglfps.html Adds a framerate display to OpenGL programs.
20 / 61
Part 3
1. Intro: Dynamic linking and LD_PRELOAD 2. Review: Existing LD_PRELOAD hacks
21 / 61
dlfcn
#include <dlfcn.h> (Dynamic Linker FunCtioNs) Two main functions:
void* dlopen(const char* filename, int flag) void* dlsym(void* handle, const char* symbol)
22 / 61
Motivating example
Suppose we have some closed-source multi-threaded application that we are stuck with
23 / 61
Motivating example
Suppose we have some closed-source multi-threaded application that we are stuck with This app is spawning too many threads (one for each CPU in the system), AND has no way to cong it
23 / 61
Motivating example
Suppose we have some closed-source multi-threaded application that we are stuck with This app is spawning too many threads (one for each CPU in the system), AND has no way to cong it Digging around with strace, ltrace, gdb, /usr/include/bits, etc we nd that its calling
sysconf(_SC_NPROCESSORS_CONF)
23 / 61
Motivating example
Suppose we have some closed-source multi-threaded application that we are stuck with This app is spawning too many threads (one for each CPU in the system), AND has no way to cong it Digging around with strace, ltrace, gdb, /usr/include/bits, etc we nd that its calling
sysconf(_SC_NPROCESSORS_CONF)
So we want a preload lib which overrides the return value of sysconf() for this case behaviour nessing
23 / 61
libsysconfcpus
http://www.kev.pulo.com.au/libsysconfcpus/ We will construct this library from the ground up, as a simple example of how to create a preload library
24 / 61
libsysconfcpus
http://www.kev.pulo.com.au/libsysconfcpus/ We will construct this library from the ground up, as a simple example of how to create a preload library Version 0.1: Empty base project
24 / 61
libsysconfcpus
http://www.kev.pulo.com.au/libsysconfcpus/ We will construct this library from the ground up, as a simple example of how to create a preload library Version 0.1: Empty base project Version 0.2: Library debug and init
24 / 61
libsysconfcpus
http://www.kev.pulo.com.au/libsysconfcpus/ We will construct this library from the ground up, as a simple example of how to create a preload library Version 0.1: Empty base project Version 0.2: Library debug and init Version 0.3: Intercept sysconf()
24 / 61
libsysconfcpus
http://www.kev.pulo.com.au/libsysconfcpus/ We will construct this library from the ground up, as a simple example of how to create a preload library Version 0.1: Empty base project Version 0.2: Library debug and init Version 0.3: Intercept sysconf() Version 0.4: Adjust sysconf() behaviour
24 / 61
libsysconfcpus
http://www.kev.pulo.com.au/libsysconfcpus/ We will construct this library from the ground up, as a simple example of how to create a preload library Version 0.1: Empty base project Version 0.2: Library debug and init Version 0.3: Intercept sysconf() Version 0.4: Adjust sysconf() behaviour Version 0.5: Extra features
24 / 61
v0.1: congure.ac
$ cat configure.ac AC_PREREQ(2.5) AC_INIT(libsysconfcpus, [0.1], [[email protected]]) AC_CONFIG_SRCDIR([src/libsysconfcpus.c]) AM_INIT_AUTOMAKE AM_CONFIG_HEADER([config.h]) AC_PROG_CC AC_PROG_INSTALL AC_PROG_LN_S
...
25 / 61
v0.1: congure.ac
$ cat configure.ac AC_PREREQ(2.5) AC_INIT(libsysconfcpus, [0.1], [[email protected]]) AC_CONFIG_SRCDIR([src/libsysconfcpus.c]) AM_INIT_AUTOMAKE AM_CONFIG_HEADER([config.h]) AC_PROG_CC AC_PROG_INSTALL AC_PROG_LN_S
...
25 / 61
v0.1: congure.ac
$ cat configure.ac AC_PREREQ(2.5) AC_INIT(libsysconfcpus, [0.1], [[email protected]]) AC_CONFIG_SRCDIR([src/libsysconfcpus.c]) AM_INIT_AUTOMAKE AM_CONFIG_HEADER([config.h]) AC_PROG_CC AC_PROG_INSTALL AC_PROG_LN_S
...
25 / 61
v0.1: congure.ac
...
AC_ENABLE_SHARED AC_DISABLE_STATIC AM_PROG_LIBTOOL AC_HEADER_STDC AC_C_CONST AC_CONFIG_FILES([Makefile src/Makefile]) AC_OUTPUT $
26 / 61
v0.1: congure.ac
...
AC_ENABLE_SHARED AC_DISABLE_STATIC AM_PROG_LIBTOOL AC_HEADER_STDC AC_C_CONST AC_CONFIG_FILES([Makefile src/Makefile]) AC_OUTPUT $
26 / 61
v0.1: congure.ac
...
AC_ENABLE_SHARED AC_DISABLE_STATIC AM_PROG_LIBTOOL AC_HEADER_STDC AC_C_CONST
26 / 61
v0.1: congure.ac
...
AC_ENABLE_SHARED AC_DISABLE_STATIC AM_PROG_LIBTOOL AC_HEADER_STDC AC_C_CONST AC_CONFIG_FILES([Makefile src/Makefile]) AC_OUTPUT $
26 / 61
v0.1: Makele.am
$ cat Makefile.am SUBDIRS = src $ cat src/Makefile.am AUTOMAKE_OPTIONS = 1.4 foreign CFLAGS += -Wall lib_LTLIBRARIES = libsysconfcpus.la libsysconfcpus_la_SOURCES = libsysconfcpus.c libsysconfcpus_la_CFLAGS = -O1 libsysconfcpus_la_LIBADD = -ldl #dist_man_MANS = libsysconfcpus.1 $ touch src/libsysconfcpus.c
27 / 61
v0.1: Makele.am
$ cat Makefile.am SUBDIRS = src
$ cat src/Makefile.am AUTOMAKE_OPTIONS = 1.4 foreign CFLAGS += -Wall lib_LTLIBRARIES = libsysconfcpus.la libsysconfcpus_la_SOURCES = libsysconfcpus.c libsysconfcpus_la_CFLAGS = -O1 libsysconfcpus_la_LIBADD = -ldl #dist_man_MANS = libsysconfcpus.1 $ touch src/libsysconfcpus.c
27 / 61
v0.1: Makele.am
$ cat Makefile.am SUBDIRS = src $ cat src/Makefile.am AUTOMAKE_OPTIONS = 1.4 foreign CFLAGS += -Wall
Generic AM setup
lib_LTLIBRARIES = libsysconfcpus.la libsysconfcpus_la_SOURCES = libsysconfcpus.c libsysconfcpus_la_CFLAGS = -O1 libsysconfcpus_la_LIBADD = -ldl #dist_man_MANS = libsysconfcpus.1 $ touch src/libsysconfcpus.c
27 / 61
v0.1: Makele.am
$ cat Makefile.am SUBDIRS = src $ cat src/Makefile.am AUTOMAKE_OPTIONS = 1.4 foreign CFLAGS += -Wall lib_LTLIBRARIES = libsysconfcpus.la libsysconfcpus_la_SOURCES = libsysconfcpus.c libsysconfcpus_la_CFLAGS = -O1 libsysconfcpus_la_LIBADD = -ldl #dist_man_MANS = libsysconfcpus.1 $ touch src/libsysconfcpus.c
Setup for
libsysconfcpus.so
27 / 61
v0.1: Makele.am
$ cat Makefile.am SUBDIRS = src $ cat src/Makefile.am AUTOMAKE_OPTIONS = 1.4 foreign CFLAGS += -Wall lib_LTLIBRARIES = libsysconfcpus.la libsysconfcpus_la_SOURCES = libsysconfcpus.c libsysconfcpus_la_CFLAGS = -O1 libsysconfcpus_la_LIBADD = -ldl #dist_man_MANS = libsysconfcpus.1 $ touch src/libsysconfcpus.c
27 / 61
v0.1: Makele.am
$ cat Makefile.am SUBDIRS = src $ cat src/Makefile.am AUTOMAKE_OPTIONS = 1.4 foreign CFLAGS += -Wall lib_LTLIBRARIES = libsysconfcpus.la libsysconfcpus_la_SOURCES = libsysconfcpus.c libsysconfcpus_la_CFLAGS = -O1 libsysconfcpus_la_LIBADD = -ldl #dist_man_MANS = libsysconfcpus.1 $ touch src/libsysconfcpus.c
27 / 61
28 / 61
28 / 61
28 / 61
28 / 61
28 / 61
v0.1: congure
$ ./configure --prefix=/tmp/sysconf checking for a BSD-compatible install... /usr/bin/ginstall -c checking whether build environment is sane... yes checking for gawk... gawk checking whether make sets $(MAKE)... yes checking for gcc... gcc ... checking for an ANSI C-conforming const... yes configure: creating ./config.status config.status: creating Makefile config.status: creating src/Makefile config.status: creating config.h config.status: executing depfiles commands $
29 / 61
v0.1: make
$ make ... /bin/sh ../libtool --tag=CC --mode=link gcc -g -O2 - Wall -o libsysconfcpus.la -rpath /home/kev/ libsysconfcpus/install/lib libsysconfcpus_la- libsysconfcpus.lo -ldl gcc -shared .libs/libsysconfcpus_la-libsysconfcpus.o -ldl -Wl,-soname -Wl,libsysconfcpus.so.0 -o . libs/libsysconfcpus.so.0.0.0 ... $
30 / 61
31 / 61
31 / 61
31 / 61
31 / 61
31 / 61
31 / 61
31 / 61
32 / 61
v0.2: debug
src/libsysconfcpus.c
#include <stdio.h> #include <stdarg.h> static int do_debug() { return getenv("LIBSYSCONFCPUS_DEBUG"); } static void dprintf(char *fmt, ...) { va_list ap; if (do_debug()) { va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fflush(stderr); } }
33 / 61
v0.2: init/ni
src/libsysconfcpus.c
static void _libsysconfcpus_init(void) __attribute__ ((constructor)); static void _libsysconfcpus_fini(void) __attribute__ ((destructor)); static void _libsysconfcpus_init(void) { dprintf("libsysconfcpus: starting up\n"); } static void _libsysconfcpus_fini(void) { dprintf("libsysconfcpus: shutting down\n"); }
34 / 61
35 / 61
src/sysconfcpus-debug.in
#!/bin/sh LD_PRELOAD="@libdir@/libsysconfcpus.so:$LD_PRELOAD" \ LIBSYSCONFCPUS_DEBUG=y \ exec "$@"
35 / 61
sysconfcpus:: Makefile $(srcdir)/sysconfcpus.in rm -f sysconfcpus sysconfcpus.tmp && \ $(edit) $(srcdir)/sysconfcpus.in >sysconfcpus.tmp \ && mv sysconfcpus.tmp sysconfcpus
36 / 61
37 / 61
v0.2: rebuild
$
38 / 61
v0.2: rebuild
$ make clean
38 / 61
v0.2: rebuild
$ make clean ... $
38 / 61
v0.2: rebuild
$ make clean ... $ autoreconf -m
38 / 61
v0.2: rebuild
$ make clean ... $ autoreconf -m ... $
38 / 61
v0.2: rebuild
$ make clean ... $ autoreconf -m ... $ make install
38 / 61
v0.2: rebuild
$ make clean ... $ autoreconf -m ... $ make install ... $
38 / 61
v0.2: rebuild
$ make clean ... $ autoreconf -m ... $ make install ... $ ls -l /tmp/sysconf/
38 / 61
v0.2: rebuild
$ make clean ... $ autoreconf -m ... $ make install ... $ ls -l /tmp/sysconf/ drwxr-xr-x 2 4096 2008-12-30 23:07 bin drwxr-xr-x 2 4096 2008-12-30 23:07 lib $
38 / 61
v0.2: rebuild
$ make clean ... $ autoreconf -m ... $ make install ... $ ls -l /tmp/sysconf/ drwxr-xr-x 2 4096 2008-12-30 23:07 bin drwxr-xr-x 2 4096 2008-12-30 23:07 lib $ ls -l /tmp/sysconf/bin/
38 / 61
v0.2: rebuild
$ make clean ... $ autoreconf -m ... $ make install ... $ ls -l /tmp/sysconf/ drwxr-xr-x 2 4096 2008-12-30 23:07 bin drwxr-xr-x 2 4096 2008-12-30 23:07 lib $ ls -l /tmp/sysconf/bin/ -rwxr-xr-x 1 102 2008-12-30 23:07 sysconfcpus -rwxr-xr-x 1 125 2008-12-30 23:07 sysconfcpus-debug $
38 / 61
39 / 61
40 / 61
41 / 61
v0.3: test
$
42 / 61
v0.3: test
$ rudeapp
42 / 61
v0.3: test
$ rudeapp Rude application v1.0 Spawning 8 threads ^C $
42 / 61
v0.3: test
$ rudeapp Rude application v1.0 Spawning 8 threads ^C $ /tmp/sysconf/bin/sysconfcpus-debug rudeapp
42 / 61
v0.3: test
$ rudeapp Rude application v1.0 Spawning 8 threads ^C $ /tmp/sysconf/bin/sysconfcpus-debug rudeapp libsysconfcpus: starting up Rude application v1.0 libsysconfcpus: sysconf(83): entered libsysconfcpus: sysconf: libc_handle = 0x1738eb78 libsysconfcpus: sysconf: underlying = 0x16cbc260 libsysconfcpus: about to call underlying sysconf() libsysconfcpus: sysconf(83) = 8 Spawning 8 threads ^C $
42 / 61
43 / 61
44 / 61
v0.4: test
$
45 / 61
v0.4: test
$ LIBSYSCONFCPUS=2 /tmp/sysconf/bin/sysconfcpus-debug rudeapp
45 / 61
v0.4: test
$ LIBSYSCONFCPUS=2 /tmp/sysconf/bin/sysconfcpus-debug rudeapp libsysconfcpus: starting up Rude application v1.0 libsysconfcpus: sysconf(83): entered libsysconfcpus: sysconf: libc_handle = 0x1738eb78 libsysconfcpus: sysconf: underlying = 0x16cbc260 libsysconfcpus: about to call underlying sysconf() libsysconfcpus: underlying sysconf(83) = 8 libsysconfcpus: sysconf(83) = 2 Spawning 2 threads ^C $
45 / 61
46 / 61
RTLD_NEXT
GNU extension: special library pseudo-handle Find symbol in next library after current
#define __USE_GNU #include <dlfcn.h> ... // or #define _GNU_SOURCE
#if defined(RTLD_NEXT) libc_handle = RTLD_NEXT; #else libc_handle = dlopen("libc.so.6", RTLD_LAZY); #endif underlying = dlsym(libc_handle, "sysconf");
47 / 61
Part 4
1. Intro: Dynamic linking and LD_PRELOAD 2. Review: Existing LD_PRELOAD hacks 3. Code: Writing LD_PRELOAD hacks
48 / 61
xlibtrace
http://www.kev.pulo.com.au/xlibtrace/ The idea: Intercept all functions in xlib Make each output tracing info like strace/ltrace
49 / 61
xlibtrace
http://www.kev.pulo.com.au/xlibtrace/ The idea: Intercept all functions in xlib Make each output tracing info like strace/ltrace Why not just use ltrace? Can verbosely interpret and output library-specic data structures Basis for wide-intercepting preload libs Portable - doesnt require per-architecture changes
49 / 61
xlibtrace output
[32095] (0): int XNextEvent(Display * display = (0x60a3b0) ( opaque), XEvent * event_return = (0x7fffbd645870) { int type = ReparentNotify, unsigned long serial = 35, Bool send_event = False, Display * display = (0x60a3b0) ( opaque), Window event = 0x8400003, Window window = 0 x8400003, Window parent = 0x3203016, int x = 0, int y = 0, Bool override_redirect = False }) = <unfinished...> [32095] (0): int XNextEvent(Display * display = (0x60a3b0) ( opaque), XEvent * event_return = (0x7fffbd645870) { int type = ConfigureNotify, unsigned long serial = 35, Bool send_event = True, Display * display = (0x60a3b0) (opaque), Window event = 0x8400003, Window window = 0 x8400003, int x = 2853, int y = 24, int width = 100, int height = 100, int border_width = 0, Window above = 0x3203015, Bool override_redirect = False }) = 0
50 / 61
xlibtrace skeleton
int XClearWindow(Display* display, Window w) { static int (*underlying)(Display* display, Window w); int retval; if (!underlying) { underlying = dlsym(RLTD_NEXT, "XClearWindow"); } /* Print function name and parameters */ retval = (*underlying)(display, w); /* Print return value */ return retval; }
51 / 61
#define __TRACE_ADDITIONAL_POST_RUN_UNDERLYING_XClearWindow__ #define __TRACE_PRINTF_BODY_XClearWindow__ \ always_reprint = 1; \ __TRACE_PRINTF_ARG__(XClearWindow, Display_p, display) \ __PRINT_COMMA__(out) \ __TRACE_PRINTF_ARG__(XClearWindow, Window, w) #define __TRACE_RUN_UNDERLYING_EPILOGUE_XClearWindow__ \ __TRACE_RUN_XFLUSH_XSYNC__(XClearWindow, Display_p, display) __TRACE__(TYPED, FIXED, XClearWindow)
52 / 61
53 / 61
54 / 61
55 / 61
56 / 61
57 / 61
The problem
I want some windows shown on both monitors at the same time.
58 / 61
The problem
I want some windows shown on both monitors at the same time. Some simple ones I just run 2 instances of: xload, pload, xapmload, xcal, xclock, xbiff, etc
58 / 61
The problem
I want some windows shown on both monitors at the same time. Some simple ones I just run 2 instances of: xload, pload, xapmload, xcal, xclock, xbiff, etc But some I cant: x11-ssh-askpass xmms xscreensaver dialogs wmwork
58 / 61
xmultiwin
http://www.kev.pulo.com.au/xmultiwin/ The idea: Intercept all window-related functions in xlib In XCreateWindow() automatically clone the window Then duplicate all xlib calls to the cloned windows
59 / 61
xmultiwin Fun
Parallel window trees Event translation from cloned windows Excessive redraw heuristics X extensions Support for higher level libs, eg OpenGL, cairo, etc Many monitors (> 1 clone) Clone on different $DISPLAY Clone to Xvfb: screen(1) for X? varargs with LD_PRELOAD?
(current hack: count args and have generated cases)
60 / 61
Thank you
Questions?
61 / 61