Digital > Fefes Blog 2.0 > a4888faa
  Leserreporter: Wer schöne Verschwörungslinks für mich hat: ab an felix-bloginput (at) fefe.de!
[zurück][ältere Posting][neuere Posting]  Sonntag, 04 Februar 2018 | Blog: 2 | No: 40146     feed-image

Cool!

Gerade sind frisch eine neue Binutils-Version und eine neue glibc-Version rausgekommen, und gcc 8 scheint auch fast fertig zu sein. Eines der (aus meiner Sicht) wichtigsten Features von gcc 8 ist der Support für "static PIE". PIE steht für Position Independent Executables. Normalerweise sind Binaries (Programme) auf eine bestimmte Adresse im Speicher hin gebaut. Jeder Prozess hat einen virtuellen Adressraum, und in dem liegen Binaries standardmäßig bei 400000 und ihre Daten ab 600000. Das war historisch nie ein Problem und hat auch Vorteile, weil man dann nämlich im Maschinencode Dinge vereinfachen kann, weil man immer weiß, wo was ist.
Auf der anderen Seite wissen dann auch Hacker, wo was ist. Und weil die Softwareentwicklungsbranche vor vielen Jahren entschieden hat, dass sauber Programmieren zu schwer ist und wir lieber Hacker ärgern wollen, ging die Entwicklung dann dahin, dass man das Programm halt bei jedem Programmstart woanders hin tut im Adressraum. Das nennt sich dann PIE.
Technisch läuft das über einen gruseligen Hack im ELF-Dateiformat, denn das kennt nur Binary (Programm, an statischer Adresse) und Shared Object (Shared Library, an dynamischer Adresse). Das ist schlicht nicht vorgesehen, dass ein Programm an einer zufälligen Adresse geladen wird. Selbst wenn man den Code so formuliert, dass das ginge (was bei Intel/AMD bei 64-bit-Programmen viel einfacher und effizienter geworden ist als bei 32-bit-Programmen, weil der Befehlssatz da ein anderer ist, der darauf ausgelegt ist). Kurz gesagt gibt es bei 64-bit-Programmen eigentlich keine Effizienz-Ausrede mehr, um die nicht positionsunabhängig zu machen. Es gibt natürlich, wenn man genau hinguckt, doch einen Performancenachteil, aber den will ich hier mal außen vor lassen :-)
Der Hack ist jetzt so, dass man in der Datei einträgt, es sei eine Shared Library, kein Programm. Der Kernel lädt die trotzdem und alles ist gut. Das ist leider ein Opt-In-Ding. Wenn ihr unter Linux Software baut, tut mal bitte immer schön -fPIE auf die Compiler-Kommandozeile.
Nun bin ich aber nicht an regulären Binaries interessiert, sondern an statischen Binaries (das ist die Zielgruppe für meine libc). Und der Hack mit dem PIE geht zwar vom Dateiformat her auch bei statisch gelinkten Programmen, aber in der Praxis halt nicht. Ich habe mal ein paar Tage lang versucht, das doch zum Laufen zu kriegen, und bin am Ende gescheitert. Es geht aber prinzipiell. Das weiß ich, weil es jemand anderes geschafft hat: Der Autor der musl-libc. Der gute Mann hat irgendwann bei GNU ein paar Bugs eingetragen, ob es nicht toll wäre, wenn man da nicht so gruselig hacken müsste, wie er es getan hat. Und gcc 8 hat jetzt die Option -static-pie, die genau das tun soll.
Die wollte ich also auch direkt mal ausprobieren, und baute erstmal die neuen binutils, dann den neuen gcc, und jetzt die neue glibc. Und dann fiel mir auf, dass plötzlich meine dietlibc-Binaries größer waren. /bin/true macht im Wesentlichen nichts und sollte eigentlich nur ein paar Bytes groß sein (ein paar ELF-Header brauchen Binaries schon, aber so Größenordnung 200 Bytes ist eigentlich realistisch). War es aber nicht, sondern es war plötzlich über 4k groß. Gut, es war auch vorher weit davon entfernt, weil die dietlibc inzwischen eben eine Menge anderen Kram supportet, der die Startup-Code größer macht. Z.B. den Stack Protector initialisieren, und Thread Local Storage. Aber das true-Binary hätte trotzdem deutlich unter 4k sein müssen.
Ich habe also ein bisschen rumgeguckt, und es stellte sich raus, dass das nur mit dem binutils-bfd-ld so war. binutils ist das Paket unter Linux, aus dem der Assembler und der Linker kommen. binutils hat aber zwei Linker. Den alten mit bfd (der fetten Abstraktionsschicht von binutils) und den neuen, in C++ geschriebenen, der weniger kann, das dafür angeblich besser: GNU gold. Den habe ich normalerweise nicht im Einsatz, weil der bei mir vor Jahren mal Probleme gemacht hat beim Firefox-Linken. Egal. Mit dem gold ist das true-Binary nur 1,3 KB groß. Ich habe also mal reingeguckt und fand in dem statischen Binary von dem bfd-ld eine PLT. PLT steht für Procedure Linkage Table und ist für die Zusammenarbeit (und Umbiegbarkeit mittels LD_PRELOAD) von Shared Libraries da. Das hat in einem statischen Binary nichts verloren. Ich habe mal einen Bug aufgemacht bei binutils.
Ich stellte also auf GNU gold um, und wollte fluchs die neue glibc bauen — aber die baut mit ihrem neuen static-pie-Support für gcc 8 nicht mit gold, nur mit dem bfd-ld. *SEUFZ*
Aber jetzt wo die Infrastruktur da Support für hat, hoffe ich mal, dass auch für die dietlibc static PIE nur noch eine Frage der Zeit ist, möglichst kurzer Zeit. Das will man schon haben, besonders auf 64-bit-x86-Systemen, wo das kaum noch was kostet gegenüber Nicht-PIE.
Aus Frust hab ich jetzt mal true und false in Assembler gehackt für x86/x64 :-)

Update: Stellt sich raus: static pie mit gcc 8 funktioniert auf Anhieb, auch mit dietlibc. Cool!

Update: Gestern Bug gefiled, heute Patch da. Binutils rockt!

[zurück] [ältere Posting][neuere Posting]
[zurück] [ältere Posting][neuere Posting]

Fefes Latest Youtube Video Links