Open Source im professionellen Einsatz

Qt-Bibliothek: Zwei Sicherheitslücken

Qt-Bibliothek: Zwei Sicherheitslücken

In der Qt-Bibliothek sind zwei Schwachstellen (hier und hier) entdeckt worden. Sie lassen sich von einem entfernten Angreifer ausnutzen, um Befehle mit den Rechten des Anwenders auszuführen. Die Attacken sind entweder über speziell konstruierte Font-Dateien oder mit Hilfe einer geschickt zusammengebauten TIFF-Bilddatei möglich.

Die Qt-Bibliothek verwendet als Layout-/Shaping-Engine für OpenType-Schriften die 3rd-Party-Bibliothek HarfBuzz. Diese kommt auch in der Pango-Bibliothek zum Einsatz, außerdem als Standalone-Bibliothek in den Browsern Firefox und Chromium. Eine kürzlich entdeckte Sicherheitslücke in HarfBuzz hat zur Folge, dass ein entfernter Angreifer Befehle mit den Rechten des Anwenders ausführen kann. Ursache für das Problem ist eine Buffer-Overflow-Schwachstelle in den Routinen zum Verarbeiten von Font-Dateien, die ein entfernter Angreifer ausnutzen kann, indem er seinem Opfer eine geschickt konstruierte Schriftartdatei unterschiebt.

Red Hat hat für diese Schwachstelle ebenfalls ein Security-Advisory herausgegeben, welches sich speziell auf die Anwendung Frysk bezieht, die ebenfalls HarfBuzz verwendet. Dort besteht die Gefahr darin, dass ein Angreifer eine Font-Datei installiert, die dann beim Aufrufen von Frysk dazu führt, dass die vom Angreifer gewünschten Befehle ausgeführt werden.

Der hierfür verantwortliche Programmierfehler befindet sich in der Datei "src/3rdparty/harfbuzz/src/harfbuzz-gpos.c" und dort in der Funktion "Lookup_MarkMarkPos()", die beim Verarbeiten von Font-Dateien von der ebenfalls in "harfbuzz-gpos.c" implementierten Funktion "HB_GPOS_Load_SubTable()" aufgerufen wird:

HB_INTERNAL HB_Error _HB_GPOS_Load_SubTable( HB_GPOS_SubTable* st, HB_Stream stream, HB_UShort lookup_type)
{
  switch ( lookup_type ) {
    ...
    case HB_GPOS_LOOKUP_MARKBASE:       return Load_MarkBasePos( st, stream );
    ...
    default:                            return ERR(HB_Err_Invalid_SubTable_Format);
  }
}

Diese Funktion wird wiederum von den Funktionen "Load_SubTable()" und "Load_Lookup()" in der Datei "harfbuzz-open.c" aufgerufen. Die "Lookup_MarkMarkPos()"-Funktion selbst arbeitet unter anderem auf der Struktur "HB_Buffer", die in der Header-Datei "harfbuzz-buffer.h" definiert ist.

typedef struct HB_BufferRec_{ 
  HB_UInt    allocated;
  HB_UInt    in_length;
  HB_UInt    out_length;
  HB_UInt    in_pos;
  HB_UInt    out_pos;
  HB_GlyphItem  in_string;
  HB_GlyphItem  out_string;
  HB_GlyphItem  alt_string;
  HB_Position   positions;
  HB_UShort      max_ligID;
  HB_Bool       separate_out;
} HB_BufferRec, *HB_Buffer;

Sie stellt eine allgemeine Puffer-Struktur mit Meta-Information dar:

i = 1;
j = buffer->in_pos - 1;

while ( i <= buffer->in_pos )
{
  error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ), &property );
  if ( error )
    return error;
  ...
  i++;
  j--;
}

Diese While-Schleife terminiert, sobald i größer ist als "buffer->in_pos". Allerdings haben die Programmierer dabei vergessen, am Ende der Schleife noch zu überprüfen, ob i größer ist als "buffer->in_pos", was zu einem Buffer Overflow führen kann. Dies lässt sich korrigieren, indem man am Ende der Schleife einfach den folgenden If-Block hinzufügt:

if (i > buffer->in_pos)
 return HB_Err_Not_Covered;

Dadurch werden mögliche Buffer Overflows aufgrund spezieller Font-Dateien vermieden, und die Attacke ist nicht mehr möglich.

