
Soweit ich es verstehe, werden User-Space-Programme im nicht privilegierten Modus ausgeführt und haben daher keinen direkten Zugriff auf den Speicher oder die E/A.
Wie genau können wir dann direkt auf den Speicher oder die E/A-Speicherorte zugreifen, wenn wir in Benutzerbereichsprogrammen /dev/mem mmap verwenden?
Zum Beispiel:
int fd = 0;
u8 leds = 0;
fd = open("/dev/mem", O_RDWR|O_SYNC);
leds = (u8 *)mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x80840000);
Dies ist ein Hack, der in eingebetteten Geräten sehr häufig verwendet wird.
Jetzt kann die Variable leds
spontan verwendet werden, um auf jedes Gerät zuzugreifen, das bei 0x80840000 vorhanden sein könnte.
Wir werden keinen Systemaufruf mehr verwenden, um auf diese Adresse zuzugreifen.
Sogar so etwas wie
leds[0x20] = val;
würde funktionieren.
Privilegierte Vorgänge wie das direkte Lesen/Schreiben von/zu einer E/A-Adresse sollten jedoch nur möglich sein, indem der Prozessor durch einen Systemaufruf in den privilegierten Modus versetzt wird.
Antwort1
Den Zugriff /dev/mem
nicht privilegierter Prozesse zuzulassen, wäre tatsächlich ein Sicherheitsproblem und sollte nicht zugelassen werden.
Auf meinem System ls -l /dev/mem
sieht es folgendermaßen aus:
crw-r----- 1 root kmem 1, 1 Sep 8 10:12 /dev/mem
Sie können es also root
lesen und schreiben, Mitglieder der kmem
Gruppe (von denen es zufällig keine gibt) können es lesen, aber nicht schreiben, und alle anderen können es überhaupt nicht öffnen. Das sollte also sicher sein.
Wenn es bei Ihnen /dev/mem
ähnlich ist wie bei mir, sollte Ihr nicht privilegierter Prozess nicht einmal in der Lage sein, die Datei überhaupt zu öffnen, geschweige denn, mmap
sie auszuführen.
Überprüfen Sie die Berechtigungen /dev/mem
auf Ihrem System, um sicherzustellen, dass sie sicher sind!
Antwort2
Die für einen Benutzerprozess sichtbaren Adressen (egal, ob er als Root oder als unprivilegierter Benutzer ausgeführt wird) sind virtuelle Adressen, die von der MMU über die Seitentabellen physischen Adressen zugeordnet werden. Das Einrichten der Seitentabellen ist eine privilegierte Operation und kann nur durch Kernelcode ausgeführt werden. Sobald die Seitentabellen jedoch eingerichtet sind, ist der Zugriff auf den Speicher im Benutzermodus zulässig.
Konkret fordert Ihr Code mmap
den Kernel auf, die Seitentabellen so einzurichten, dass auf einen bestimmten Bereich des physischen Speichers zugegriffen werden kann. Der Kernel überprüft die Berechtigungen des Prozesses (er hat Lese-/Schreibzugriff auf /dev/mem
) und richtet die Seitentabellen so ein, dass auf den physischen Speicher zugegriffen werden kann.
Antwort3
Der Wert von leds
ist eine virtuelle Adresse. Solange sie sich im Benutzerbereich des aktuellen Prozesses befindet, kann der Prozess direkt über Anweisungen wie darauf zugreifen, leds[0] = val
ohne sich im privilegierten Modus befinden zu müssen, unabhängig davon, wo im RAM diese virtuelle Adresse abgebildet ist.