2013-02-14 5 views
16

In meinem Versuch, "Steam for Linux" mit Debian zu arbeiten, bin ich auf ein Problem gestoßen. libcef (Chromium Embedded Framework) funktioniert mit GLIBC_2.13 (die auf Debian Testing eglibc zur Verfügung stellen kann), aber erfordert eine nervtötende wenig zusätzliche Funktion von GLIBC_2.15 (die eglibc nicht zur Verfügung stellen kann):Kann ich libc (GLIBC_2.13) dazu bringen, ein Symbol zu laden, das es nicht hat (aus GLIBC_2.15)?

$ readelf -s libcef.so | grep -E "@GLIBC_2\.1[4567]" 
1037: 00000000  0 FUNC GLOBAL DEFAULT UND [email protected]_2.15 (49) 
2733: 00000000  0 FUNC GLOBAL DEFAULT UND [email protected]@GLIBC_2.15 

Mein Plan des Angriffs hier war zu LD_PRELOAD eine Shim-Bibliothek, die nur diese Funktionen bietet. Das scheint nicht zu funktionieren. Ich möchte wirklich vermeiden, GLIBC_2.17 zu installieren (da es in Debian experimentell ist; selbst Debian sid hat immer noch GLIBC_2.13).


Das habe ich ausprobiert.

fdelt_chk.c ist im Grunde from the GNU C library gestohlen:

#include <sys/select.h> 

