Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interposing part of a shared object by soname

I’ve written a shared object that modifies the arguments to FreeType’s FT_Load_Glyph and FT_Render_Glyph functions, currently by interposing it with LD_PRELOAD and dlsym.

This works fine, but I’m curious to know whether or not there’s a way to make these changes:

  • to all programs that use FreeType on a given host (running e.g. Debian);
  • without clobbering any programs that aren’t actually linked to FreeType;
  • without simply applying an LD_PRELOAD to all programs on the host;
  • without requiring any maintenance unless FreeType’s soname is changed; and
  • without modifying any of FreeType’s files, nor those of any programs on the host.

The only two “solutions” that I’ve been able to come up with are ugly hacks:

  • to LD_PRELOAD all programs, all of the time, which seems slow and fragile; or
  • to copy e.g. libfreetype.so.6.12.3 to libxxxxtype.so.6.12.3; then
    • patch the soname in libxxxxtype.so.6.12.3 to libxxxxtype.so.6;
    • link the interposing shared object against libxxxxtype.so.6; and
    • install the shared object as e.g. libfreetype.so.6.999.

I’d essentially like to transparently patch a couple of functions in a shared object, while letting the remaining functions through, without necessarily having access to the source of the shared object or the programs that use it, but if I make a fake shared object with the soname libfreetype.so.6, I can’t see a clean way to link it to (or dlopen) the real libfreetype.so.6.

This is my first real experiment with shared libraries, so please bear with me if this question makes some incorrect assumptions, or just makes no sense.

like image 979
Delan Azabani Avatar asked May 10 '16 21:05

Delan Azabani


People also ask

What is shared object in Spos?

A shared object is an indivisible unit that is generated from one or more relocatable objects. Shared objects can be bound with dynamic executables to form a runable process. As their name implies, shared objects can be shared by more than one application.

What are shared object files?

A shared library or shared object is a file that is intended to be shared by multiple programs. Symbols used by a program are loaded from shared libraries into memory at load time or runtime.

What are shared objects in Linux?

so (short for "shared object"). Shared libraries are the most common way to manage dependencies on Linux systems. These shared resources are loaded into memory before the application starts, and when several processes require the same library, it will be loaded only once on the system.

Where are shared objects stored?

These shared objects are named with the extension . fso and are stored on the server in a subdirectory of the application that created the shared object. Adobe Media Server creates these directories automatically; you don't have to create a directory for each instance name.


2 Answers

Can you try to use uprobes to dynamically steal control from some functions?

Check http://www.brendangregg.com/blog/2015-06-28/linux-ftrace-uprobe.html

uprobes: user-level dynamic tracing, which was added to Linux 3.5 and improved in Linux 3.14. It lets you trace user-level functions; for example, the return of the readline() function from all running bash shells, with the returned string:

# ./uprobe 'r:bash:readline +0($retval):string'
Tracing uprobe readline (r:readline /bin/bash:0x8db60 +0($retval):string). Ctrl-C to end.
 bash-11886 [003] d... 19601837.001935: readline: (0x41e876 <- 0x48db60) arg1="ls -l"
 bash-11886 [002] d... 19601851.008409: readline: (0x41e876 <- 0x48db60) arg1="echo "hello world""
 bash-11886 [002] d... 19601854.099730: readline: (0x41e876 <- 0x48db60) arg1="df -h"
 bash-11886 [002] d... 19601858.805740: readline: (0x41e876 <- 0x48db60) arg1="cd .."
 bash-11886 [003] d... 19601898.378753: readline: (0x41e876 <- 0x48db60) arg1="foo bar"
^C
Ending tracing...

And http://www.brendangregg.com/blog/2015-07-03/hacking-linux-usdt-ftrace.html

There were also other solutions of tracing user-space functions, like ftrace, systemtap, dtrace, lttng. Some of them need recompilation and defining tracing points statically in the program; and uprobes are "user-level dynamic tracing".

Some links about uprobes:

  • https://events.linuxfoundation.org/slides/lfcs2010_keniston.pdf Uprobes: User-Space Probes (2010)
  • https://www.kernel.org/doc/Documentation/trace/uprobetracer.txt
  • https://lwn.net/Articles/499190/ "Uprobes in 3.5", Jonathan Corbet (2012)

There is handler of uprobes which has pt_regs. As said in last link: "Uprobes thus implements a mechanism by which a kernel function can be invoked whenever a process executes a specific instruction location." and it suggests that uprobes may replace some ptrace/gdb based solutions; so there is a possibility to change execution of any program hitting active uprobe, by changing its eip/rip (PC) register.

You may try some other dynamic instrumentation tools, like pin or dyninst; but they are designed for per-process usage.

like image 102
osgx Avatar answered Sep 21 '22 22:09

osgx


Another solution would be to make system wide "overlay" for lib, with custom libfreetype and then proxying unmodified methods to real lib.

You have to make custom lib compatible with real one. You can to that by using dlopen with absolute path (eg. dlopen("/usr/lib64/libfreetype.so.6")), copying definitions of real, exported functions and proxying them with dlsym. It think that for ease of maintenance you could event replace proxied argument types with simple void*. You would only need to make changes when freetype functions change (arguments count, function names).

To create lib "overlay", you could install custom lib into eg. "/opt/myapp/lib64/libfreetype.so.6", then add this path to dynamic linker run time paths. You may have to create symlinks for other versions or compile new custom lib if original implementation changes. Whatever is needed to shadow real lib and keep other apps working :)

Google says that to change run time loading paths on Debian you have to simply edit /etc/ld.so.conf. Add /opt/myapp/lib64 path at the beginning so it will be checked first. Now any app searching for freetype should load your lib, you can check it with ldd <path to app>.

I can think of just one case when this solution will not work: if app is loading bundled libfreetype or loading it by full path, not by name.

like image 23
glorpen Avatar answered Sep 25 '22 22:09

glorpen