Beiträge anzeigen

Diese Sektion erlaubt es dir alle Beiträge dieses Mitglieds zu sehen. Beachte, dass du nur solche Beiträge sehen kannst, zu denen du auch Zugriffsrechte hast.


Nachrichten - Dimension

Seiten: [1] 2 3 ... 8
1
OS-Design / Re: Qemu = ok, echt Hardware = Auaa... ;(
« am: 14. February 2014, 08:17 »
Wie kann man den einen Kernel töten?
Mit der Kreissäge? Aus deiner Perspektive befindet sich der Kernel in der Matrix.
2
Offtopic / Re: NSA und die Sicherheit von Betriebssystemen
« am: 22. January 2014, 16:35 »
Vorschlag: schreib dir einen x86 emu, der A: deinen Browser ausführt, B: die Betriebssystem API inkl. Treibern und C: Graphik, Eingabegeräte und Netzwerkkarten emuliert. Der D: mittels Debugsymbolen Speichergrenzen überwacht und E: alle API Aufrufe loggt und bei Anomalien warnt.

Schreib den Emu in einer verwalteten Sprache.

Im Hostsystem dann den Zugriff auf alle Graphik- und Fontrenderingbibliotheken sperren, die Treiber für die Netzwerkkarte entfernen und diese per PCI durchschleifen.

Wünsche viel Spaß xD
3
Offtopic / Re: Hello Lowlevel!
« am: 19. January 2014, 14:05 »
Nimm einen aktuellen Linux-Kernel oder gleich eine komplette Distro. Mach deine Umgebung als Kernel-Modul oder einfach als Dienstprogramm. Lasse dieses mit dem X server reden oder nimm gleich den vorhandenen GUI Manager.

Wirf alles raus, was du nicht brauchen kannst.

Deine Programme werden vermutlich mit v8 ausgeführt und mit Webkit gerendert. Gib deinen Programmen eine minimale Schnittstelle zum System.

Wenn du nur vorhandene Bibliotheken nutzt, wirst du noch dieses Jahr fertig. Möchtest du Teile des Systems ersetzen, kannst du das dann immer noch tun.
4
Ein 4096 Bytes großer Stack reicht für 42 Funktionsaufrufe mit einem Äquivalent von 10 64-Bit Ints als Parameter oder lokale Variablen. Interrupts sollten nicht re-entrant sein, also nicht während einer ISR auftreten dürfen. Ich setze den Stack an den Segmentanfang um Overflows zu erkennen. In der Mainloop meines Schedulers wird der Kernel-Stack nach jedem Task zurückgesetzt, da hier eh keine lokalen Variablen liegen.
5
Lowlevel-Coding / Re: Welche Geräte gehören zu PCI?
« am: 25. May 2013, 22:05 »
Also ist es damit dann möglich, dem SATA-Controller zu sagen er soll die Daten in den Speicher laden, also das DMA-System von PCI nutzen? Ich habe nämlich gehört, dass dies mit fragmentierten Speicherbereichen arbeiten kann.
DMA arbeitet mit physischen Speicheradressen. Der Treiber muss virtuelle Adressen zuerst umwandeln oder gleich physische Speicherbereiche anfordern. Der physische Speicher muss zusammenhängend sein, eventuell reichen auch eine einzelne 4KB-Pages.
6
Nachdem ich vor einer halben Stunde meinen PC eingeschaltet habe ist er abgestürzt und [...] jetzt sind fast alle meine Dateien weg

Uuuuh, das läuft bei mir unter "Panikattacke" direkt nach rm -rf falscher_ordner und dd if=ziel of=quelle
7
Offtopic / Re: Logisim CPU
« am: 15. May 2013, 10:53 »
Ich glaube er will bestimmte Prozedureinsprungspunkte markieren, so dass diese bei Aufruf in einen privilegierten Modus wechseln und mit privilegierten Rechten ausgeführt werden. Vor dem RET muss die privilegierte Funktion den privilegierten Modus beenden, da die Markierungen nur in eine Richtung funktionieren.

Diese Markierungen und das "privileged mode Flag" sind wiederum nur schreibbar, wenn der privilegierte Modus aktiv ist, so auch beim Systemstart.

Aber so richtig verstanden habe ich es wohl auch nicht.
8
Dieser Fix hat natürlich nur eingeschränkte Auswirkung auf die gesamte Anwendung. Dass dem so ist wird vom Editor per Datenflussanalyse geprüft.
Von so Dingen wie "Turing-Vollständigkeit" und "Halteproblem" hast du gehört und weißt, dass damit jede Datenflussanalyse deutliche Grenzen hat?

Das bedeutet nur, dass das Verhalten nicht für jeden Code vorhersagbar ist. Zumindest kann man aber mit Bestimmtheit sagen, ob der (Teil-)Code deterministisch ist oder nicht.

Und wer programmiert den Updater in seiner ganzen Komplexität fehlerfrei?

Das gesamte System ist in erster Linie dazu gedacht so eine Komplexität kontrollieren zu können. Anwendungs-Software wird meiner Meinung nach auch so immer komplexer werden, sei es um verschiedene Zielgruppen anzusprechen, individuellen Kundenanforderungen gerecht zu werden oder einfach nur ein Entwicklerteam von mehreren hundert Leuten zu koordinieren.

Die vorgstellten Szenarien lassen sich auch auf beliebige andere Anwendungsfälle übertragen.
9
Ich benutze ein Programm und entdecke einen schwer zu reproduzierenden Bug. Ich sende ein Speicherabbild des Programms und eine Aufzeichnung der letzten 10 sek. an den Entwickler. Eventuell schaue ich mir den Code an und schreibe mir selbst einen Fix. Diesen kann ich direkt an den Entwickler weiterleiten und jedem, der ebenfalls einen Fix schreiben will über einen Kommentar im Code zum Download anbieten. Dieser Fix hat natürlich nur eingeschränkte Auswirkung auf die gesamte Anwendung. Dass dem so ist wird vom Editor per Datenflussanalyse geprüft.
10
Gib mal Beispiele, die man heute nicht erreichen kann.

Wie wärs damit:

Ein User postet auf lowlevel und hat ein Problem mit einem Stück Code. Er postet seine Entwicklungsumgebung und jeder kann es im Browser testen. Die funktionierende Lösung holt der User sich dann zurück auf seinen Rechner.

Ein Developer-Tutorial oder ein Referenzhandbuch im Internet ist mit Beispielen. Die Beispiele lassen sich im Browser ausführen.

Es wurde ein Update für den Browser veröffentlicht. Ich habe gerade einen 80GB-Download bei 50%. Ohne das Update browse ich gefährlich. Der Browser macht einen Snapshot seines Speichers und macht das Update unter Berücksichtigung der aktuell ausgeführten Programmteile.

Ich arbeite zuhause an einem Projekt und will im Geschäft daran weiter arbeiten. Ich transferiere meine komplette Arbeitsumgebung auf ein Tablet und gehe unterwegs noch mal alle Punkte durch. Im Geschäft angekommen öffne ich das Projekt an meinem Arbeitsplatz und setze meine Arbeit fort.

Nur so als Inspiration.

Gruß
11
Offtopic / Re: Bis wann ist ein OS ein OS?
« am: 22. March 2013, 12:42 »
Jetzt mal was ganz anderes, wenn man z.B. einen Virus schreiben will, muss man sich mit dem Programm/Betriebssystem besser auskennen als der Entwickler?
Wenn ICH einen Virus schreiben wollen würde, würde ich mir zuerst alle Programme und Betriebssysteme vornehmen, die weit verbreitet sind: Web-Browser, Email-Clients, PDF-Reader, Office-Programme sowie Spiele und bei den Betriebssystemen Windows, Linux und Mac OS. Bei den Betriebssystemen würde ich mir vor Allem die Libraries für den Netzwerkstack, Treiber allgemein, Videocodecs und Grafikroutinen vornehmen.

Dann würde ich mir einem Emulator schreiben, der die entsprechende Umgebung simuliert und den Maschinencode des entsprechenden Programms oder der Library ausführen kann. Mit diesem Emulator würde ich für jedes Stück Code analysieren, in welchem Kontext dieses normalerweise ausgeführt wird. Dazu betrachte ich den Callstack, die Parameter und die globalen Variablen. Dann untersuche ich den Code auf mögliche use-after-free, integer-overflows, buffer-overflows und besonders stack-overflows. Überall wo Arrays indiziert oder Puffer verwendet werden reicht eine fehlende Bereichsprüfung um den Stack zu manipulieren. Niemand schreibt Code mit Checks bei jeder Adressberechnung. Format-Bugs lasse ich mal außen vor, die können mit einfachen Mitteln behoben werden.

Mit einem funktionierenden Exploit würde man schon mal in den Usermode kommen. Hier kann man bereits beliebige DLLs patchen, um etwa SSL abzufangen, Mails mitzulesen oder Passwörter zu klauen. Über das Dateisystem lassen sich versendete Dateien oder USB-Sticks infizieren. Aus dem Usermode lässt sich auch sehr bequem ein Dienst einrichten, der sich in den Autostart schreibt und so bei jedem Start geladen wird (bei XP, Win 7 weiss ich nicht genau).

Um vom Usermode zum root zu kommen reicht ein weiterer Overflow in irgendeiner Library oder Treiber. Am effektivsten ist es, Code dort im Kernel zu platzieren, wo er häufig ausgeführt wird. Wenn man es darauf anlegt, kann man auch in dem Bootloader gehen und alles virtualisieren, was eine Entdeckung riskieren würde.

Die Kommunikation würde ich über frei verfügbare Online-Dienste machen und zwar in beliebigen XML-Formaten oder anderen geläufigen Formaten, welche die Kommandos enthalten. Je nach Typ der Schwachstelle kann man über das Netzwerk weitere Computer infizieren oder den Schadcode mit Dateien versenden. Eine Entdeckung durch Virenscanner vermeidet man in der Regel, indem man einen kleinen Compiler für eine rudimentäre Sprache verwendet, der sich selbst und seine Payload in diversen Variationen generieren kann. Eventuell versteckt sich der echte Code noch zwischen einem großen Haufen nutzlosem Maschinencode. Den Exploit an sich kann man auch variieren oder an unterschiedlichen Stellen im Dokument platzieren.

Aber ich bin ja einer von den guten ;-)
12
Weder Windows noch Linux erlauben einem Benutzer, Dienste im Hintergrund zu starten oder unbeabsichtigte, das System beeinflussende, Dinge zu tun.
Wirklich? Also ich habe da schon ganz andere Geschichten gehört.

