Überprüfen Sie den Speicherschutz von Linux Kern mit Code für ARM

Verweise

http://ijcsit.com/docs/Volume%205/vol5issue04/ijcsit20140504225.pdf

Überprüfen Sie den Speicherschutz von Linux Kern mit Code

Überprüfen Sie für den in bestätigten Speicherschutz Attack Surface Reduction mit dem tatsächlichen Quellcode. (Hauptsächlich in ARM)

KCONFIG

Dies sind die Schlüsselwörter ...

Diese sind in src / arch / Kconfig definiert. Ja, es ist an einem Ort, den ich normalerweise nicht anfasse.

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/Kconfig

arch/Kconfig


config ARCH_OPTIONAL_KERNEL_RWX
    def_bool n

config ARCH_OPTIONAL_KERNEL_RWX_DEFAULT
    def_bool n

config ARCH_HAS_STRICT_KERNEL_RWX
    def_bool n

config STRICT_KERNEL_RWX
    bool "Make kernel text and rodata read-only" if ARCH_OPTIONAL_KERNEL_RWX
    depends on ARCH_HAS_STRICT_KERNEL_RWX
    default !ARCH_OPTIONAL_KERNEL_RWX || ARCH_OPTIONAL_KERNEL_RWX_DEFAULT
    help
      If this is set, kernel text and rodata memory will be made read-only,
      and non-text memory will be made non-executable. This provides
      protection against certain security exploits (e.g. executing the heap
      or modifying text)

      These features are considered standard security practice these days.
      You should say Y here in almost all cases.

config ARCH_HAS_STRICT_MODULE_RWX
    def_bool n

config STRICT_MODULE_RWX
    bool "Set loadable kernel module data as NX and text as RO" if ARCH_OPTIONAL_KERNEL_RWX
    depends on ARCH_HAS_STRICT_MODULE_RWX && MODULES
    default !ARCH_OPTIONAL_KERNEL_RWX || ARCH_OPTIONAL_KERNEL_RWX_DEFAULT
    help
      If this is set, module text and rodata memory will be made read-only,
      and non-text memory will be made non-executable. This provides
      protection against certain security exploits (e.g. writing to text)

Das war's. ARCH_HAS_STRICT_KERNEL_RWX ist abhängig und ohne es ungültig.

ARM-Streudatei

Zunächst die beim Verknüpfen verwendete Streuung. Es ist lang, also nur ein Teil davon.

c:arch/arm/kernel/vmlinux.lds.S



<Ausgelassen>
#ifdef CONFIG_STRICT_KERNEL_RWX
    . = ALIGN(1<<SECTION_SHIFT);
#endif

#ifdef CONFIG_ARM_MPU
    . = ALIGN(PMSAv8_MINALIGN);
#endif
    .text : {           /* Real text segment        */
        _stext = .;     /* Text and read-only data  */
        ARM_TEXT
    }

#ifdef CONFIG_DEBUG_ALIGN_RODATA
    . = ALIGN(1<<SECTION_SHIFT);
#endif
    _etext = .;         /* End of text section */

    RO_DATA(PAGE_SIZE)
<Ausgelassen>

Klicken Sie hier für die Definition von SECTION_SHIFT. (2 Level, wenn LPAE nicht unterstützt wird, 3 Level, wenn LPAE unterstützt wird)

arch/arm/include/asm/pgtable-2level.h



/*
 * section address mask and size definitions.
 */
#define SECTION_SHIFT       20
#define SECTION_SIZE        (1UL << SECTION_SHIFT)
#define SECTION_MASK        (~(SECTION_SIZE-1))

arch/arm/mm/init.c


static struct section_perm nx_perms[] = {
    /* Make pages tables, etc before _stext RW (set NX). */
    {
        .name   = "pre-text NX",
        .start  = PAGE_OFFSET,
        .end    = (unsigned long)_stext,
        .mask   = ~PMD_SECT_XN,
        .prot   = PMD_SECT_XN,
    },
    /* Make init RW (set NX). */
    {
        .name   = "init NX",
        .start  = (unsigned long)__init_begin,
        .end    = (unsigned long)_sdata,
        .mask   = ~PMD_SECT_XN,
        .prot   = PMD_SECT_XN,
    },
    /* Make rodata NX (set RO in ro_perms below). */
    {
        .name   = "rodata NX",
        .start  = (unsigned long)__start_rodata_section_aligned,
        .end    = (unsigned long)__init_begin,
        .mask   = ~PMD_SECT_XN,
        .prot   = PMD_SECT_XN,
    },
};

