4

Click here to load reader

Unix fork und exec vs. Windows create process

Embed Size (px)

Citation preview

Page 1: Unix fork und exec vs. Windows create process

fork und exec vs. CreateProcessDie wunderbare Welt von Isotopp

Sonntag, 7. Januar 2007fork und exec vs. CreateProcessDisclaimer: Meine Windows­Kenntnisse sind beschränkt, veraltet und ausschließlichtheoretischer Natur. Im Zweifel erzählt dieser Artikel Unsinn nach Hörensagen.

Nach dem Artikel form, exec, wait und exit habe ich mir aber einmal meine Kopie vonJeffrey Richters Windows ­ Programmierung für Experten (Advanced Windows) (1997)gegriffen und dort nachgeschlagen, wie man sich das mit den Prozessen und Programmenunter Windows vorstellt (oder jedenfalls vor 10 Jahren vorgestellt hat).

Windows hat zu diesem Zweck die Systemfunktion CreateProcess(10 Parameters). Dieliest sich so:

BOOL WINAPI CreateProcess(LPCTSTR lpApplicationName,LPTSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCTSTR lpCurrentDirectory,LPSTARTUPINFO lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation);

Die Funktion erzeugt einen neuen Prozeß und lädt in diesen ein neues Programm. Dieseswird dann gestartet. lpApplicationName ist der Pfadname des auszuführendenProgrammes.

lpCommandLine ist die Kommandozeile (der argv) des neuen Programmes. Sie wird alsString und nicht als Vektor von Strings übergeben. Das Parsen der Kommandozeile in Wortwird also durch das Betriebssystem übernommen und kann nicht durch den Aufruferkontrolliert werden. In Unix muß man bei execve() einen Vektor von Strings übergeben, dasZerlegen der Kommandozeile in Worte muß also durch den Aufrufer, z.B. die Shellübernommen werden. Die anderen Funktionen der exec­Familie sind Bibliotheksfunktionen,die einem hier einen Teil der Arbeit abnehmen.

lpApplicationName und lpCommandLine interagieren: lpApplicationName darf NULL sein,dann wird das erste Wort von lpCommandLine nach der Zerlegung in Worte alslpApplicationName interpretiert. lpApplicationName darf ohne Endung angegeben werden,dann rät Windows die Extension bzw. probiert eine Liste von ausführbaren System­Extensions aus.

lpApplicationName darf auch ein unqualifizierter Pfadname sein. In diesem Fall wird dasAbsuchen eines System­Suchpfades wird durch diese Funktion von Windowsübernommen. In Unix führt execve() genau das Binary aus, dessen Pfadnamen man

Page 2: Unix fork und exec vs. Windows create process

angegeben hat. Will man einen Suchpfad absuchen, muß man execve() in einer Schleife solange ausführen, bis es nicht mehr zurück kommt.

lpProcessAttributes ist kein einzelner Parameter, sondern ein Zeiger auf eineSECURITY_ATTRIBUTES­Struktur, die man ausfüllen kann und die viele Parameterenthalten kann. Die Struktur enthält eine ACL für die Discretionary Access Control,bestimmt also im wesentlichen, wer diesen Prozeß anfassen und was mit ihm machen darf.In Unix gibt es kein vergleichbares Konzept für Prozesse: Ein Prozeß hat entweder dieentsprechende Capability (etwa CAP_KILL oder CAP_SYS_PTRACE) oder nicht.

lpThreadAttributes erzeugt ist der passende Parameter für den in dem Prozeß zwingendenthaltenen Thread. bInheritHandles definiert, ob vererbbare Handles auf Objekte von demneu erzeugten Prozeß geerbt werden.

dwCreationFlags legt die Priorität des Prozesses und weitere Flags für den neuen Prozeßfest. In Unix würde man all dies zwischen dem fork() und dem exec() mit einzelnen Callsmachen, etwa mit Calls aus der setpriority()­Familie oder mit Aufrufen nach setpgrp().

lpEnvironment entspricht konzeptuell, aber nicht im Format dem envp von execve.

lpCurrentDirectory ist das aktuelle Verzeichnis des neuen Prozesses. In Unix würde manden identischen Effekt erreichen, indem man zwischen dem fork() und dem exec()­Systemaufruf ein chdir() (oder chroot()) aufruft.

lpStartupInfo ist ein Zeiger auf eine eine Struktur STARTUPINFO, die keine Entsprechungin Unix hat, weil hier Dinge angegeben werden, die mit den Fenstern einer Anwendung zutun haben. Unix handhabt diese Dinge komplett vom Betriebssystemkern getrennt unddaher finden wir in den Betriebssystem­Primitiven zu Prozessen keineFensterinformationen. Genaugenommen ist lpStartupInfo entweder ein Zeiger auf eineSTARTUPINFO oder STARTUPINFOEX­Struktur. Was es genau ist wird mit einem Flag indwCreationFlags angegeben. Das ist nicht typsicher, und das ist bemerkenswert, weilWindows an anderer Stelle sehr viel Wert auf solche Dinge legt.

Der letzte Parameter von CreateProcess, lpProcessInformation, ist ein Referenzparameterauf eine PROCESS_INFORMATION­Struktur, die von Windows überschrieben undausgefüllt wird. Wir finden dort die Handles zu unserem Prozeß und dem darin enthaltenenThread sowie eine ProcessId und eine ThreadId.

Will man das Äquivalent zu einem setuid()­Eignerwechsel in Unix in Windows durchführen,kommt dieses Konzept an seine Grenzen ­ so etwas ist trotz der Vielzahl der Parametervon CreateProcess() in Windows nicht vorgesehen. Man braucht eine neue Funktion,CreateProcessAsUser(11 Parameter).

