Forum: PC-Programmierung Feedback GCC Spectre LFENCE patch


von Stephan B. (matrixstorm)


Angehängte Dateien:

Lesenswert?

Hallo Community.

Anbei findet ihr meine cruden gcc-Patches. (gcc_spectre_v1_rev2.patch)
Natürlich sind diese enorm verbesserungswürdig - zumindest ich will aber 
erstmal wieder etwas sichereres haben...
...natürlich stehen auch entsprechende Kernelpatches an...

Ich habe noch einige bedingte Maschinenbefehle an spekulativer 
Ausführung blockieren lassen.
Ggf. kommen irgendwann mal optimierte Patchserien gegen Spectre V1 
online, oder das hier wird besser optimiert...

Die Patche sind alle auf den aktuellen gcc 7.2 anzuwenden: 
https://ftp.gnu.org/gnu/gcc/gcc-7.2.0/gcc-7.2.0.tar.xz

Zum Compilieren vom gcc werden 3 weitere externe Pakete gebraucht:
https://ftp.gnu.org/gnu/gmp/gmp-6.1.2.tar.xz
http://www.mpfr.org/mpfr-3.1.5/mpfr-3.1.5.tar.xz
https://ftp.gnu.org/gnu/mpc/mpc-1.0.3.tar.gz

Ausserdem muss zuvor eine moderne binutils gebaut werden:
https://ftp.gnu.org/gnu/binutils/binutils-2.29.tar.xz

Bitte beachtet, das ihr zuerst einen morderneren gcc benötigt, um mein 
installiertes Patch compilieren zu können. (Die meisten Distributionen 
liefern ggc 4.9 aus: gcc --version)
Am besten erstmal den 7.2 ohne Patches bauen und in einen Ordner eurer 
Wahl installieren lassen.
Dann Pfad umbiegen (gcc --version auf 7.2.0 checken) und dann Patches 
installieren und das ganze mit den frischen Compiler nochmal 
compilieren.

Ganz am Ende am besten alles ein finales mal Übersetzten...

(Bauanleitung am Ende des Posts)

Mit dem neuen Compiler könnt ihr dann auch (unabhängig von den lfence 
Barrieren) "-mindirect-branch=thunk -mfunction-return=thun" zur 
Mitigation v. Spectre V2 aktivieren: 
https://support.google.com/faqs/answer/7625886

gcc -mindirect-branch=thunk-extern -mfunction-return=thunk  -o hello 
hello.c

produziert:
# objdump -M intel -d hello
[...]
1
000000000040050a <main>:
2
  40050a:       55                      push   rbp
3
  40050b:       48 89 e5                mov    rbp,rsp
4
  40050e:       48 83 ec 10             sub    rsp,0x10
5
  400512:       89 7d fc                mov    DWORD PTR [rbp-0x4],edi
6
  400515:       48 89 75 f0             mov    QWORD PTR [rbp-0x10],rsi
7
  400519:       83 7d fc 00             cmp    DWORD PTR [rbp-0x4],0x0
8
  40051d:       0f ae e8                lfence                                   <-----
9
  400520:       7e 0a                   jle    40052c <main+0x22>
10
  400522:       bf d4 05 40 00          mov    edi,0x4005d4
11
  400527:       e8 b4 fe ff ff          call   4003e0 <puts@plt>
12
  40052c:       b8 00 00 00 00          mov    eax,0x0
13
  400531:       c9                      leave  
14
  400532:       e9 00 00 00 00          jmp    400537 <__x86_indirect_thunk>     <-----
[...]

Wogegen der alte Compiler /usr/bin/gcc -o hello  hello.c
produziert:
# objdump -M intel -d hello
[...]
1
000000000400526 <main>:
2
  400526:       55                      push   rbp
3
  400527:       48 89 e5                mov    rbp,rsp
4
  40052a:       48 83 ec 10             sub    rsp,0x10
5
  40052e:       89 7d fc                mov    DWORD PTR [rbp-0x4],edi
6
  400531:       48 89 75 f0             mov    QWORD PTR [rbp-0x10],rsi
7
  400535:       83 7d fc 00             cmp    DWORD PTR [rbp-0x4],0x0
8
  400539:       7e 0a                   jle    400545 <main+0x1f>
9
  40053b:       bf d4 05 40 00          mov    edi,0x4005d4
10
  400540:       e8 bb fe ff ff          call   400400 <puts@plt>
11
  400545:       b8 00 00 00 00          mov    eax,0x0
12
  40054a:       c9                      leave  
13
  40054b:       c3                      ret    
14
  40054c:       0f 1f 40 00             nop    DWORD PTR [rax+0x0]
