[LINUX] Der Kernel Address Sanitizer (KASAN) (2/2)

Ursprünglich ist es Teil des Quellcodes des Linux-Kernels, daher wird es als GPLv2 behandelt (Anerkennung, dass es sein sollte).

https://www.kernel.org/doc/html/latest/index.html

Licensing documentation

The following describes the license of the Linux kernel source code (GPLv2), how to properly mark the license of individual files in the source tree, as well as links to the full license text.

https://www.kernel.org/doc/html/latest/process/license-rules.html#kernel-licensing

https://www.kernel.org/doc/html/latest/dev-tools/kasan.html


Docs » Development tools for the kernel » The Kernel Address Sanitizer (KASAN)

The Kernel Address Sanitizer (KASAN)

Implementation details

Generic KASAN

From a high level, our approach to memory error detection is similar to that of kmemcheck: use shadow memory to record whether each byte of memory is safe to access, and use compile-time instrumentation to insert checks of shadow memory on each memory access.

Auf hoher Ebene ähnelt unser Ansatz zur Speicherfehlererkennung dem kmemcheck. Verwenden Sie den Schattenspeicher, um aufzuzeichnen, ob der Zugriff in jedem Speicherbyte sicher ist, und fügen Sie bei der Kompilierung bei jedem Speicherzugriff eine Überprüfung auf Schattenspeicher ein.

Generic KASAN dedicates 1/8th of kernel memory to its shadow memory (e.g. 16TB to cover 128TB on x86_64) and uses direct mapping with a scale and offset to translate a memory address to its corresponding shadow address.

Generisches KASAN weist 1/8 des Kernelspeichers dem Schattenspeicher zu (z. B. 16 TB für 128 TB für x86_64). Dann direkte Zuordnung zu der der Speicheradresse zugeordneten Schattenadresse durch Skalierung und Versatz.

Here is the function which translates an address to its corresponding shadow address:

Hier ist die Funktion, die die der Schattenadresse zugeordnete Adresse übersetzt, ...


static inline void *kasan_mem_to_shadow(const void *addr)
{
    return ((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT)
            + KASAN_SHADOW_OFFSET;
}

where KASAN_SHADOW_SCALE_SHIFT = 3.

Compile-time instrumentation is used to insert memory access checks. Compiler inserts function calls (__asan_load*(addr), __asan_store*(addr)) before each memory access of size 1, 2, 4, 8 or 16. These functions check whether memory access is valid or not by checking corresponding shadow memory.

Die Instrumentierung zur Kompilierungszeit wird verwendet, um die Speicherzugriffsprüfung einzufügen. Der Compiler fügt den Funktionsaufruf kasan_load * (addr), __asan_store * (addr)) ein, bevor ein Speicherzugriff der Größe 1,2,4,8 erfolgt. Diese Funktionen prüfen, ob der Speicherzugriff aktiviert ist, indem sie den zugehörigen Schattenspeicher überprüfen.

GCC 5.0 has possibility to perform inline instrumentation. Instead of making function calls GCC directly inserts the code to check the shadow memory. This option significantly enlarges kernel but it gives x1.1-x2 performance boost over outline instrumented kernel.

Mit GCC 5.0 ist es möglich, Inline-Instrumente durchzuführen. Anstatt einen Funktionsaufruf durchzuführen, fügt GCC den Code ein, den der Schattenspeicher direkt überprüft. Dies führt dazu, dass der Kernel leicht aufgebläht ist, bietet jedoch eine x1.1-x2-Leistungsbeschleunigung im Vergleich zum Kernel mit Umrissinstrumenten.

Software tag-based KASAN

Tag-based KASAN uses the Top Byte Ignore (TBI) feature of modern arm64 CPUs to store a pointer tag in the top byte of kernel pointers. Like generic KASAN it uses shadow memory to store memory tags associated with each 16-byte memory cell (therefore it dedicates 1/16th of the kernel memory for shadow memory).

Tag-basiertes KASAN zeichnet das Zeigertag im tio-Byte des Kernelzeigers unter Verwendung der TBI-Funktionen (Top Byte Ignore) auf, die eine Funktion der neuesten arm64-CPU ist. Wie bei generi KASAN wird Shadow Mamory verwendet, um das jeder 16-Byte-Speicherzelle zugeordnete Speicher-Tag aufzuzeichnen (der Schattenspeicher belegt also 1/16 des Kernel-Speichers).