Die Sicherheit soll hardwareseitig, durch das Design und durch Runtime-Checks gewährleistet werden.
Das heißt, du setzt moderne Hardware voraus (IOMMU, 64-Bit-Modus), verzichtest damit auf Segmentierung und arbeitest ausschließlich mit "managed Code" in einem Hypervisor.
Siehe aktualisierte Posts vom 18. März 2013, 21:09 und 20. März 2013, 23:22.

Willst du wirklich den Source-Code von Firefox, Chrome, Internet Explorer einsehen und zur Laufzeit ändern können? Glaubst du, es gibt Programmierer auf dieser Welt, der in der Lage ist, sich auf die Schnelle in solch ein Mammutprojekt einzulesen und seiteneffektfreie Änderungen vorzunehmen?
Nehmen wir einmal an, du hast ein Programm und willst diesem eine Funktion hinzufügen, die dir das Arbeiten erleichtert. Wenn dieses Programm überhaupt Scripting bereitstellt, wie willst du damit die Benutzeroberfläche erweitern und vorhandenen Code des Programms anpassen? Geht das auch bei Anwendungen, die auf dem Server laufen? Bei meinem System reicht ein Klick mit gehaltener F-Taste auf das Fenster und das zu bearbeitende Formular und alle verknüpften Ereignisse werden im Editor geöffnet. Da die Symbole im Editor sofort aufgelöst werden, sind die Effekte direkt sichtbar.
13
ich fasse zusammen, was ich da rauslese (bei Fehlern bitte korrigieren):
- du programmierst den Kernel extrem defensiv, auf Kosten der Performance