[...]





Bauanleitung nach /tmp/install

 1) mkdir -p /tmp/sources
 2) cd /tmp/sources
 3) xzcat binutils-2.29.tar.xz | tar -x
 4) cd binutils-2.29
 5) mkdir build
 6) cd build
 7) ../configure --prefix=/tmp/install/ --disable-nls --disable-werror
 8) make -j<AnzahlDerCPUKerne>
 9) make install
10) cd /tmp/sources
11) xzcat gcc-7.2.0.tar.xz | tar -x
12) cd gcc-7.2.0
13) xzcat gmp-6.1.2.tar.xz | tar -x
14) mv gmp-6.1.2/ gmp
15) xzcat mpfr-3.1.5.tar.xz | tar -x
16) mv mpfr-3.1.5/ mpfr
17) zcat mpc-1.0.3.tar.gz | tar -x
18) mv mpc-1.0.3/ mpc
19) mkdir build
20) cd build
21) ./configure --prefix=/tmp/delme.gast/install/ --disable-werror 
--enable-languages=c,c++ --disable-multilib

(wenn der gcc auch 32Bit können soll - dann "--disable-multilib" 
weglassen)

22) make -j<AnzahlDerCPUKerne>                <-- das dauert ne Weile ?
23) make install

24) export PATH="/tmp/install/bin/:${PATH}:/tmp/install/bin/"
25) gcc --version
gcc (GCC) 7.2.0
Copyright (C) 2017 Free Software Foundation, Inc.
Dies ist freie Software; die Kopierbedingungen stehen in den Quellen. Es
gibt KEINE Garantie; auch nicht für MARKTGÄNGIGKEIT oder FÜR SPEZIELLE 
ZWECKE.