Analyse

Hier wird der grundlegende Unterschied zwischen den Konzepten von Windows und Unixdeutlich: Die Unix­API stammt von Mitte der 70er Jahre und hat sich in den vergangenenmehr als 30 Jahren nicht wesentlich verändert.

Sie genügt heutigen Ansprüchen, weil sie alle Ansprüche nicht erfüllt ­ sie liefertstattdessen relativ atomare primitive Funktionen und trennt sogar auf den ersten, flüchtigenBlick zusammengehörende Dinge wie Erzeugen von Prozessen und Laden vonProgrammen. Dadurch muß ein Programmierer einer Anwendung entweder eineBibliotheksfunktion verwenden, die fork() und exec() in etwas bequemeres einpackt (etwasystem() oder popen()) oder all die Dinge selber machen, die Windows im Kernel für denProgrammierer erledigt. fork() hat keine Parameter und execve() hat deren drei.

Will man mehr, hat man die Gelegenheit, das Environment des neuen Prozesses nach demfork() vor dem Start des neuen Programmes mit execve() von innen zu verändern.

Page 3: Unix fork und exec vs. Windows create process

Windows dagegen erzeugt eine alles­in­einem Funktion, die für den häufigenAnwendungsfall und alle denkbaren Varianten Extraparameter hat. Windows hat dabei dieSicht von außen auf den Kindprozeß. Dies führt zu nützlichen Dingen wie einer Thread­und Prozeß DACL, ist aber konzeptuell nicht gut erweiterbar. Dinge wie ein setuid()­Aufrufzwischen fork() und exec() sind mit CreateProcess() nicht abbildbar und machen weitereFunktionen erforderlich, die noch mehr Parameter haben.

Das Konzept von Unix ist auf den ersten Blick umständlich und wenig intuitiv. Es genügtvon der Aufteilung her jedoch den Ansprüchen, die man als Datenbanker an eineNormalform hätte und ist daher flexibel und ohne Änderungen am Kern erweiterbar ­unabhängige Konzepte sind als unabhängige Funktionen implementiert und Erweiterungerfolgt durch Einschieben weiterer Aufrufe zwischen fork() und exec(). Neben dem Vorteilder Erweiterbarkeit hat dies den Nachteil, daß mehr Systemaufrufe notwendig sind als beiWindows (Unix­Systemaufrufe müssen schnell sein, damit dieses Konzept aufgeht) unddaß man unter Umständen ein Problem mit der Atomizität bekommen kann.

Beispiel ist hier die Aufgabe: "Starte aus einem Debugger einen Programm in einemKindprozeß und zwar so, daß der Kindprozeß ohne Racecondition auf der erstenAnweisung des Kindes stoppt und debugbar ist.". Das Problem war lange Zeit nicht lösbar,und wurde von Linux durch das PTRACE_TRACEME­Flag zu ptrace() gelöst, das nebeneinigen anderen Dingen bewirkt, daß ein Kindprozeß nach einem execve() erst mal miteinem SIGTRAP stehen, bleibt bevor er irgendwas selber macht. Bemerkenswert ist, daßdie Erweiterung möglich war, ohne das bestehende 30 Jahre alte Konzept von fork, execund wait verändern zu müssen.Geschrieben von Kristian Köhntopp in Schulung um 09:06 | Kommentare (3) | Trackbacks (0)

TrackbacksTrackback­URL für diesen Eintrag

Keine Trackbacks

KommentareAnsicht der Kommentare: (Linear | Verschachtelt)

Das man für das Ausführen eines anderen Programmes erst forken muß, finde ich aber nachwie vor absurd. Erst dank copy­on­write wird dabei heutzutage wenigstens nicht mehr derganze Prozess erst kopiert, um diese Kopie dann sofort wieder wegzuwerfen.#1 kju am 08.01.2007 09:07

I tend to disagree. Die Trennung von fork() und exec() ist IMHO eine Generalisierung, diees moeglich machte, sowohl Nebenlaeufigkeit als auch das Ausfuehren einesProgrammes im aktuellen oder einem neuen Prozess zu implementieren.#1.1 ak (Link) am 08.01.2007 12:23

> Dinge wie ein setuid()­Aufruf zwischen> fork() und exec() sind mit> CreateProcess() nicht abbildbar

Du kannst nen neuen Thread starten, dort dann beliebige impersonations vornehmen unddann den CreateProcess machen.

Das Impersonation Model mit den ACLs und den Security Descriptoren finde ich in Windowseinfach klasse.

Ansonten stimme ich aber zu, manchmal sind die Systemfunktionen in der Win32 API einwenig überladen.

Aber dafür gibts dann ja .Net :)

Page 4: Unix fork und exec vs. Windows create process

Bernd

#2 Anonym am 08.01.2007 14:07

Kommentar schreibenName

E­Mail

Homepage

Antwort zu

Kommentar

Umschließende Sterne heben ein Wort hervor (*wort*), per _wort_ kann ein

Wort unterstrichen werden.

Um maschinelle und automatische Übertragung von Spamkommentaren zu

verhindern, bitte die Zeichenfolge im dargestellten Bild in der Eingabemaske

eintragen. Nur wenn die Zeichenfolge richtig eingegeben wurde, kann der

Kommentar angenommen werden. Bitte beachten Sie, dass Ihr Browser

Cookies unterstützen muss, um dieses Verfahren anzuwenden.

Hier die Zeichenfolge der Spamschutz­Grafik eintragen:

BBCode­Formatierung erlaubt Daten merken?