Ich versuche den Kernel so übersichtlich zu machen, wie es geht. Wenn ein Codestück zu komplex wird, schmeisse ich es weg, verzichte auf ein unwesentliches Merkmal und schreibe es einfacher.

Die Sicherheit soll hardwareseitig, durch das Design und durch Runtime-Checks gewährleistet werden. Ich will dass User im Internet surfen können ohne ein schlechtes Gewissen zu bekommen und beliebige Software herunterladen und ausführen können ohne dass diese unbeabsichtigte Dinge tun oder Dienste im Hintergrund starten.

Ich will außerdem, dass ein Programm beliebig angehalten und sein Zustand gespeichert werden kann, um es mit ins Büro zu nehmen oder einem Bekannten zu schicken. Eine Präsentation im Internet bedeutet, ich kann die Show anhalten und das Programm selbst ausprobieren.

Ich will mein Betriebssystem und alle darauf laufenden Programme mit nur einem Klick im Editor bearbeiten können, etwa um eine Suchmaske zu ändern oder ein Programm zu scripten.

Einen mehrstündigen Kompiliervorgang oder einen aufwändigen Testlauf will ich auf einem schnellen Server parallelisiert ausführen, während ich ein Forum im Internet auch gerne mal offline lesen möchte.

Wenn ich Windows oder Linux benutze sehe ich immer nur was alles nicht geht.