TIFF-Schwachstelle

 

Eine weitere Schwachstelle befindet sich in der Qt-Bibliothek selbst, in der Quelltextdatei "src/gui/image/qtiffhandler.cpp". Sie tritt beim Verarbeiten bestimmter TIFF-Dateien auf. Das Problem betrifft TIFF-Dateien mit gesetztem "TIFFTAG_SAMPLESPERPIXEL"-Tag. Dieses Tag spezifiziert die Anzahl der Komponenten pro Pixel im Bild. Ein Graustufen-Bild hat hierbei einen Wert von 1, ein RGB-Bild einen Wert von 3. Es ist auch möglich, mehr als 3 Komponenten zu kodieren, wobei dann "ExtraSamples" angibt, was in den zusätzlichen Kanälen abgelegt ist.

Diese Sicherheitslücke tritt auf, falls eine TIFF-Datei mit folgenden Tags verarbeitet werden soll:

TIFFTAG_BITSPERSAMPLE = 8
TIFFTAG_SAMPLESPERPIXEL = 2
TIFFTAG_PHOTOMETRIC = PHOTOMETRIC_MINISBLACK

"TIFFTAG_BITSPERSAMPLE" gibt an, wie viele Bits pro Komponente benötigt werden. Für ein 24-Bit-RGB-Bild benötigt so jeder Kanal beispielsweise 8 Bit. Das "TIFFTAG_PHOTOMETRIC"-Tag spezifiziert den Farbraum der Bilddatei genauer, wobei hier mehrere Werte möglich sind, beispielsweise:

0 = WhiteIsZero. For bilevel and grayscale images: 0 is imaged as white.
1 = BlackIsZero. For bilevel and grayscale images: 0 is imaged as black.
2 = RGB. RGB value of (0,0,0) represents black, and (255,255,255) represents white, assuming 8-bit components. The components are stored in the indicated order: first Red, then Green, then Blue.

"PHOTOMETRIC_MINISBLACK" ist eine im Qt-Code definierte Konstante und steht für 1, analog steht "PHOTOMETRIC_MINISWHITE" für 0. Der angegebene Wert für "TIFFTAG_SAMPLESPERPIXEL" ergibt allerdings wenig Sinn, da "TIFFTAG_PHOTOMETRIC" für Graustufen-Bilder verwendet wird, wo nur ein Sample pro Pixel benötigt wird. Und genau dies bringt den TIFF-Code in der Qt-Bibliothek durcheinander, denn dieser geht davon aus, dass in diesem Fall "TIFFTAG_SAMPLESPERPIXEL" auf 1 gesetzt ist und prüft dies nicht explizit. Hat ein Angreifer diesen Wert wie im obigen Beispiel jedoch tatsächlich auf einen Wert ungleich 1 gesetzt, führt dies zu Problemen im Speicher, da der Code nur Speicher für ein Sample pro Pixel alloziert.

Das Patch für diese Schwachstelle besteht darin, zusätzlich immer noch den Wert "TIFFTAG_SAMPLESPERPIXEL" zu überprüfen und den obigen Fall als unzulässige Eingabe abzulehnen. Das folgende Patch bewerkstelligt dies und stellt damit sicher, dass derartige TIFF-Dateien keinen Schaden mehr anrichten können:

  uint16 bitPerSample;
  if (!TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitPerSample))
   bitPerSample = 1;
+ uint16 samplesPerPixel; // they may be e.g. grayscale with 2 samples per pixel
+ if (!TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel))
+  samplesPerPixel = 1;
 
  bool grayscale = photometric == PHOTOMETRIC_MINISBLACK || photometric == PHOTOMETRIC_MINISWHITE;
- if (grayscale && bitPerSample == 1) {
+ if (grayscale && bitPerSample == 1 && samplesPerPixel == 1) {
   if (image->size() != QSize(width, height) || image->format() != QImage::Format_Mono)
    *image = QImage(width, height, QImage::Format_Mono);
   QVector<QRgb> colortable(2);
   ... 

- if ((grayscale || photometric == PHOTOMETRIC_PALETTE) && bitPerSample == 8) {
+ if ((grayscale || photometric == PHOTOMETRIC_PALETTE) && bitPerSample == 8 && samplesPerPixel == 1) {
   ...   
comments powered by Disqus

Stellenmarkt

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.