Wo setzt der Linux-Kernel das Protected Mode Flag für x86?
-
Hi,
ich will gerne wissen, wo im Linux Quellcode die Stelle zu finden ist, die vor dem Ausführen von Usermode-Programmcode das Prozessor-Flag für den Protected Mode setzt. Ich habe dazu schon ein bisschen Recherche betrieben, bin aber an einer Stelle hängen geblieben.
Ich habe angefangen, nach dem Syscall zu suchen. Den hab ich dann hier gefunden.
Dann bin ich die Aufrufkette durchgegangen: Der Syscall selbst ruft zuerst einmal ohne Umwege do_execve auf. Weiter geht es wieder ohne Umwege mit do_execveat_common.
In dieser Funktion habe ich eine Stelle gefunden, bei der ich zuerst dachte, sie sei relevant, die ich dann aber als unwichtig für mein Vorhaben abgetan habe. Zur Sicherheit teile ich euch das mal mit, vielleicht irre ich mich ja: Es geht um den Aufruf sched_exec();. Die Definition dafür findet ihr hier. Ich hab nicht ganz verstanden, was die Funktion macht, aber offenbar führt sie keinen Code aus. Ich dachte zuerst, dass die das Ausführen scheduled, aber offenbar habe ich mich geirrt (oder?).
Weiter im Programm geht es dann meiner Meinung nach mit exec_binrpm();, die hier definiert ist. Darin sucht er nach dem Handler für die Binary. Das macht er mittels des Aufrufes search_binary_handler(brpm);. Diese Funktion ist hier definiert. Den richtigen Handler sucht er mittels Aufruf von list_for_each_entry(fmt, &formats, lh) raus, der über die verkettete Liste in der Variable "formats" läuft. Diese Liste enthält offenbar alle Handler für ausführbare Binärformate. Einen Handler hinzufügen kann man mittels der Funktion __register_binfmt. Diese wird mittels register_binfmt (ohne die beiden führenden Unterstriche) gewrappt und schließlich für das ELF-Format hier aufgerufen, um den Handler für das Format zu registrieren. Das Struct, das hier übergeben wird, enthält (unter anderem) den für uns wichtigen Eintrag "load_binary", was ein Funktionspointer für die Funktion zum Laden einer ELF-Binary darstellt. Für das ELF-Format wird hier die Funktion load_elf_binary angegeben. An dieser Stelle dachte ich mir: OK, wenn das die Stelle ist, die die ELF-Datei lädt, dann wird wohl spannend sein, was die Funktion zurückgibt. Dadurch bin ich dann darauf gestoßen, dass hier der Aufruf start_thread(regs, elf_entry, bprm->p); ist. Das hat mich insofern etwas verwundert, als dass ich nicht erwartet hätte, dass die Funktion zum Ladenn der Informationen über die Datei bereits etwas ausführt (hier dem Namen nach ja einen Thread). Da hab ich dann mal hier geschaut, wo die Funktion/das Makro zu finden ist. Da sind mehrere Treffer. Ich habe mir die für arch/arm64/include/asm/processor.h, arch/x86/kernel/process_32.c, arch/x86/kernel/process_64.c und arch/ia64/include/asm/processor.h angeschaut, aber keine von diesen Funktionen und Makros scheint einen Thread auszuführen, sondern nur Flags zu setzen. Und dabei leider scheinbar kein Protected Mode Flag.
Also wieder zurück: Stehen gebliebe waren wir in der Funktion search_binary_handler. Nachdem diese also den Handler gefunden, und die oben beschriebene Funktion load_binary aufgerufen hat, passiert scheinbar nichts mehr, was die Binary dann tatsächlich auch ausführt. Also noch eine Ebene höher, zurück in die Funktion exec_binprm. Nach dem Aufruf von search_binary_handler passieren ab hier noch 4 Funktionsaufrufe, bei denen ich aber auch kein Setzen eines Flags finden konnte.
Wo wird denn das Flag für den Protected Mode gesetzt und der Code der Binary dann tatsächlich ausgeführt?
Der eigentliche Grund für meine Frage ist, dass ich verstehen will, wie der Kernel seinen Code weiter im Real Mode ausführen kann, User-Mode-Code aber im Protected Mode. So wie ich es verstanden habe, handelt es sich ja um ein Prozessor-Flag, das man setzt und das dann aktiv bleibt. Stimmt das gar nicht?
-
Mist, ich hab das Ganze falsch verstanden gehabt: Ich dachte, dass gilt:
- Real Mode = Kernel Mode
- Protected Mode = User Mode
Dem ist aber nicht so. Das wird über die Protection Rings gehandhabt.
Eine Frage bleibt aber für mich weiterhin offen: Wo wird der Code aus der jeweiligen Datei ausgeführt, nachdem der Syscall execve aufgerufen wurde?
-
LinuxVersteher schrieb:
Der eigentliche Grund für meine Frage ist, dass ich verstehen will, wie der Kernel seinen Code weiter im Real Mode ausführen kann, User-Mode-Code aber im Protected Mode. So wie ich es verstanden habe, handelt es sich ja um ein Prozessor-Flag, das man setzt und das dann aktiv bleibt. Stimmt das gar nicht?
Ich bin nicht ganz sicher wie der Linux Kernel das macht, aber bei nicht uralt x86 Prozessoren sollte das inzwischen einfach über die Maschinenbefehle sysenter/sysexit (Intel) oder syscall/sysret (AMD) gehen. Der Prozessor wechselt dabei selbstständig von Ring 3 zu Ring 0 und zurück. Das hat allerdings auch Voraussetzungen daran wie Segmentierung, Paging etc. vom OS konfiguriert wurden.
Finden könntest du das bei den Interrupt und Syscall handlern.
-
Danke Tobiking2, auf die von dir genannten Befehle bin ich ebenfalls gestoßen.
Zu meiner ursprünglichen Frage hab ich auch noch was rausgefunden: execute startet gar keinen neuen Prozess, sondern überschreibt im Erfolgsfall den aktuellen Prozess mit den Daten aus dem, den man ausführen will. Was dabei die einzelnen beteiligen Funktionsaufrufe machen, hat ein Typ hier erklärt. Ich werde mir wohl mal fork() zu Gemüte führen, das startet ja meines Wissens wirklich einen neuen Prozess.
Gibt es denn eine Webseite, die anhand des Quellcodes erklärt, wie was in Linux funktioniert? Es ist sehr mühsam, das alles manuell raussuchen zu müssen. Oder kann man einen laufenden Kernel wenigstens irgendwie debuggen, um zu schauen, was z. B. bei syscalls passiert?
-
LinuxVersteher schrieb:
Oder kann man einen laufenden Kernel wenigstens irgendwie debuggen, um zu schauen, was z. B. bei syscalls passiert?
Mit Qemu oder Bochs kannst du ein x86 System emulieren und dich mit dem GDB drauf verbinden um es von außen zu debuggen. Man muss nur schauen das man die Debug Symbole des Kernels bekommt, sonst sieht man relativ wenig.