Gruß
14
Sobald ein System-Prozess spezielle Berechtigungen anfordert, hat dieser eine gewisse Verantwortung.
Damit fallen also alle Treiber unter die Trusted Computing Base. Hätten wir das also geklärt. :-)
Das tun sie. Und sie profitieren vom Buffer-Overflow-Schutz der Sandbox. Mittels sparsam vergebenen Berechtigungen weiss man, wo man genau hin schauen muss (in Container-Sandboxen werden diese für alle untergeordneten Prozesse abgefangen).
15
Sobald ein System-Prozess spezielle Berechtigungen anfordert, hat dieser eine gewisse Verantwortung.

Die Treiber sind weiterhin Teil des Betriebssystems und werden entsprechend robust sein. Solange der Treiber sich nur auf seine eigentliche Aufgabe konzentriert und keine optionalen Funktionen implementiert sehe ich da keine Gefahr.

Siehe auch bearbeiteten Post zu DMA.
16
Die Berechtigungen geben Ports und MMIO-Bereich vor und der DMA wird vom Kernel ausgeführt. Geräte sollten bestenfalls nicht Busmaster werden dürfen, da hast du natürlich recht.

Der Kernel implementiert grundlegende Protokolle wie PRDT (ATA über DMA). Falls die Hardware unbedingt Busmaster werden muss, bekommt sie halt einen reservierten Speicherbereich.

Spezielle Berechtigungen, die den Kernel und die Treiber betreffen sind auf Systemprozesse beschränkt.
17
Ich schrieb "es gibt keine Hardwaretreiber". Das ist was anderes.
Und nicht so gedacht. Bus-, Chipsatz- und Gerätetreiber laufen als Prozess. (Siehe aktualisierten Post.)

