2012-08-09 5 views
13

Ich habe ein einfaches Programm, das versucht, auf den physischen Speicher im Benutzerbereich zuzugreifen, wo der Kernel die erste Strukturseite speichert. Auf einer 64-Bit-Maschine ist diese Adresse:Wie kann man auf mmaped/dev/mem zugreifen, ohne den Linux-Kernel zu beschädigen?

  • virtuelle Kernel-Adresse: ffffea0000000000
  • physikalische Adresse: 0000620000000000

ich diese physikalische Adresse durch mmap im User-Space zugreifen versuchen. Aber der folgende Code stürzt den Kernel ab.

int *addr; 
if ((fd = open("/dev/mem", O_RDWR|O_SYNC)) < 0) { 
    printf("Error opening file. \n"); 
    close(fd); 
    return (-1); 
} 
/* mmap. address of first struct page for 64 bit architectures 
* is 0x0000620000000000. 
*/ 
addr = (int *)mmap(0, num*STRUCT_PAGE_SIZE, PROT_READ, MAP_PRIVATE, 
      fd, 0x0000620000000000); 
printf("addr: %p \n",addr); 
printf("addr: %d \n",*addr); /* CRASH. */ 
+1

Was ist der Wert, den mmap() in addr zurückgibt? – BjoernD

+1

@BjoernD: Ich habe das oben auf einem 32-Bit x86 (ersetzt mmap Offset als 0x01000000) versucht; addr = 0xffffffff. Und ja, es stürzt natürlich auf die Dereferenzierung ab. Was ist die Lösung? – kaiwan

+3

0xffffffff == -1 -> mmap() gibt einen Fehler zurück. Laut der man-Seite wird der Grund für den Fehler in der Variablen 'errno' angegeben. Vielleicht möchtest du es also überprüfen. – BjoernD

Antwort

18

Ich denke, ich habe das Problem gefunden - es ist mit/Dev/Mem Memory Mapping-Schutz auf dem x86 zu tun.

Pl beziehen sich auf diese LWN Artikel: "x86: Einführung/dev/mem Einschränkungen mit einer Konfigurationsoption" http://lwn.net/Articles/267427/

CONFIG_NONPROMISC_DEVMEM

Now (Getestet habe ich diese auf einem aktuellen 3.2.21 Kernel) scheint die Konfigurationsoption CONFIG_STRICT_DEVMEM zu heißen.

ich meine Kernel-Konfiguration geändert:

$ grep DEVMEM .config 
# CONFIG_STRICT_DEVMEM is not set 
$ 

Wenn die oben prg mit dem vorherigen Kernel ausgeführt wurde, mit CONFIG_STRICT_DEVMEM SET: dmesg zeigt:

[29537.565599] Program a.out tried to access /dev/mem between 1000000->1001000. 
[29537.565663] a.out[13575]: segfault at ffffffff ip 080485bd sp bfb8d640 error 4 in a.out[8048000+1000] 

Dies wegen der ist Kernelschutz ..

Wenn der Kernel neu erstellt wurde (mit dem CONFIG_STRICT_DEVMEM UNSET) und die oben prg ausgeführt wurde:

# ./a.out 
mmap failed: Invalid argument 
# 

Dies liegt daran, die 'Offset' Parameter> 1 MB (ungültig auf x86) (es war 16MB).

Nach dem Mmap machen Offset innerhalb von 1 MB sein:

# ./a.out 
addr: 0xb7758000 
*addr: 138293760 
# 

Es funktioniert! Siehe den obigen LWN Artikel für Details.

Auf x86-Architekturen mit PAT-Unterstützung (Page Attribute Table) verhindert der Kernel weiterhin die Zuordnung von DRAM-Bereichen. Der Grund dafür, wie in den kernel source erwähnt ist:

This check is nedded to avoid cache aliasing when PAT is enabled 

Diese Prüfung einen ähnlichen Fehler, der die oben erwähnte verursachen. Beispiel:

Program a.out tried to access /dev/mem between [mem 68200000-68201000]. 

Diese Einschränkung kann durch Deaktivieren von PAT aufgehoben werden. PAT kann deaktiviert werden, indem das "nopat" -Argument während der Boot-Zeit zur Kernel-Befehlszeile hinzugefügt wird.

+0

Hi Kaiwan, Thanks um auf die interessante Konfigurationsvariable hinzuweisen. 'CONFIG_STRICT_DEVMEM ist in meinem Fall nicht gesetzt. Kernel (3.4.6 und 3.1.0). Nach dem Offset-Wechsel funktioniert das Programm. Aber ich war daran interessiert, auf diese Adresse zuzugreifen, da sie die erste Strukturseite enthält. Ist das möglich? – Vinay

+0

Auch ich Offset auf 0x0000000000000000 setzen und ich bekomme gültige Absenderadresse. Aber wenn ich den Offset auf eine zufällige Adresse setze, sagen wir 0x00000000000000ff, bekomme ich keine gültige Adresse zurück. Muss ich die Adresse auf der Seitengrenze einstellen? – Vinay

+1

ARM erfordert die Verwendung einer Seitenbegrenzung für mmap(). Von einem kleinen Test auf IA32 scheint es auch dort der Fall zu sein ... (& du hast es auf dem x86_64 versucht, vermute ich). Auch, mit Ihrem Kommentar auf den Zugriff auf die erste Strukturseite, mit CONFIG_STRICT_DEVMEM Off, ich dachte, es würde funktionieren (auf einer Seitengrenze) .. nicht sicher über das .. – kaiwan

3

Auf x86-Architekturen mit PAT-Unterstützung (Page-Attributtabelle) kann der Kernel das Mapping von DRAM-Regionen verhindern (auch wenn er kompiliert wird, ohne CONFIG_NONPROMISC_DEVMEM zu setzen).

Der Grund dafür, wie in den kernel source erwähnt ist:

This check is nedded to avoid cache aliasing when PAT is enabled 

Diese Prüfung ein ähnlicher Fehler verursachen wird in dmesg wie die oben oben in Kaiwan Antwort erwähnt erscheinen. Beispiel:

Program a.out tried to access /dev/mem between [mem 68200000-68201000]. 

Diese Einschränkung kann durch Deaktivieren von PAT aufgehoben werden.

PAT kann durch Hinzufügen des nopat-Arguments zur Kernel-Befehlszeile beim Booten deaktiviert werden.

+0

Diese (korrekte!) Antwort scheint auf die obige Antwort von einem anonymen Benutzer kopiert worden zu sein, 8 Minuten nachdem Sie geantwortet haben. Wenn Sie das entfernen möchten, lassen Sie es mich wissen und ich werde es bearbeiten, da ich es für unfair halte, wenn es ohne Ihre Zustimmung gemacht wird. –

+0

Es war ich. Ich war derjenige, der es der vorherigen Antwort hinzugefügt hat und es dann als separate Antwort hinzugefügt hat, weil (anscheinend) ich nicht weiß, wie man das Werkzeug benutzt: D. –

+0

OK! Lassen Sie es mich wissen, wenn Sie möchten, dass es von der obigen Antwort entfernt wird. Prost. –