static struct section_perm ro_perms[] = {
    /* Make kernel code and rodata RX (set RO). */
    {
        .name   = "text/rodata RO",
        .start  = (unsigned long)_stext,
        .end    = (unsigned long)__init_begin,
#ifdef CONFIG_ARM_LPAE
        .mask   = ~(L_PMD_SECT_RDONLY | PMD_SECT_AP2),
        .prot   = L_PMD_SECT_RDONLY | PMD_SECT_AP2,
#else
        .mask   = ~(PMD_SECT_APX | PMD_SECT_AP_WRITE),
        .prot   = PMD_SECT_APX | PMD_SECT_AP_WRITE,
        .clear  = PMD_SECT_AP_WRITE,
#endif
    },
};

arch/arm/include/asm/pgtable-2level-hwdef.h


/*
 *   - section
 */
#define PMD_SECT_PXN    (_AT(pmdval_t, 1) << 0)     /* v7 */
#define PMD_SECT_BUFFERABLE (_AT(pmdval_t, 1) << 2)
#define PMD_SECT_CACHEABLE  (_AT(pmdval_t, 1) << 3)
#define PMD_SECT_XN     (_AT(pmdval_t, 1) << 4)     /* v6 */
#define PMD_SECT_AP_WRITE   (_AT(pmdval_t, 1) << 10)
#define PMD_SECT_AP_READ    (_AT(pmdval_t, 1) << 11)
#define PMD_SECT_TEX(x)     (_AT(pmdval_t, (x)) << 12)  /* v5 */
#define PMD_SECT_APX        (_AT(pmdval_t, 1) << 15)    /* v6 */
#define PMD_SECT_S      (_AT(pmdval_t, 1) << 16)    /* v6 */
#define PMD_SECT_nG     (_AT(pmdval_t, 1) << 17)    /* v6 */
#define PMD_SECT_SUPER      (_AT(pmdval_t, 1) << 18)    /* v6 */
#define PMD_SECT_AF     (_AT(pmdval_t, 0))

Bereiche wie text / ro / rw / bss sollten jetzt in Schritten von 1 MB beginnen. Jede Attributverwaltung Der folgende Code verwaltet jedes Attribut. - "nx_perms" ist die Berechtigung Nicht ausführen. - "ro_perms" ist schreibgeschützt. Ich glaube, dass der. Zum Beispiel im vorherigen Beispiel

Start End NX/RO/RW Zweck
PAGE_OFFSET _stext NX pre-text
_stext _etext RO text
_start_rodata_section_aligned __init_begin RO + NX rodata
__init_begin _sdata NX init

In Bezug auf Rodata ist das Makro jedoch so aufgebaut, dass es eine Grenze von 1 MB gibt.

Bis zum Anruf

Die Aufrufsequenz, die die Abschnittsaktualisierung erreicht, sieht folgendermaßen aus. (Ich habe die Kexec-Beziehung vorerst nicht gesehen).

update_sections_early()

Fordern Sie hier an, die Abschnittsberechtigungseinstellungen für alle Threads (außer kthreads) aller Prozessoren und die aktuellen actieve_mm und init_mm zu ändern.

c:arch/arm/mm/init.c::update_sections_early()



/**
 * update_sections_early intended to be called only through stop_machine
 * framework and executed by only one CPU while all other CPUs will spin and
 * wait, so no locking is required in this function.
 */
static void update_sections_early(struct section_perm perms[], int n)
{
    struct task_struct *t, *s;

    for_each_process(t) {
        if (t->flags & PF_KTHREAD)
            continue;
        for_each_thread(t, s)
            if (s->mm)
                set_section_perms(perms, n, true, s->mm);
    }
    set_section_perms(perms, n, true, current->active_mm);
    set_section_perms(perms, n, true, &init_mm);
}

set_section_perms()

Hier wird die Attributänderung des Abschnitts in 1-MB-Einheiten angefordert. Abhängig vom gesetzten Flag, ob Berechtigungsschutz verwendet oder Änderungen gelöscht werden sollen.

c:arch/arm/mm/init.c::set_section_perms()


static void set_section_perms(struct section_perm *perms, int n, bool set,
                  struct mm_struct *mm)
{
    size_t i;
    unsigned long addr;

    if (!arch_has_strict_perms())
        return;