Ein user-Prozess kann mit der entsprechenden Berechtigung Funktionen im Kontext des Prozesses mit den Treibern aufrufen.
18
Windows Programme brauchen eine Win-API
Linux-Programme brauchen eine Linux-API
Java-Programme brauchen eine JVM
.NET-Programme brauchen eine CLR
Javascript braucht einen JIT-Compiler

Das System läuft direkt auf x86-Hardware, somit weiss ich nicht, was du jetzt genau meinst.

Gruß
19
Die Sandbox realisiere ich wie folgt:

Ebenen:
1: Speicherverwaltung
2: Datenzugriff & Berechtigungen
3: Sandbox
4: Prozesse (in Containern strukturiert)

Die Sandbox führt User-Code in Ring 3 aus. Der Code wurde zuvor in eine spezielle 4KB-Seite geladen. Ein spezieller Compiler erzeugt diese entsprechenden 4KB-Frames. Aus Ring 3 ist nur eine spezielle Seite adressierbar, die Daten enthält, die zuvor aus dem Speicher des Prozesses kopiert wurden. Nach Ablauf der Berechnung werden die Daten wieder zurück geschrieben.

Treiber würden sich auf Ebene 4 und der Scheduler zwischen Ebene 2 und 3 befinden. Interrupts werden in eine Warteschlange geschrieben und von einem Prozess verarbeitet.

Die Berechtigungen eines Prozesses geben an, welcher Speicher zugreifbar ist und ob spezielle Befehle erlaubt sind. Befehle, die in Ring 3 verboten sind werden von der Sandbox emuliert, etwa Portzugriff und DMA (nur für System-Prozesse). Der Code von Ebene 1 bis 3 und System-Prozesse mit speziellen Berechtigungen sind kritisch für die Sicherheit des Systems.

Sicherheitskritischen Code schreibe ich wie folgt:
Überprüfen aller Parameter auf Wertebereich und erlaubte Kombinationen
Überprüfen der Grenzen für die Index- und Adressberechnung
Keine Arrays/Puffer auf dem Stack
Checks gegen alle möglichen Integer-Overflows, Division nur mit Immediate
Einfache Codestruktur: einfache deterministische Schleifen, keine Rekursion, keine Pointer-Magie, kaum verschachtelte Calls
Keine speziellen Spracherweiterungen oder Befehle

Der Code kommt in ein Segment ohne Schreibrechte. BIOS, IDT und GDT werden nicht gemappt. Weitere Segmente sind Daten+Stack für den Kernel, Code- sowie Daten-Frames für die Sandbox, MMIO, und das große Segment für den dynamische allozierbaren Speicher.

Ein Angriff würde sich auf die Segmente des Kernels konzentrieren, insbesondere auf das Code-Segment, auf den Stack (ROP), die Tabellen der Speicherverwaltung und die Bereiche der Festplatte, von der das System gebootet wird. Außerdem könnte versucht werden auf Speicher anderer Prozesse unerlaubt zuzugreifen und erweiterte Berechtigungen zu erhalten oder Das System durch viele Prozesse oder Einträge in den Verwaltungsdaten zu überlasten. Des weiteren könnte ein Angreifer versuchen die Rücksprungadresse auf dem Stack zu verändern, so dass die Instruktionen anders interpretiert werden.

Durch die Segmentierung werden Buffer-Overflows in die Kernel-Segmente oder die ungemappten Bereiche hardwareseitig verhindert, somit können nach dem Starten des Systems das Kernel-Codesegment, die IDT, die ISR und die GDT nicht mehr verändert werden. Ein Problem stellt hier allerdings noch DMA dar, weil auf 32-Bit Systemen jedes PCI-Gerät uneingeschränkt auf den gesamten Speicher zugreifen kann. Hier muss man der Hardware und ihren Treibern vertrauen und/oder die Treiber absichern.

Da der sicherheitskritische Teil des Kernels (ohne Treiber) nur einige 1000 Zeilen Code umfasst, kann er leicht geprüft werden.
20
Ich will hier kurz den Task-Scheduler und den Speichermanager aus meinem Kernel vorstellen und Details zur Implementierung verraten.