26) cd ..
27) xzcat gcc-7_2_0-retpoline-20180107.tar.xz | tar -x
28) cat ./gcc-7_2_0-retpoline-20180107/*.patch | patch -Np1
29) cat gcc_spectre_v1_rev2.patch | patch -Np1
30) cd build

31) make -j<AnzahlDerCPUKerne>
32) make install

-fertig ist der neue Compiler, jetzt nocheinmal komplett übersetzten um 
alle c-libs anzupassen...

: Bearbeitet durch User
Beitrag #5279653 wurde vom Autor gelöscht.
von Stephan B. (matrixstorm)


Angehängte Dateien:

Lesenswert?

...einige bedingte fcmovs vergessen...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Stephan B. schrieb:
> zumindest ich will aber erstmal wieder etwas sichereres haben...

Ist ein Patch auf der Ebene denn überhaupt sinnvoll?

Es handelt sich ja nicht um einen Silicon-Bug (in dem Sinne, dass 
falscher Code generiert wird wie z.B. beim FDIV).  Sondern er 
ermöglicht, abhängig vom OS, Speicherbereiche zu "lesen", die man 
eigentlich nicht lesen dürfen sollte.

> With this patch performance might drop by more than 75% !!

:-)

So ein Patch nimmt einem also nur die Möglichkeit, selbst einen solchen 
Angriff zu starten — den mal als "good boy" natürlich niemals machen 
würde.  Und als "bad boy" kann man (Inline) Assembler o.ä. verwenden.

> ...natürlich stehen auch entsprechende Kernelpatches an...

Auf den GCC Mailing-Listen werden auch Patches diskutiert, aber vor 
allem auch Built-ins, die zur Unterstützung in OS-Code, VMs etc. gezielt 
eingesetzt werden können.

https://gcc.gnu.org/ml/gcc/2018-01/msg00029.html

> Ich habe noch einige bedingte Maschinenbefehle an spekulativer
> Ausführung blockieren lassen.

Müssen da nicht auch die Instruktionslängen angepasst werden?

> Die Patche sind alle auf den aktuellen gcc 7.2 anzuwenden:
> https://ftp.gnu.org/gnu/gcc/gcc-7.2.0/gcc-7.2.0.tar.xz
>
> Zum Compilieren vom gcc werden 3 weitere externe Pakete gebraucht:
> https://ftp.gnu.org/gnu/gmp/gmp-6.1.2.tar.xz
> http://www.mpfr.org/mpfr-3.1.5/mpfr-3.1.5.tar.xz
> https://ftp.gnu.org/gnu/mpc/mpc-1.0.3.tar.gz

Meist will man auch ISL.  Am einfachsten bekommt man diese Libs in der 
richtigen Version, unabhängig von evtl. vorhandenen Host-Versionen per 
in-tree Build mit
1
./contrib/download_prerequisites

> Ausserdem muss zuvor eine moderne binutils gebaut werden:
> https://ftp.gnu.org/gnu/binutils/binutils-2.29.tar.xz
>
> Bitte beachtet, das ihr zuerst einen morderneren gcc benötigt, um mein
> installiertes Patch compilieren zu können. (Die meisten Distributionen
> liefern ggc 4.9 aus: gcc --version)
> Am besten erstmal den 7.2 ohne Patches bauen und in einen Ordner eurer
> Wahl installieren lassen.

Huh?  Das macht ein Bootstrap doch automatisch?

> Bauanleitung nach /tmp/install
> [...]
> 11) xzcat gcc-7.2.0.tar.xz | tar -x
> 12) cd gcc-7.2.0
> 13) xzcat gmp-6.1.2.tar.xz | tar -x
> 14) mv gmp-6.1.2/ gmp
> 15) xzcat mpfr-3.1.5.tar.xz | tar -x
> 16) mv mpfr-3.1.5/ mpfr
> 17) zcat mpc-1.0.3.tar.gz | tar -x
> 18) mv mpc-1.0.3/ mpc

./contrib/download_prerequisites ist hier der empfohlene Weg

> 19) mkdir build
> 20) cd build
> 21) ./configure --prefix=/tmp/delme.gast/install/ --disable-werror
> --enable-languages=c,c++ --disable-multilib

configure innerhalb des Source-Tree wird von GCC nicht unterstützt. 
Evtl. beruhen deine Probleme beim Generieren darauf?  Jedenfalls würde 
ich von nicht-unterstützten Konfigurationen absehen: wozu möglichen 
Ärger wenn man ihne einfach ausschließen kann...

> 24) export PATH="/tmp/install/bin/:${PATH}:/tmp/install/bin/"

Wozu 2× /tmp/install/bin/?

von Stephan B. (matrixstorm)


Lesenswert?

Hallo Johann L., schön das jemand antwortet.

Johann L. schrieb:
> Stephan B. schrieb:
>> zumindest ich will aber erstmal wieder etwas sichereres haben...
>
> Ist ein Patch auf der Ebene denn überhaupt sinnvoll?
> [...]

Ich habe das original "Spectre"-paper so verstanden, das für eine 
halbwegs abdeckende Mitigation des Szenarios "conditional branch 
misprediction" (Spectre V1) auch alle Software im Userspace neu 
übersetzt werden muss.
Seite 11, Kapitel 7 Abs.2 "The problem of inserting speculative 
execution blocking [...]" ist sogar recht spezifisch darüber 
("[...]Insertion in security-critical routines alone is not sufficient, 
[...]").

Da es dafür IMHO an compiler patches mangelt, habe ich mal den "Hammer" 
angesetzt.


> So ein Patch nimmt einem also nur die Möglichkeit, selbst einen solchen
> Angriff zu starten — den mal als "good boy" natürlich niemals machen
> würde.  Und als "bad boy" kann man (Inline) Assembler o.ä. verwenden.

Nein, ich denke das ist anders zu verstehen.
Spectre V1 benötigt sog. "gadjets" im -->Fremdcode<-- im Fremdcontext 
zum exploiten.
Wenn ein Angreifer also sich selbst in ASM implementiert (oder anders 
übersetzt) nützt ihm das wohl nichts.


> Auf den GCC Mailing-Listen werden auch Patches diskutiert, aber vor
> allem auch Built-ins, die zur Unterstützung in OS-Code, VMs etc. gezielt
> eingesetzt werden können.

eben.
Gibt es schon irgendwo ein Wort darüber was mit dem restl. Userspace 
ist? Vielleicht hat das paper ja unrecht oder übertreibt? (Oder ich was 
falsch verstanden?)
Aber auch Intel spricht in seinem Whitepaper von "For the bounds check 
bypass method, Intel’s mitigation strategy is focused on software 
modifications. [...]"



> Müssen da nicht auch die Instruktionslängen angepasst werden?

Das ist eine hervorragende Frage: Ich bin nicht sicher. Hast du eine 
Empfehlung?
Der gcc soll das lfence eigentlich nicht mit dem Sprung assoziieren.
Ich nutze nur die Ausgabe um es per huckepack mit in den ASM Code 
einzufügen.
Bisher scheint alles übersetzte auch gleichermassen zu funktionieren. 
(Auch Kernel...)

> [...]
>
1
./contrib/download_prerequisites
> [...]
> Huh?  Das macht ein Bootstrap doch automatisch?

OK - ich hatte mich an LFS orientiert.
funktioniert aber auch so.

>> 19) mkdir build
>> 20) cd build
>> 21) ./configure --prefix=/tmp/delme.gast/install/ --disable-werror
>> --enable-languages=c,c++ --disable-multilib
>
> configure innerhalb des Source-Tree wird von GCC nicht unterstützt.
> Evtl. beruhen deine Probleme beim Generieren darauf?  Jedenfalls würde
> ich von nicht-unterstützten Konfigurationen absehen: wozu möglichen
> Ärger wenn man ihne einfach ausschließen kann...

Vor dem configure fehlt ein Punkt: "../configure [...]"
Sorry Tippfehler.


Danke für deine Anmerkungen und sorry für meine gcc-Unsicherheit.
Normalerweise mach ich weniger am gcc rum - und nur jetzt gerade aus der 
Not heraus.

MfG Stephan

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Stephan B. schrieb:
> Hallo Johann L., schön das jemand antwortet.
>
> Johann L. schrieb:
>> Stephan B. schrieb:
>>> zumindest ich will aber erstmal wieder etwas sichereres haben...
>>
>> Ist ein Patch auf der Ebene denn überhaupt sinnvoll?
>> [...]
>
> Ich habe das original "Spectre"-paper so verstanden, das für eine
> halbwegs abdeckende Mitigation des Szenarios "conditional branch
> misprediction" (Spectre V1) auch alle Software im Userspace neu
> übersetzt werden muss.
> Seite 11, Kapitel 7 Abs.2 "The problem of inserting speculative
> execution blocking [...]" ist sogar recht spezifisch darüber
> ("[...]Insertion in security-critical routines alone is not sufficient,
> [...]").
>
> Da es dafür IMHO an compiler patches mangelt, habe ich mal den "Hammer"
> angesetzt.

Scheint dann doch etwas aufwändiger zu sein:

https://gcc.gnu.org/ml/gcc-patches/2018-01/msg00422.html

An Patches mangelt es also nicht.

> Aber auch Intel spricht in seinem Whitepaper von "For the bounds
> check bypass method, Intel’s mitigation strategy is focused on
> software modifications. [...]"

Ja klar, einen Silicon-Bug behebt man durch Software oder durch anderes 
Silizium.  Letzteres scheidet zumindest kurzfristig aus, und selbst 
langfristig wird noch ältere Hardware im Einsatz bleiben — auch weil 
das Problem softwareseitig behebbar ist (sieht zumindest momentan danach 
aus, auch wenn die Mühlen dann langsamer mahlen).

>> Müssen da nicht auch die Instruktionslängen angepasst werden?
>
> Das ist eine hervorragende Frage: Ich bin nicht sicher. Hast du eine
> Empfehlung?

Mit x86 kenn ich mich nicht soweit aus. Bei den meisten Targets gibt es 
falschen Code wenn Instruktionslängen zu klein sind, weil relative 
Sprünge nicht mehr passen.  Momentan kenn ich auch kein offizielles 
Target, das zu kurze Sprünge Relaxen kann, z.B. durch jumpity-jump, was 
aber erfordert, dass Assembler oder Linker im Code reinfutscheln.

> Der gcc soll das lfence eigentlich nicht mit dem Sprung assoziieren.

Genau das hast du aber getan :-)

> Ich nutze nur die Ausgabe um es per huckepack mit in den ASM Code
> einzufügen.

Der gcc weiß von dem lfence ja nix; es gehört zum asm-String der in 
final ausgegeben wird.  Und die ausgegebene Instruktion hat eine 
bestimmte (maximal-)Länge, die nun nicht mehr stimmt.

> Bisher scheint alles übersetzte auch gleichermassen zu funktionieren.

Ja größer die von der ISA unterstützten Offsets sind, desto seltener 
wird man das Probhlem sehen.  Es tritt ja nur an der Grenze der 
Gültigkeit auf, und die Wahrscheinlichkeit für eine bestimmte Sprungläge 
fällt grob exponentiell mit der Weite.

Hier ein Beispiel für so einen Bug in Aktion (nicht für x86):

https://gcc.gnu.org/PR72767

Es kracht nur bei bestimmten Sprungweiten, siehe Testfall am PR.


>> configure innerhalb des Source-Tree wird von GCC nicht unterstützt.
>> Evtl. beruhen deine Probleme beim Generieren darauf?  Jedenfalls würde
>> ich von nicht-unterstützten Konfigurationen absehen: wozu möglichen
>> Ärger wenn man ihne einfach ausschließen kann...
>
> Vor dem configure fehlt ein Punkt: "../configure [...]"

  "First, we highly recommend that GCC be built into a separate
   directory from the sources which does not reside within the
   source tree. [...] building where objdir is a subdirectory
   of srcdir is unsupported."

https://gcc.gnu.org/install/configure.html

von Stephan B. (matrixstorm)


Lesenswert?

Johann L. schrieb:
> Scheint dann doch etwas aufwändiger zu sein:
>
> https://gcc.gnu.org/ml/gcc-patches/2018-01/msg00422.html
>
> An Patches mangelt es also nicht.

Das sind nur die retpoline patches (siehe allererste Datei im ersten 
Post) gegen Spectre Variante 2.
Steht auch in der longmsg drin:

>This set of patches for GCC 8 mitigates variant #2 of the speculative execution 
vulnerabilities on x86 processors identified by CVE-2017-5715, aka Spectre.
>They convert indirect branches to call and return thunks to avoid speculative 
execution via indirect call and jmp.

Mir ist nichts bekannt das derzeit etwas gegen Variante 1 unternommen 
wird?

Johann L. schrieb:
> Mit x86 kenn ich mich nicht soweit aus. Bei den meisten Targets gibt es
> falschen Code wenn Instruktionslängen zu klein sind, weil relative
> Sprünge nicht mehr passen.  Momentan kenn ich auch kein offizielles
> Target, das zu kurze Sprünge Relaxen kann, z.B. durch jumpity-jump, was
> aber erfordert, dass Assembler oder Linker im Code reinfutscheln.
>
>> Der gcc soll das lfence eigentlich nicht mit dem Sprung assoziieren.
>
> Genau das hast du aber getan :-)

Sollte der lfence Inject tatsächlich für paranoide Menschen notwendig 
sein,
muss man vermutlich alle bedingten Opcodes per "define_insn_and_split" 
definieren. Dann kann man sich den Hack dann sparen.

Johann L. schrieb:
> https://gcc.gnu.org/install/configure.html

OK, zur Kenntniss genommen. Danke für den Link.
Scheinbar handhabt es LFS dann "unsupported": 
http://www.linuxfromscratch.org/lfs/view/stable/chapter05/gcc-pass1.html

MfG Stephan

von MaWin O. (Gast)


Lesenswert?

Ich finde es schon merkwürdig, dass du diesen Patch hier auf 
Mikrocontroller.net und nicht auf einer gcc-Liste präsentierst.

Warum sollte ich meinen GCC und mein System mit einem windigen Patch aus 
irgendeinem Forum compilieren?

von Stephan B. (matrixstorm)


Lesenswert?

Ma W. schrieb:
> Warum sollte ich meinen GCC und mein System mit einem windigen Patch aus
> irgendeinem Forum compilieren?

Brauchst du nicht und sollst du nicht.

Ich bin nicht sicher ob das einem Post in den gcc-Mailinglisten bereits 
wert ist - zumal die Leute dort erstmal allerhand anderes zu tun haben.

Hatte mir wohl mehr Feedback und Diskussion erhofft - nicht das nur alle 
darauf warten mit Patches bedient zu werden?

Schönen Abend noch.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Stephan B. schrieb:
> Ich bin nicht sicher ob das einem Post in den gcc-Mailinglisten bereits
> wert ist - zumal die Leute dort erstmal allerhand anderes zu tun haben.
>
> Hatte mir wohl mehr Feedback und Diskussion erhofft

Genau dieses Feedback und Diskussion wirst du aber — wenn überhaupt — 
genau dort finden; dort sind die Leute, die sich mit GCC auskennen, und 
in diesem Fall mit dem i386-Backend und der entsprechenden Harware bis 
in die kleinsten Details vertraut sind.

Sich in gcc-patches anzumelden (wo momentan über Änderungen diskutiert 
wird) ist also nicht die schlechteste Idee, und es kostet nur einen 
Click.

https://gcc.gnu.org/lists.html#subscribe

Momentan ist das Thema ja on-topic und wird heiß diskutiert.  Wenn du 
eine Frage zum aktuellen Patch o.ä. hast dann wird man bestimmt 
bereitwillig Auskunft geben; was aber bedingt dass man auch nachfragt 
:-)

von Nop (Gast)


Lesenswert?

Johann L. schrieb:
> Stephan B. schrieb:
>> With this patch performance might drop by more than 75% !!
>
> :-)

Klingt nach nem ziemlichen Killer, sofern man nicht den Spezialfall von 
einem Rechner hat, der ausschließlich für Anwendungen mit sehr niedrigen 
Anforderungen an die Performance, aber hohen an die Sicherheit dient.

Ist ja auch kein Wunder, denn viele memory barriers einzufüen killt ja 
jede Performance.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.