GNU/Linux >> Linux Esercitazione >  >> Linux

Come accedere agli indirizzi fisici dallo spazio utente in Linux?

Puoi mappare un file di dispositivo a una memoria di processo utente usando mmap(2) chiamata di sistema. Di solito, i file di dispositivo sono mappature della memoria fisica al file system. Altrimenti, devi scrivere un modulo del kernel che crei tale file o fornisca un modo per mappare la memoria necessaria a un processo utente.

Un altro modo è rimappare parti di /dev/mem in una memoria utente.

Modifica:Esempio di mmaping /dev/mem (questo programma deve avere accesso a /dev/mem, ad esempio avere i diritti di root):

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    if (argc < 3) {
        printf("Usage: %s <phys_addr> <offset>\n", argv[0]);
        return 0;
    }

    off_t offset = strtoul(argv[1], NULL, 0);
    size_t len = strtoul(argv[2], NULL, 0);

    // Truncate offset to a multiple of the page size, or mmap will fail.
    size_t pagesize = sysconf(_SC_PAGE_SIZE);
    off_t page_base = (offset / pagesize) * pagesize;
    off_t page_offset = offset - page_base;

    int fd = open("/dev/mem", O_SYNC);
    unsigned char *mem = mmap(NULL, page_offset + len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, page_base);
    if (mem == MAP_FAILED) {
        perror("Can't map memory");
        return -1;
    }

    size_t i;
    for (i = 0; i < len; ++i)
        printf("%02x ", (int)mem[page_offset + i]);

    return 0;
}

busybox devmem

busybox devmem è una piccola utility CLI che mmaps /dev/mem .

Puoi ottenerlo in Ubuntu con:sudo apt-get install busybox

Utilizzo:legge 4 byte dall'indirizzo fisico 0x12345678 :

sudo busybox devmem 0x12345678

Scrivi 0x9abcdef0 a quell'indirizzo:

sudo busybox devmem 0x12345678 w 0x9abcdef0

Fonte:https://github.com/mirror/busybox/blob/1_27_2/miscutils/devmem.c#L85

mmap MAP_SHARED

Durante la mappatura di /dev/mem , probabilmente vorrai usare:

open("/dev/mem", O_RDWR | O_SYNC);
mmap(..., PROT_READ | PROT_WRITE, MAP_SHARED, ...)

MAP_SHARED fa sì che le scritture vadano immediatamente nella memoria fisica, il che rende più facile l'osservazione e ha più senso per le scritture del registro hardware.

CONFIG_STRICT_DEVMEM e nopat

Per usare /dev/mem per visualizzare e modificare la normale RAM sul kernel v4.9, devi pugno:

  • disattiva CONFIG_STRICT_DEVMEM (impostato per impostazione predefinita su Ubuntu 17.04)
  • passa il nopat opzione della riga di comando del kernel per x86

Le porte IO funzionano ancora senza quelle.

Vedi anche:mmap di /dev/mem fallisce con argomento non valido per l'indirizzo virt_to_phys, ma l'indirizzo è allineato alla pagina

Svuotamento della cache

Se provi a scrivere sulla RAM anziché su un registro, la memoria potrebbe essere memorizzata nella cache dalla CPU:come svuotare la cache della CPU per una regione dello spazio degli indirizzi in Linux? e non vedo un modo molto portatile/semplice per scaricarlo o contrassegnare la regione come non memorizzabile nella cache:

  • Come scrivere la memoria dello spazio del kernel (indirizzo fisico) in un file usando O_DIRECT?
  • Come svuotare la cache della CPU per una regione dello spazio degli indirizzi in Linux?
  • È possibile allocare, nello spazio utente, un blocco di memoria non memorizzabile nella cache su Linux?

Quindi forse /dev/mem non può essere utilizzato in modo affidabile per passare i buffer di memoria ai dispositivi?

Questo purtroppo non può essere osservato in QEMU, poiché QEMU non simula le cache.

Come provarlo

Adesso per la parte divertente. Ecco alcune fantastiche configurazioni:

  • Memoria utente
    • allocare volatile variabile su un processo userland
    • ottieni l'indirizzo fisico con /proc/<pid>/maps + /proc/<pid>/pagemap
    • modificare il valore all'indirizzo fisico con devmem e osserva la reazione del processo userland
  • Memoria del kernel
    • allocare la memoria del kernel con kmalloc
    • ottieni l'indirizzo fisico con virt_to_phys e passalo di nuovo a userland
    • modifica l'indirizzo fisico con devmem
    • interroga il valore dal modulo del kernel
  • IO mem e dispositivo della piattaforma virtuale QEMU
    • creare un dispositivo di piattaforma con indirizzi di registro fisici noti
    • usa devmem scrivere al registro
    • guarda printf escono dal dispositivo virtuale in risposta

Bonus:determina l'indirizzo fisico per un indirizzo virtuale

Esiste qualche API per determinare l'indirizzo fisico dall'indirizzo virtuale in Linux?


Linux
  1. Come aggiungere o rimuovere un utente da un gruppo in Linux

  2. Linux:come accedere a Tty da Ssh?

  3. Come accedere alla cartella condivisa di Windows da Linux?

  4. Come accedere (se possibile) allo spazio del kernel dallo spazio utente?

  5. Come eseguire il mmap di un buffer del kernel Linux nello spazio utente?

Come consentire o negare l'accesso SSH a un particolare utente o gruppo in Linux

Come estrarre indirizzi e-mail da file di testo in Linux

Come limitare l'accesso SSH a determinati utenti in Linux

Come cambiare utente su Linux

Come modificare l'indirizzo IP su Linux

Linux:come viene suddiviso uno spazio di indirizzi virtuali di processo a 64 bit in Linux?