Teil eines gemeinsamen Objekts nach Soname einfügen

8

Ich habe ein gemeinsames Objekt geschrieben, das die Argumente für die Funktionen FT_Load_Glyph und FT_Render_Glyph von FreeType ändert, indem es mit LD_PRELOAD und dlsym verknüpft wird.

Das funktioniert gut, aber ich bin neugierig, ob es eine Möglichkeit gibt, diese Änderungen vorzunehmen:

  • für alle Programme, die FreeType auf einem bestimmten Host (z. B. Debian) verwenden;
  • ohne irgendwelche Programme zu überlisten, die nicht mit FreeType verbunden sind;
  • ohne einfach ein LD_PRELOAD auf alle Programme auf dem Host anzuwenden;
  • ohne Wartung, es sei denn, FreeTypes Soname wurde geändert; und
  • ohne Änderung von FreeType-Dateien oder von Programmen auf dem Host.

Die einzigen zwei "Lösungen", die ich mir vorstellen konnte, sind hässliche Hacks:

  • to LD_PRELOAD alle Programme, die ganze Zeit, die langsam und zerbrechlich erscheint; oder
  • um z.B. libfreetype.so.6.12.3 bis libxxxxtype.so.6.12.3 ; dann
    • packe den Soname in libxxxxtype.so.6.12.3 auf libxxxxtype.so.6 ;
    • Verknüpfen Sie das zwischengeordnete Objekt mit libxxxxtype.so.6 ; und
    • installieren Sie das gemeinsame Objekt als z. libfreetype.so.6.999 .

Ich möchte im Wesentlichen transparent einige Funktionen in einem gemeinsamen Objekt patchen, während ich die restlichen Funktionen durchlasse, ohne notwendigerweise Zugriff auf die Quelle des gemeinsamen Objekts oder die Programme zu haben, die es benutzen, aber wenn ich a mache gefälschtes geteiltes Objekt mit dem Soname libfreetype.so.6 , ich kann keine saubere Methode sehen, um es mit (oder dlopen ) mit dem echten libfreetype.so.6 zu verknüpfen.

Dies ist mein erstes wirkliches Experiment mit Shared Libraries, also bitte ertragen Sie mich, wenn diese Frage einige falsche Annahmen macht oder einfach keinen Sinn ergibt.

    
Delan Azabani 10.05.2016, 21:00
quelle

3 Antworten

3

Können Sie versuchen, uprobes zu verwenden, um die Steuerung einiger Funktionen dynamisch zu stehlen?

Überprüfen Ссылка

  

uprobes: Dynamische Ablaufverfolgung auf Benutzerebene, die zu Linux 3.5 hinzugefügt und in Linux 3.14 verbessert wurde. Sie können Funktionen auf Benutzerebene verfolgen. Zum Beispiel die Rückgabe der Funktion readline () von allen laufenden Bash-Shells mit der zurückgegebenen Zeichenfolge:

%Vor%

Und Ссылка

Es gab auch andere Lösungen zum Verfolgen von User-Space-Funktionen, wie ftrace, systemtap, dtrace, lttng. Einige von ihnen müssen neu kompiliert werden und Tracing-Punkte statisch im Programm definieren. und uprobes sind "user-level dynamic tracing".

Einige Links über Uprobes:

Es gibt handler von uprobes mit pt_regs . Wie im letzten Link gesagt: " Uprobes implementiert somit einen Mechanismus, mit dem eine Kernel-Funktion aufgerufen werden kann, wenn ein Prozess eine bestimmte Befehlsstelle ausführt. " und schlägt vor, dass uprobes einige ptrace / gdb-basierte Lösungen ersetzen können ; es besteht also die Möglichkeit, die Ausführung eines Programms zu ändern, das den aktiven Modus anspricht, indem das eip / rip (PC) -Register geändert wird.

Sie können auch andere dynamische Instrumentierungswerkzeuge wie pin oder dyninst ; aber sie sind für die pro-Prozess-Nutzung ausgelegt.

    
osgx 29.06.2016, 02:54
quelle
2

Eine andere Lösung wäre, systemweit "overlay" für lib zu machen, mit benutzerdefiniertem libfreetype und dann unprofessionell unmodifizierter Methoden zu reell lib.

Sie müssen die benutzerdefinierte Lib mit der echten lib kompatibel machen. Das kannst du mit dlopen mit absoluter Pfad (zB dlopen("/usr/lib64/libfreetype.so.6") ), Kopieren von Definitionen von reellen, exportierten Funktionen und deren Proxy mit dlsym . Sie denken, dass zur einfacheren Wartung Sie können proxied Argumenttypen durch einfache void* ersetzen. Sie müssen nur Änderungen vornehmen, wenn sich Freetype-Funktionen ändern (Argumente zählen, Funktionsnamen).

Um lib "overlay" zu erstellen, könnten Sie benutzerdefinierte Lib in zB installieren. "/opt/myapp/lib64/libfreetype.so.6", dann fügen Sie diesen Pfad zu Laufzeitpfaden dynamischer Linker hinzu. Sie müssen möglicherweise Symlinks für andere Versionen erstellen oder neue benutzerdefinierte Bibliotheken kompilieren, wenn sich die ursprüngliche Implementierung ändert. Was auch immer benötigt wird, um Real-Lib zu beschatten und andere Apps in Betrieb zu halten :)

Google sagt, dass man, um Laufzeitladepfade auf Debian zu ändern, einfach /etc/ld.so.conf bearbeiten muss. Fügen Sie /opt/myapp/lib64 path am Anfang hinzu, so dass es zuerst überprüft wird. Jetzt sollte jede App, die nach Freetype sucht, deine lib laden, du kannst sie mit ldd <path to app> überprüfen.

Ich kann nur an einen Fall denken, wenn diese Lösung nicht funktioniert: wenn die App gebündelten libfreetype lädt oder sie nach dem vollständigen Pfad lädt, nicht nach dem Namen.

    
glorpen 28.06.2016 10:02
quelle
2
  

zu LD_PRELOAD alle Programme, die ganze Zeit, die langsam und zerbrechlich scheint

Das ist eine gute Lösung (für was Sie wollen). Ich sehe keinen besseren.

  • Es ist nicht fragil. Es stellt dem Runtime-Linker auf dokumentierte Weise Informationen bereit. Du nimmst nichts an und tust so, als wäre etwas nicht das, was es ist. Sie ändern nur die Präferenzhierarchie für die Auflösung von Funktionsnamen.

  • Es ist nicht langsam. Der Linker muss irgendwann etwas tun. Es muss überprüft werden, ob LD_PRELOAD definiert ist, was in jedem Fall eine User-Space-Operation ist. Also wird es diesem Pfad folgen und deine Bibliothek laden, bevor du eine Menge anderer Arbeit verrichtest. Ich wäre erstaunt, wenn die Zeit unter normalen Umständen überhaupt messbar wäre.

Es gibt zwei Bedenken, die ich haben würde, aber sie sind orthogonal zur Technik. Der Code muss in jedem Fall funktionieren, und Sie müssen ein wenig in das Prozess-Erzeugungs-Framework eintauchen, um sicherzustellen, dass LD_PRELOAD wirklich überall definiert ist . Darüber hinaus definiert Id.so seine Umgebungsvariablen genau für Ihre beabsichtigte Verwendung. Wer soll streiten?

    
James K. Lowden 29.06.2016 02:49
quelle