Der Scheduler

Nachdem ich über längere Zeit nicht mehr am Kernel gearbeitet habe, bin ich nun endlich wieder dazu gekommen. In den letzten Tagen habe ich am Scheduler gearbeitet. Anforderungen an diesen waren: Taskwechsel in konstanter Zeit, Prioritäten, gewichtete Verteilung der Ausführungszeit und die Strukturierung in Unter-Tasks. Ein Programm soll über seine Rechenzeit frei verfügen und an Unterprogramme verteilen können, aber keinesfalls Programme überhalb seiner Position im Baum beeinträchtigen. Damit wird verhindert, dass sich das System "aufhängt" und nicht mehr auf Benutzereingaben reagiert.

Die Tasks sind zu einer Liste verkettet. Wenn ein Task seine Ausführungszeit verbraucht hat, wird der nächste Task aufgerufen. Die Ausführungszeit des Schedulers wird mitgezählt, Abweichungen zur geplanten Zeit werden auf die nächsten Slice angerechnet. Durch Timeout-Interrupts wird garantiert, dass kein Task seine Ausführungszeit um das Vielfache überschreitet. Die Unter-Tasks sind ebenfalls alle in dieser Liste enthalten. Sobald ein Task mit höherer Priorität aktiv wird, wird die Liste an Beginn und Ende des übergeordneten Containers aufgetrennt und ein anderes Stück eingefügt. Die Position im Teilstück wird gespeichert. Die parallelen Pfade liegen alle im Speicher vor, sind jedoch erstmal nicht mit der Liste verkettet. Suspend/Resume, Spawn/Terminate und Änderung der Priorität arbeiten zuerst auf der Baumstruktur und aktualisieren dann die Liste in konstanter Zeit.

Ich habe mir Gedanken gemacht über die Anzahl der Taskwechsel pro Sekunde (Overhead), die maximale Antwortzeit von Tasks mit hoher Priorität, sowie das Intervall, bis ein Task nach seiner Ausführung wieder aufgerufen wird.

Folgende Konfiguration war das Resultat:

2G Takte/sek
800 aktive Prozesse (Äquivalent)
256K Takte/Zeitscheibe
8K Zeitscheiben/sek
100ms Intervall für erneuten Aufruf eines Tasks
0.125 ms/Zeitscheibe
< 1ms maximale Antwortzeit (des aktiven Tasks mit der höchten Priorität)


Die Speicherverwaltung

Vor dem Scheduler habe ich an der Speicherverwaltung gearbeitet. Die Anforderungen an diese waren: malloc, free und realloc in konstanter Zeit und keine Fragmentierung oder Performanceverlust nach sehr langer Uptime.

Der Speicher wird in 4KB-Seiten verwaltet. Bereiche kleiner 4KB werden innerhalb der Seite in einer Bitmap verwaltet, Bereiche größer 4KB werden aus mehreren 4KB-Seiten zusammengesetzt. Welche Seiten aneinander gereiht werden, steht in einer Tabelle. Elemente eines Vektors oder andere Zugriffe mit Offset dürfen die Seitengrenze nicht überlappen. Elementare Datenstrukturen, sowie die Funktionen memset(), memcpy() und memcmp() habe ich entsprechend implementiert. Details zu jeder einzelnen Seite stehen in einer weiteren Tabelle, dort sind die Seiten in diversen Listen verkettet. Seiten mit freien Slots kleiner 4KB, Slots in der Tabelle für große Bereiche oder die nächste freie Seite können in konstanter Zeit gefunden werden.

Ich habe mir auch Methoden für effizientes garbage Collecting überlegt, bin aber zu keinem Ergebnis gekommen. Als einzige Möglichkeit ohne Auswirkungen auf die Performance sehe ich die Implementierung in Hardware.

Gruß
Seiten: [1] 2 3 ... 8

Einloggen