    for (i = 0; i < n; i++) {
        if (!IS_ALIGNED(perms[i].start, SECTION_SIZE) ||
            !IS_ALIGNED(perms[i].end, SECTION_SIZE)) {
            pr_err("BUG: %s section %lx-%lx not aligned to %lx\n",
                perms[i].name, perms[i].start, perms[i].end,
                SECTION_SIZE);
            continue;
        }

        for (addr = perms[i].start;
             addr < perms[i].end;
             addr += SECTION_SIZE)
            section_update(addr, perms[i].mask,
                set ? perms[i].prot : perms[i].clear, mm);
    }

}

section_update()

Konvertieren Sie es von der Speicheradresse in pgd, konvertieren Sie es in pud, konvertieren Sie es in pmd, wenden Sie mask und prot (oder clear) darauf an und aktualisieren Sie es.

c:arch/arm/mm/init.c::section_update()


/*
 * Updates section permissions only for the current mm (sections are
 * copied into each mm). During startup, this is the init_mm. Is only
 * safe to be called with preemption disabled, as under stop_machine().
 */
static inline void section_update(unsigned long addr, pmdval_t mask,
                  pmdval_t prot, struct mm_struct *mm)
{
    pmd_t *pmd;

    pmd = pmd_offset(pud_offset(pgd_offset(mm, addr), addr), addr);

#ifdef CONFIG_ARM_LPAE
    pmd[0] = __pmd((pmd_val(pmd[0]) & mask) | prot);
#else
    if (addr & SECTION_SIZE)
        pmd[1] = __pmd((pmd_val(pmd[1]) & mask) | prot);
    else
        pmd[0] = __pmd((pmd_val(pmd[0]) & mask) | prot);
#endif
    flush_pmd_entry(pmd);
    local_flush_tlb_kernel_range(addr, addr + SECTION_SIZE);
}

flush_pmd_entry()

Da der Inhalt von pmd neu geschrieben wurde, leeren Sie den pmd-Eintrag hier.

arch/arm/include/asm/tlbflush.h


/*
 *  flush_pmd_entry
 *
 *  Flush a PMD entry (word aligned, or double-word aligned) to
 *  RAM if the TLB for the CPU we are running on requires this.
 *  This is typically used when we are creating PMD entries.
 *
 *  clean_pmd_entry
 *
 *  Clean (but don't drain the write buffer) if the CPU requires
 *  these operations.  This is typically used when we are removing
 *  PMD entries.
 */
static inline void flush_pmd_entry(void *pmd)
{
    const unsigned int __tlb_flag = __cpu_tlb_flags;

    tlb_op(TLB_DCLEAN, "c7, c10, 1  @ flush_pmd", pmd);
    tlb_l2_op(TLB_L2CLEAN_FR, "c15, c9, 1  @ L2 flush_pmd", pmd);

    if (tlb_flag(TLB_WB))
        dsb(ishst);
}

#define tlb_op(f, regs, arg)    __tlb_op(f, "p15, 0, %0, " regs, arg)
#define tlb_l2_op(f, regs, arg) __tlb_op(f, "p15, 1, %0, " regs, arg)

#define __tlb_op(f, insnarg, arg)                   \
    do {                                \
        if (always_tlb_flags & (f))             \
            asm("mcr " insnarg              \
                : : "r" (arg) : "cc");          \
        else if (possible_tlb_flags & (f))          \
            asm("tst %1, %2\n\t"                \
                "mcrne " insnarg                \
                : : "r" (arg), "r" (__tlb_flag), "Ir" (f)   \
                : "cc");                    \
    } while (0)

Ich weiß ehrlich gesagt nicht, warum es funktioniert.

Es ist also über 4 Stunden her, seit ich es geschrieben habe, aber ich kann von hier aus nicht fortfahren. Ich habe die Topper-Projektdokumentation gelesen und verstanden, aber ... gut. Ich werde es bis zu diesem Punkt belassen.

asm("mcr p15, 0, %0, c7, c10, 1" : : "r"(pmd) : "cc" ); 

https://www.aps-web.jp/academy/ca/229/

MCR{ cond } coproc,#opcode1,Rd,CRn,CRm {, # opcode2 } opcode1 Gibt einen für den 3-Bit-Coprozessor spezifischen Opcode an. CRn Gibt das Coprozessorregister an. CRm Gibt das Coprozessorregister an.

→ CRn = c7, CRm = c10, opcode=0, opcode2 = 1

http://infocenter.arm.com/help/topic/com.arm.doc.ddi0388fj/CIHGJFEH.html

1 DCCVAC WO

Einzelheiten zu dieser Anleitung finden Sie im ARM-Referenzhandbuch. Vorerst ist es soweit.

Möglicherweise ist es möglich, Berechtigungen in 1-MB-Einheiten festzulegen, indem das Ergebnis des Betriebs des AP-Bits auf der SECTION-Ebene wiedergegeben wird.

