Linux-HFS-Implementierung: Stack Buffer Overflow

Der Linux-Kernel bietet Lese- und Schreibzugriff auf HFS-Dateisysteme. Eine Sicherheitslücke in der Linux-Implementierung von HFS hat zur Folge, dass ein Angreifer Befehle mit Root-Rechten ausführen kann.

Das Hierarchical File System (HFS) ist ein Dateisystem, das Apple für Mac OS entwickelt hat. HFS basiert technisch auf B*-Bäumen und unterstützt eine Dateisystem-Gesamtgröße von bis zu 2 TByte mit Dateinamen einer Maximallänge von 31 Zeichen. Einzelne Dateien können dabei bis zu 2 GByte groß sein, das System insgesamt kann maximal 65535 Dateien verwalten. Der Nachfolger HFS+ wurde 1998 von Apple vorgestellt und enthält zahlreiche Effizienzverbesserungen.

Die HFS-Implementierung im Linux-Kernel ist wie üblich im Quelltextverzeichnis “fs/” untergebracht, wobei alle HFS-relevanten Dateien im Unterverzeichnis “hfs/” liegen. Darin finden sich auch Routinen zum Konvertieren von Macintosh-Zeichensätzen in andere Encodings wie ASCII. Beispielsweise wandelt die Funktion “hfs_mac2asc()” Pascal-ähnliche Strings (mit führendem Längen-Byte) in Macintosh-Notation um. Hierbei wird “/” in “:” umgewandelt:

int hfs_mac2asc(struct super_block *sb, char *out, const struct hfs_name *in)
{ struct nls_table *nls_disk = HFS_SB(sb)->nls_disk; struct nls_table *nls_io = HFS_SB(sb)->nls_io; const char *src; char *dst; int srclen, dstlen, size; src = in->name; srclen = in->len; dst = out; dstlen = HFS_MAX_NAMELEN; if (nls_io) { wchar_t ch; while (srclen > 0) { if (nls_disk) { size = nls_disk->char2uni(src, srclen, &ch); if (size <= 0) { ch = '?'; size = 1; } src += size; srclen -= size; } else { ch = *src++; srclen--; } if (ch == '/') ch = ':'; size = nls_io->uni2char(ch, dst, dstlen); if (size < 0) { if (size == -ENAMETOOLONG) goto out; *dst = '?'; size = 1; } dst += size; dstlen -= size; } } else { char ch; while (--srclen >= 0) *dst++ = (ch = *src++) == '/' ? ':' : ch; } out: return dst - out;
}

Die übergebene Struktur “hfs_name” enthält den zu konvertierenden HFS-Namen:

struct hfs_name { u8 len; u8 name[HFS_NAMELEN];
} __packed;

Es kann allerdings vorkommen, dass der “len”-Eintrag in dieser Struktur größer ist als “HFS_NAMELEN”, beispielsweise wenn das Dateisystem von einem Angreifer speziell präpariert wurde oder versehentlich korrumpiert wurde. Prinzipiell könnte die Länge sogar größer sein die Länge des “out”-Puffers (HFS_MAX_NAMELEN=31). Dadurch kann es zu einem Stack Buffer Overflow kommen, den ein Angreifer zum Ausführen von Befehlen mit Root-Rechten ausnützen könnte.

Diese Sicherheitslücke lässt sich sehr einfach durch eine zusätzliche Längenkontrolle korrigieren:

int hfs_mac2asc(struct super_block *sb, char *out, const struct hfs_name *in)
{ struct nls_table *nls_disk = HFS_SB(sb)->nls_disk; struct nls_table *nls_io = HFS_SB(sb)->nls_io; const char *src; char *dst; int srclen, dstlen, size; src = in->name; srclen = in->len; if (srclen > HFS_NAMELEN) srclen = HFS_NAMELEN; ...

Dadurch wird “srclen” beschränkt, und der Overflow kann nicht mehr auftreten.

Der Fehler wurde Mitte November im Zweig 2.6 des Kernel-Git-Repository korrigiert.

Nach oben