On each memory allocation tag-based KASAN generates a random tag, tags the allocated memory with this tag, and embeds this tag into the returned pointer. Software tag-based KASAN uses compile-time instrumentation to insert checks before each memory access. These checks make sure that tag of the memory that is being accessed is equal to tag of the pointer that is used to access this memory. In case of a tag mismatch tag-based KASAN prints a bug report.

Für jede Speicherzuweisung generiert tagbasiertes KASAN ein zufälliges Tag. Der zugewiesene Speicher ist mit diesem Tag versehen, und der zurückgegebene Zeiger ist mit diesem Tag eingebettet. Software-Tag-basiertes KASAN verwendet eine Instrumentierung zur Kompilierungszeit und fügt vor jedem Speicherzugriff eine Prüfung ein. Diese Überprüfung überprüft, ob das Tag des Speichers, auf das zugegriffen wird, mit dem Tag des Zeigers übereinstimmt, der für den Zugriff auf diesen Speicher verwendet wird. Wenn die Tags nicht übereinstimmen, druckt tagbasiertes KASAN einen Fehlerbericht.

Software tag-based KASAN also has two instrumentation modes (outline, that emits callbacks to check memory accesses; and inline, that performs the shadow memory checks inline). With outline instrumentation mode, a bug report is simply printed from the function that performs the access check. With inline instrumentation a brk instruction is emitted by the compiler, and a dedicated brk handler is used to print bug reports.

Software-Tag-basiertes KASAN verfügt außerdem über zwei Instrumentierungsmodi. (Geben Sie einen Rückruf aus, um die Gliederung, den Speicherzugriff und die Inline-Ausführung des Schattenspeichers zu überprüfen.) Im Gliederungsinstrumentierungsmodus wird einfach ein Fehlerbericht von der Funktion ausgegeben, die die Zugriffsprüfung ausgeführt hat. Bei der Inline-Instrumentierung werden brk-Anweisungen vom Compiler ausgegeben, und der brk-Handler wird ausschließlich zur Ausgabe von Fehlerberichten verwendet.

A potential expansion of this mode is a hardware tag-based mode, which would use hardware memory tagging support instead of compiler instrumentation and manual shadow memory manipulation.

Eine mögliche Erweiterung dieses Modus ist der Hardware-Tag-basierte Modus, in dem Hardware Speicher-Tagging anstelle von Compiler-Instrumentierung oder manueller Manipulation des Schattenspeichers unterstützt.

What memory accesses are sanitised by KASAN?

The kernel maps memory in a number of different parts of the address space. This poses something of a problem for KASAN, which requires that all addresses accessed by instrumented code have a valid shadow region.

Der Kernel ordnet einen Speicher zu, in dem der Adrec-Bereich unterschiedlich ist. Dies wirft das Problem in KASAN auf. Auf alle Adressen muss ein instrumentierter Code mit einem normalen Schattenbereich zugreifen.

The range of kernel virtual addresses is large: there is not enough real memory to support a real shadow region for every address that could be accessed by the kernel.

Der Bereich der virtuellen Adressen im Kernel ist sehr groß. Es ist unwahrscheinlich, dass der tatsächliche Speicher alle tatsächlichen Schattenbereiche unterstützen kann, auf die der Kernel zugreifen wird.

By default

By default, architectures only map real memory over the shadow region for the linear mapping (and potentially other small areas). For all other areas - such as vmalloc and vmemmap space - a single read-only page is mapped over the shadow area. This read-only shadow page declares all memory accesses as permitted.

Standardmäßig ordnet die Architektur den tatsächlichen Speicher nur durch lineare Zuordnung (möglicherweise kleine andere Bereiche) dem Schattenbereich zu. Für alle anderen Bereiche, z. B. in den Bereichen vmalloc und vmemmmap, wird eine einfache schreibgeschützte Seite dem Schattenbereich zugeordnet. Diese schreibgeschützte Schattenseite deklariert den gesamten zulässigen Speicherzugriff.

This presents a problem for modules: they do not live in the linear mapping, but in a dedicated module space. By hooking in to the module allocator, KASAN can temporarily map real shadow memory to cover them. This allows detection of invalid accesses to module globals, for example.