Das ist es.

Recommended Posts

Überprüfen Sie den Speicherschutz von Linux Kern mit Code für ARM
Überprüfen Sie den Speicherstatus des Servers mit dem Befehl Linux free
Überprüfen Sie den Code mit flake8
Überprüfen Sie die Antwort des HTTP-Statuscodes mit dem Befehl curl (#Linux #Shell).
Überprüfen Sie die Existenz der Datei mit Python
Die dritte Nacht der Runde mit für
Die zweite Nacht der Runde mit für
Berechnen Sie die Speicherfreigaberate von Linux-Prozessen
[2020Juli] Überprüfen Sie die UDID des iPad unter Linux
Überprüfen Sie das Datum der Flaggenpflicht mit Python
Code zum Überprüfen des Betriebs von Python Matplot lib
Konvertieren Sie den Zeichencode der Datei mit Python3
Hier finden Sie die Menge an freiem Speicher des Befehls free
Fügen Sie Attribute von Klassenobjekten mit einer for-Anweisung hinzu
Erstellen Sie unter Linux einen QR-Code für die URL
Überprüfen Sie, ob in Java BigQuery-Tabellen vorhanden sind
[Für Anfänger] Quantifizieren Sie die Ähnlichkeit von Sätzen mit TF-IDF
Überprüfen Sie den Linux-Verteilungstyp und die Version
Grundlagen zum Erstellen eines internen Servers für Linux (CentOS 8.1, openSUSE 15.1, Ubuntu 20.04)! Dateiserver mit Samba
Ich habe den Code für die japanische Satzgenerierung mit DeZero geschrieben
Testcode, um auf der Seite nach defekten Links zu suchen
Überprüfen Sie die Funktionsweise von Python für .NET in jeder Umgebung
Holen Sie sich die ID einer GPU mit geringer Speichernutzung
Einstellungen zum Eingeben und Debuggen des Inhalts der Bibliothek mit VS-Code
Komfortables LaTeX mit Windows-Subsystem für Linux und VS-Code
[Tipps] Persistenz von Kali Linux Live Image mit USB-Speicher
Befehle und Dateien zum Überprüfen der Version von CentOS Linux
Rufen Sie den Hostnamen des Host-PCs mit Docker unter Linux ab
Erläutern Sie den Code von Tensorflow_in_ROS
Mechanismus zur automatischen Flusenprüfung mit flake8 beim Festschreiben von Python-Code
Überprüfen Sie die Zunahme / Abnahme der Bitmünzen für jede Adresse aus der Blockchain
[Maschinelles Lernen] Überprüfen Sie die Leistung des Klassifikators anhand handgeschriebener Zeichendaten
So überprüfen Sie die Speichergröße einer Variablen in Python
Die Geschichte, einen Standardtreiber für db mit Python zu erstellen.
So überprüfen Sie die Speichergröße eines Wörterbuchs in Python
Überprüfen Sie die Verwendung des Server-E / A-Geräts mit dem Linux-Befehl iostat
Aufzeichnung des Codes für klinische Studien, die von der Ethikkommission abgelehnt wurden
Fassen wir den Grad der Kopplung zwischen Modulen mit Python-Code zusammen
Ich möchte die Position meines Gesichts mit OpenCV überprüfen!
Überprüfen Sie Python auf Speicherlecks
QR-Code mit CNN entschlüsseln
[Muss für Anfänger] Grundlagen von Linux
4. Nacht der Schleife mit für
Hinweise zur Verwendung von KUnit, dem Unit-Test-Mechanismus des Linux-Kernels
Sie können auch die Kommunikation von DB und Cache mit Curl überprüfen
[Ota Ward] Überprüfen Sie den Status der Antragsbearbeitung auf besondere Pauschalleistungen
Richtlinien für die Reinkarnation in der Welt der Linux-Programmierentwicklung (C / C ++ - Sprache)
Bearbeiten Sie die Datei des SSH-Verbindungszielservers auf dem Server mit VS-Code
Ich habe versucht, den Authentifizierungscode der Qiita-API mit Python abzurufen.
Impressionen und Memorandum bei der ersten Arbeit mit VScode
Die Geschichte des Ausführens der asp.net Core 3.1-App auf der arm64-Version von Amazon Linux 2
Mit dem Aufkommen von systemd-homed im Jahr 2020 wird sich die Linux-Benutzerverwaltung dramatisch ändern.
Ich habe die Geschwindigkeit der Listeneinschlussnotation für und während mit Python2.7 gemessen.