# define strong_alias(name, aliasname) _strong_alias(name, aliasname) 
# define _strong_alias(name, aliasname) \ 
    extern __typeof (name) aliasname __attribute__ ((alias (#name))); 

unsigned long int 
__fdelt_chk (unsigned long int d) 
{ 
    if (d >= FD_SETSIZE) 
    __chk_fail(); 

    return d/__NFDBITS; 
} 
strong_alias (__fdelt_chk, __fdelt_warn) 

Mein Versions Skript sieht wie folgt aus:

GLIBC_2.15 { 
    __fdelt_chk; __fdelt_warn; 
}; 

ich die Bibliothek dann bauen Sie wie folgt vor:

$ gcc -m32 -c -fPIC fdelt_chk.c -o fdelt_chk.o 
$ gcc -m32 -shared -nostartfiles -Wl,-s -Wl,--version-script Versions -o fdelt_chk.so fdelt_chk.o 

Allerdings, wenn ich Dann starte Steam (mit ein paar Extras, um es zu bekommen) in erster Linie in Betrieb), weigert sich der Lader immer noch das Symbol zu finden:

% LD_LIBRARY_PATH="/home/tinctorius/.local/share/Steam/ubuntu12_32" LD_PRELOAD=./fdelt_chk.so:./steamui.so ./steam 
./steam: /lib/i386-linux-gnu/i686/cmov/libc.so.6: version `GLIBC_2.15' not found (required by /home/tinctorius/.local/share/Steam/ubuntu12_32/libcef.so)  

Allerdings ist die Version Symbol auch durch die .so versehen ich gerade gebaut:

% readelf -s fdelt_chk.so 

Symbol table '.dynsym' contains 8 entries: 
    Num: Value Size Type Bind Vis  Ndx Name 
    0: 00000000  0 NOTYPE LOCAL DEFAULT UND 
    1: 00000000  0 FUNC GLOBAL DEFAULT UND [email protected]_2.3.4 (3) 
    2: 0000146c  0 NOTYPE GLOBAL DEFAULT ABS _edata 
    3: 0000146c  0 NOTYPE GLOBAL DEFAULT ABS _end 
    4: 00000310 44 FUNC GLOBAL DEFAULT 11 [email protected]@GLIBC_2.15 
    5: 00000310 44 FUNC GLOBAL DEFAULT 11 [email protected]@GLIBC_2.15 
    6: 00000000  0 OBJECT GLOBAL DEFAULT ABS GLIBC_2.15 
    7: 0000146c  0 NOTYPE GLOBAL DEFAULT ABS __bss_start 

An diesem Punkt I Ich weiß nicht, was ich tun kann, um den Loader (wer?) dazu zu bringen, meine Symbole zu wählen. Gehe ich überhaupt in die richtige Richtung?

+1

Versuchen zu ermöglichen [LD_DEBUG] (http://www.bnikolic.co .uk/blog/linux-ld-debug.html) '= all' und überprüfe, wie rtld (ld-linux.so) nach' __fdelt' und '@@ GLIBC_2.15' sucht. – osgx

+0

So viel logspam. Es sieht so aus, als würde man nur '/ lib/i386-linux-gnu/i686/cmov/libc.so.6' betrachten und sofort aufgeben. Vielleicht muss ich ein geeignetes Soname für fdelt_chk.so ... –

+0

Einstellung '-Wl, -soname, libc.so.6' tötet alles, denn jetzt wird es nicht weiter als meine eigene Bibliothek suchen. Wäre es möglich, die tatsächliche 'libc' durch den absoluten Soname zu importieren und alle anderen Symbole wieder zu exportieren? –

Antwort

9

Ich stieß auf dasselbe Problem, allerdings nicht mit Steam. Was ich wollte, wollte 2.15 für fdelt_chk während mein System hatte 2.14. Ich habe eine Lösung für einfache Fälle wie unsere gefunden, in denen wir leicht eine eigene Implementierung für die fehlende Funktionalität bereitstellen können.

Ich begann von Ihrer versuchten Lösung der Implementierung der Funktionalität und LD_PRELOAD ing es. Die Verwendung von (wie von OSGX vorgeschlagen) zeigte, dass der Linker immer noch nach 2.15 suchte, also war es nicht genug, das richtige Symbol zu haben, und irgendwo gab es einen anderen Versionierungsmechanismus. Ich bemerkte, dass objdump -p und readelf -V beide Referenzen auf 2.15 zeigten, also suchte ich nach Dokumentation über ELF und fand information on version requirements.

Also mein neues Ziel war, Referenzen auf in Verweise auf etwas anderes zu transformieren. Es schien vernünftig, dass ich einfach Strukturen überschreiben konnte, die sich auf mit den Strukturen bezogen, die sich auf eine niedrigere Version bezogen, wie 2.1. Am Ende, nach einigem Versuch und Irrtum, fand ich gerade das Bearbeiten der richtigen Elfxx_Vernaux (es?) In .gnu.version_r war ausreichend, aber Vorsicht Hacker, schätze ich.

Der .gnu.version_r Abschnitt ist eine Liste von 16-Byte Elfxx_Verneed s und 16-Byte Elfxx_Vernaux es.Jedem Eintrag Elfxx_Verneed folgt der zugehörige Eintrag Elfxx_Vernaux es. Soweit ich sagen konnte, ist vn_file tatsächlich, wie viele assoziierte Elfxx_Vernaux es gibt, obwohl die Dokumente sagen number of associated verneed array entries. Es könnte jedoch nur ein Missverständnis sein.

Also, um die Bearbeitungen zu starten, schauen wir uns einige Informationen von readelf -V an. Ich habe Teile herausgeschnitten, die uns nicht interessieren.

$ readelf -V mybinary 
<snip stuff before .gnu.version_r> 
Version needs section '.gnu.version_r' contains 5 entries: 
Addr: 0x00000000000021ac Offset: 0x0021ac Link: 4 (.dynstr) 
<snip libraries that don't refer to GLIBC_2.15> 
    0x00c0: Version: 1 File: libc.so.6 Cnt: 10 
    0x00d0: Name: GLIBC_2.3 Flags: none Version: 19 
    0x00e0: Name: GLIBC_2.7 Flags: none Version: 16 
    0x00f0: Name: GLIBC_2.2 Flags: none Version: 15 
    0x0100: Name: GLIBC_2.2.4 Flags: none Version: 14 
    0x0110: Name: GLIBC_2.1.3 Flags: none Version: 13 
    0x0120: Name: GLIBC_2.15 Flags: none Version: 12 
    0x0130: Name: GLIBC_2.4 Flags: none Version: 10 
    0x0140: Name: GLIBC_2.1 Flags: none Version: 9 
    0x0150: Name: GLIBC_2.3.4 Flags: none Version: 4 
    0x0160: Name: GLIBC_2.0 Flags: none Version: 2 

Daraus sehen wir, dass der Abschnitt in 0x21ac beginnt. Jede aufgelistete Datei hat einen Elfxx_Verneed gefolgt von einem Elfxx_Vernaux für jeden der Untereinträge (wie GLIBC_2.3). Ich nehme an, dass die Reihenfolge der Informationen in der Ausgabe immer der Reihenfolge in der Datei entspricht, da readelf nur die Strukturen ausgibt. Hier ist meine gesamte.gnu.version_r Abschnitt.

000021A0           01 00 02 00 
000021B0 A3 0C 00 00 10 00 00 00 30 00 00 00 11 69 69 0D 
000021C0 00 00 11 00 32 0D 00 00 10 00 00 00 10 69 69 0D 
000021D0 00 00 0B 00 3C 0D 00 00 00 00 00 00 01 00 02 00 
000021E0 BE 0C 00 00 10 00 00 00 30 00 00 00 13 69 69 0D 
000021F0 00 00 08 00 46 0D 00 00 10 00 00 00 10 69 69 0D 
00002200 00 00 07 00 3C 0D 00 00 00 00 00 00 01 00 02 00 
00002210 99 0C 00 00 10 00 00 00 30 00 00 00 11 69 69 0D 
00002220 00 00 06 00 32 0D 00 00 10 00 00 00 10 69 69 0D 
00002230 00 00 05 00 3C 0D 00 00 00 00 00 00 01 00 02 00 
00002240 AE 0C 00 00 10 00 00 00 30 00 00 00 11 69 69 0D 
00002250 00 00 12 00 32 0D 00 00 10 00 00 00 10 69 69 0D 
00002260 00 00 03 00 3C 0D 00 00 00 00 00 00 01 00 0A 00 
00002270 FF 0C 00 00 10 00 00 00 00 00 00 00 13 69 69 0D 
00002280 00 00 13 00 46 0D 00 00 10 00 00 00 17 69 69 0D 
00002290 00 00 10 00 50 0D 00 00 10 00 00 00 12 69 69 0D 
000022A0 00 00 0F 00 5A 0D 00 00 10 00 00 00 74 1A 69 09 
000022B0 00 00 0E 00 64 0D 00 00 10 00 00 00 73 1F 69 09 
000022C0 00 00 0D 00 70 0D 00 00 10 00 00 00 95 91 96 06 
000022D0 00 00 0C 00 7C 0D 00 00 10 00 00 00 14 69 69 0D 
000022E0 00 00 0A 00 87 0D 00 00 10 00 00 00 11 69 69 0D 
000022F0 00 00 09 00 32 0D 00 00 10 00 00 00 74 19 69 09 
00002300 00 00 04 00 91 0D 00 00 10 00 00 00 10 69 69 0D 
00002310 00 00 02 00 3C 0D 00 00 00 00 00 00 

Um kurz über die Struktur zu sprechen hier, es beginnt mit einem Elfxx_Verneed aus. Laut der Dokumentation können wir sehen, es wird 2 Elfxx_Vernaux es, ein Offset 16 Bytes, und der nächste Elfxx_Verneed ist Offset 48 Bytes. Diese Offsets sind vom Anfang der aktuellen Struktur. Es sieht aus wie technisch die verbundenen Elfxx_Vernaux es möglicherweise nicht angrenzend nach der aktuellen Elfxx_Verneed aber es war eigentlich so in allen Dateien stocherte ich in.

Von diesem können wir die Datei finden, die wir wollen (libc.so.6) auf ein paar verschiedene Arten. Querverweis auf die Zeichenfolge (die ich nicht bekommen werde), finden Sie die Elfxx_Verneed mit einer Zählung von 0A 00 (10, passend zu unserem readelf Ausgang oben), oder finden Sie die letzte Elfxx_Verneed, da es die letzte readelf Ausgabe ist. In jedem Fall ist der richtige für meine Datei unter 0x226C. Seine erste Elfxx_Vernaux beginnt bei 0x227C.

Wir wollen die Elfxx_Vernaux mit einer Version von (12, wieder passend zu unserem readelf Ausgang oben) finden. Wir sehen die Elfxx_Vernaux, die passt, ist 0x22CC und die gesamte Struktur ist 95 91 96 06 00 00 0C 00 7C 0D 00 00 10 00 00 00. Wir werden die ersten 12 Bytes überschreiben, um den Offset alleine zu lassen. Wir modifizieren nur die Daten, bewegen uns nicht um die Strukturen herum.

Um die Daten zum Überschreiben mit auszuwählen, kopieren wir es einfach von einem anderen Elfxx_Vernaux für eine Version von glibc, die wir erfüllen können. Ich wählte eine für 2.1, die unter 0x22EC in meiner Datei ist, mit den Daten 11 69 69 0D 00 00 09 00 32 0D 00 00 10 00 00 00. Also nimm die ersten 12 Bytes davon und überschreibe die ersten 12 Bytes oben, und das war's für die Hex-Bearbeitung.

Natürlich könnten Sie mehrere Referenzen haben, mit denen Sie umgehen müssen. Ihr Programm könnte mehrere Binärdateien zum Bearbeiten haben.

An diesem Punkt wird unser Programm immer noch nicht ausgeführt. Aber statt etwas wie GLIBC_2.15 not found gesagt werden, sollte es über fehlende __fdelt_chk beschweren. Jetzt machen wir die Shim und LD_PRELOAD in der Frage beschrieben, außer, anstatt unsere Implementierung als 2.15 Versionierung, verwenden wir die Version, die wir während der Hex-Bearbeitung ausgewählt. An diesem Punkt sollte das Programm laufen.

Diese Methode hängt davon ab, eine Implementierung für alles, was fehlt, bereitstellen zu können. Unsere __fdelt_chk ist extrem einfach, aber ich bezweifle nicht, dass in einigen Fällen die Bereitstellung einer Implementierung schwieriger sein könnte, als nur die libc des Systems zu aktualisieren.

+0

Danke für den Link! Ihre Lösungen klingen wie ein Hack. Können Sie Hex-Daten vorher und nachher zeigen und uns detailliert zeigen, wie man Offsets findet? – osgx

+2

Erweitete meine Antwort. Es ist definitiv ein Hack, heh. – Fyren

+0

Ich habe diese Antwort akzeptiert, nicht weil sie perfekt passt, sondern weil sie die einfachste Lösung im Detail beschreibt, und ich denke, es gibt keine andere Möglichkeit, dies zu tun. Danke :) –

6

Für was es wert ist, ist die __fdelt_chk-Funktion mit der FORTIFY_SOURCE-Funktion verwandt, die in glibc 2.15 hinzugefügt wurde. Es ermöglicht die Überprüfung der Kompilierungszeit und der Laufzeit auf Pufferüberläufe.

Wenn Sie waren in der Lage die folgenden CFLAGS hinzugefügt neu kompilieren mit, eine rückwärtskompatibel binäre ohne die zusätzliche Überprüfung bauen würde:

-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 
+1

Leider hat der -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE = 0 Vorschlag das __fdelt_chk Symbol nicht entfernt. Ich verbinde auch mit Pthreads, die es möglicherweise verwenden können. – Matt

+0

FWIW, löste das Problem für mich nach Einstellungen der Flags, dann ersetzen Readline, und dann das: https://forums.gentoo.org/viewtopic-p-7807512.html?sid=72aae1be7e1c8994989b783fe1462ee8 –

+0

funktioniert für mich, entfernt __fdelt_chk @ GLIBC_2.15 und [email protected]_2.11 – zhaorufei

Verwandte Themen