Dies verursacht Probleme für das Modul. Diese gelten nicht für die lineare Zuordnung und befinden sich in ihrem eigenen Modulraum. Durch das Einbinden in den Moduke-Allokator implementiert KASAN vorübergehend einen echten Schattenspeicher und eine temporäre Zuordnung, die diese abdeckt. Dies ermöglicht es beispielsweise, nicht autorisierten Zugriff auf das globale Modul zu erkennen.

This also creates an incompatibility with VMAP_STACK: if the stack lives in vmalloc space, it will be shadowed by the read-only page, and the kernel will fault when trying to set up the shadow data for stack variables.

Dies führt auch zu einer Inkompatibilität mit VMAP_STACK. Befindet sich der Stapel im vmalloc-Bereich, wird er von der schreibgeschützten Seite ausgeblendet, und der Kernel schlägt fehl, wenn versucht wird, Schattendaten für die Shack-Variable einzurichten.

CONFIG_KASAN_VMALLOC

With CONFIG_KASAN_VMALLOC, KASAN can cover vmalloc space at the cost of greater memory usage. Currently this is only supported on x86.

Wenn Sie CONFIG_KASAN_VMALLOC festlegen, kann KASAN auch den vmalloc-Speicherplatz auf Kosten der Speichernutzung abdecken. Derzeit wird dies nur auf x86 unterstützt.

This works by hooking into vmalloc and vmap, and dynamically allocating real shadow memory to back the mappings.

Dies funktioniert durch Einbinden von vmalloc und vmap. Anschließend wird der reale Schattenspeicher dynamisch zugewiesen, um die Zuordnung zurückzugeben.

Most mappings in vmalloc space are small, requiring less than a full page of shadow space. Allocating a full shadow page per mapping would therefore be wasteful. Furthermore, to ensure that different mappings use different shadow pages, mappings would have to be aligned to KASAN_SHADOW_SCALE_SIZE * PAGE_SIZE.

Viele Mappingu sind im vmalloc-Bereich klein und stellen kleinere Anforderungen als die gesamte Seite im Schattenbereich. Das Sichern einer vollständigen Schattenseite mit dem Mapping ist nutzlos. Wenn unterschiedliche Zuordnungen unterschiedliche Schattenseiten zuordnen, muss die Zuordnung außerdem an KASAN_SHADOW_SCALE_SIZE * PAGE_SIZE ausgerichtet werden.

Instead, we share backing space across multiple mappings. We allocate a backing page when a mapping in vmalloc space uses a particular page of the shadow region. This page can be shared by other vmalloc mappings later on.

Stattdessen wird ein Hintergrund für mehrere Zuordnungen beibehalten. Die Hintergrundseite ist reserviert, wenn der vmalloc-Bereich einige Seiten im Schattenbereich verwendet. Diese Seite wird freigegeben, nachdem andere Malloc-Zuordnungen vorgenommen wurden.

We hook in to the vmap infrastructure to lazily clean up unused shadow memory.

Hook vmap infrastructure, um nicht verwendeten Schattenspeicher zu verschieben und zu löschen.

To avoid the difficulties around swapping mappings around, we expect that the part of the shadow region that covers the vmalloc space will not be covered by the early shadow page, but will be left unmapped. This will require changes in arch-specific code.

Tauschen Sie die Zuordnung aus Erwarten Sie, dass der Teil des Schattenbereichs nicht mit den schwierigen Teilen in der Umgebung umgeht. Das heißt, der vmalloc-Bereich wird von der frühen Schattenseite nicht abgedeckt. Es gibt jedoch Fälle, in denen Upn-Mapping verbleibt. Dies erforderte eine Änderungsanforderung innerhalb der Bogenspezifikation.

This allows VMAP_STACK support on x86, and can simplify support of architectures that do not have a fixed module region.

Die Unterstützung von VMAP_STACK ist auf x86 zulässig. Es kann Architekturen unterstützen, die keinen festen Modulbereich haben.

Recommended Posts

Der Kernel Address Sanitizer (KASAN) (2/2)
Der Kernel Address Sanitizer (KASAN) (1/2)
Probieren Sie den Linux-Kernel-Sperrmechanismus aus
Holen Sie sich eine Adresse aus einer Postleitzahl