doc/de_DE.ISO8859-1/books/developers-handbook/secure/chapter.sgml
2012-09-14 17:47:48 +00:00

637 lines
23 KiB
XML

<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
<!--
The FreeBSD Documentation Project
The FreeBSD German Documentation Project
$FreeBSD$
$FreeBSDde: de-docproj/books/developers-handbook/secure/chapter.sgml,v 1.16 2010/12/18 13:28:29 jkois Exp $
basiert auf: 1.30
-->
<chapter id="secure">
<chapterinfo>
<authorgroup>
<author>
<firstname>Murray</firstname>
<surname>Stokely</surname>
<contrib>Contributed by </contrib>
</author>
</authorgroup>
<authorgroup>
<author>
<firstname>Hagen</firstname>
<surname>Kühl</surname>
<contrib>Übersetzt von </contrib>
</author>
</authorgroup>
</chapterinfo>
<title>Sicheres Programmieren</title>
<sect1 id="secure-synopsis">
<title>Zusammenfassung</title>
<para>Dieses Kapitel beschreibt einige Sicherheitsprobleme, die
&unix;-Programmierer seit Jahrzehnten quälen, und
inzwischen verfügbare Werkzeuge, die Programmierern helfen,
Sicherheitslücken in ihrem Quelltext zu vermeiden.</para>
</sect1>
<sect1 id="secure-philosophy">
<title>Methoden des sicheren Entwurfs</title>
<para>Sichere Anwendungen zu schreiben erfordert eine sehr
skeptische und pessimistische Lebenseinstellung. Anwendungen
sollten nach dem Prinzip der <quote>geringsten
Privilegien</quote> ausgeführt werden, sodass kein Prozess
mit mehr als dem absoluten Minimum an Zugriffsrechten arbeitet,
die er zum Erfüllen seiner Aufgabe benötigt. Wo es
möglich ist, sollte Quelltext, der bereits
überprüft wurde, wiederverwendet werden, um
häufige Fehler, die andere schon korrigiert haben, zu
vermeiden.</para>
<para>Eine der Stolperfallen der &unix;-Umgebung ist, dass es
sehr einfach ist Annahmen über die Konsistenz der Umgebung
zu machen. Anwendungen sollten Nutzereingaben (in allen Formen)
niemals trauen, genauso wenig wie den System-Ressourcen,
der Inter-Prozess-Kommunikation oder dem zeitlichen Ablauf von
Ereignissen. &unix;-Prozesse arbeiten nicht synchron. Daher sind
logische Operationen selten atomar.</para>
</sect1>
<sect1 id="secure-bufferov">
<title>Puffer-Überläufe</title>
<para>Puffer-Überläufe gibt es schon seit den
Anfängen der Von-Neuman-Architektur <xref linkend="COD"/>.
<indexterm><primary>Puffer-Überlauf</primary></indexterm>
<indexterm><primary>Von-Neuman</primary></indexterm>
Sie erlangten zum ersten Mal durch den Internetwurm Morris im
Jahre 1988 öffentliche Bekanntheit. Unglücklicherweise
<indexterm><primary>Morris Internetwurm</primary></indexterm>
funktioniert der gleiche grundlegende Angriff noch heute. Die bei weitem
häufigste Form eines Puffer-Überlauf-Angriffs basiert darauf,
den Stack zu korrumpieren.</para>
<indexterm><primary>Stack</primary></indexterm>
<indexterm><primary>Arguments</primary></indexterm>
<para>Die meisten modernen Computer-Systeme verwenden einen
Stack, um Argumente an Prozeduren zu übergeben und
lokale Variablen zu speichern. Ein Stack ist ein
last-in-first-out-Puffer (LIFO) im hohen Speicherbereich
eines Prozesses. Wenn ein Programm eine Funktion
<indexterm><primary>LIFO</primary></indexterm>
<indexterm>
<primary>Prozessabbild</primary>
<secondary>Stack-Pointer</secondary>
</indexterm>
aufruft wird ein neuer "Stackframe" erzeugt. Dieser besteht aus
den Argumenten, die der Funktion übergeben wurden und
einem variabel grossem Bereich für lokale Variablen. Der
"Stack-Pointer" ist ein Register, dass die
<indexterm><primary>Stack-Frame</primary></indexterm>
<indexterm><primary>Stack-Pointer</primary></indexterm>
aktuelle Adresse der Stack-Spitze enthält.
Da sich dieser Wert oft ändert, wenn neue Werte
auf dem Stack abgelegt werden, bieten viele Implementierungen
einen "Frame-Pointer", der nahe am Anfang des Stack-Frames
liegt und es so leichter macht lokale Variablen relativ zum
aktuellen Stackframe zu adressieren. <xref linkend="COD"/>
Die Rücksprungadresse
<indexterm><primary>Frame-Pointer</primary></indexterm>
<indexterm>
<primary>Prozessabbild</primary>
<secondary>Frame-Pointer</secondary>
</indexterm>
<indexterm><primary>Rücksprungadresse</primary></indexterm>
<indexterm><primary>Stack-Überlauf</primary></indexterm>
der Funktionen werden ebenfalls auf dem Stack
gespeichert und das ist der Grund für
Stack-Überlauf-Exploits. Denn ein böswilliger Nutzer
kann die Rücksprungadresse der Funktion überschreiben
indem er eine lokale Variable in der Funktion
überlaufen lässt, wodurch es ihm möglich ist
beliebigen Code auszuführen.</para>
<para>Obwohl Stack-basierte Angriffe bei weitem die
Häufigsten sind, ist es auch möglich den Stack mit
einem Heap-basierten (malloc/free) Angriff zu
überschreiben.</para>
<para>Die C-Programmiersprache führt keine automatischen
Bereichsüberprüfungen bei Feldern oder Zeigern durch, wie
viele andere Sprachen das tun. Außerdem enthält
die C-Standardbibliothek eine Handvoll sehr
gefährlicher Funktionen.</para>
<informaltable frame="none" pgwide="1">
<tgroup cols="2">
<tbody>
<row>
<entry><function>strcpy</function>(char *dest, const
char *src)</entry>
<entry><simpara>Kann den Puffer dest überlaufen
lassen</simpara></entry>
</row>
<row>
<entry><function>strcat</function>(char *dest, const
char *src)</entry>
<entry><simpara>Kann den Puffer dest überlaufen
lassen</simpara></entry>
</row>
<row>
<entry><function>getwd</function>(char *buf)</entry>
<entry><simpara>Kann den Puffer buf überlaufen
lassen</simpara></entry>
</row>
<row>
<entry><function>gets</function>(char *s)</entry>
<entry><simpara>Kann den Puffer s überlaufen
lassen</simpara></entry>
</row>
<row>
<entry><function>[vf]scanf</function>(const char
*format, ...)</entry>
<entry><simpara>Kann sein Argument überlaufen
lassen</simpara></entry>
</row>
<row>
<entry><function>realpath</function>(char *path,
char resolved_path[])</entry>
<entry><simpara>Kann den Puffer path überlaufen
lassen</simpara></entry>
</row>
<row>
<entry><function>[v]sprintf</function>(char *str,
const char *format, ...)</entry>
<entry><simpara>Kann den Puffer str überlaufen
lassen</simpara></entry>
</row>
</tbody>
</tgroup>
</informaltable>
<sect2>
<title>Puffer-Überlauf Beispiel</title>
<para>Das folgende Quellcode-Beispiel enthält einen
Puffer-Überlauf, der darauf ausgelegt ist die
Rücksprungadresse zu überschreiben und die
Anweisung direkt nach dem Funktionsaufruf zu
überspringen. (Inspiriert durch
<xref linkend="Phrack"/>)</para>
<programlisting>#include &lt;stdio.h&gt;
void manipulate(char *buffer) {
char newbuffer[80];
strcpy(newbuffer,buffer);
}
int main() {
char ch,buffer[4096];
int i=0;
while ((buffer[i++] = getchar()) != '\n') {};
i=1;
manipulate(buffer);
i=2;
printf("The value of i is : %d\n",i);
return 0;
}</programlisting>
<para>Betrachten wir nun, wie das Speicherabbild dieses
Prozesses aussehen würde, wenn wir 160 Leerzeichen
in unser kleines Programm eingeben, bevor wir Enter
drücken.</para>
<para>[XXX figure here!]</para>
<para>Offensichtlich kann man durch böswilligere Eingaben
bereits kompilierten Programmtext ausführen (wie z.B.
exec(/bin/sh)).</para>
</sect2>
<sect2>
<title>Puffer-Überläufe vermeiden</title>
<para>Die direkteste Lösung, um
Stack-Überläufe zu vermeiden, ist immer
grössenbegrenzten Speicher und String-Copy-Funktionen
zu verwenden.
<function>strncpy</function> und <function>strncat</function>
sind Teil der C-Standardbibliothek.
<indexterm>
<primary>Zeichenketten-Kopierfunktioen</primary>
<secondary>strncpy</secondary>
</indexterm>
<indexterm>
<primary>Zeichenketten-Kopierfunktionen</primary>
<secondary>strncat</secondary>
</indexterm>
Diese Funktionen akzeptieren einen Längen-Parameter. Dieser
Wert sollte nicht größer sein als die Länge
des Zielpuffers. Die Funktionen kopieren dann bis zu
`length' Bytes von der Quelle zum Ziel. Allerdings gibt es
einige Probleme. Keine der Funktionen garantiert, dass
die Zeichenkette NUL-terminiert ist, wenn die
Größe
<indexterm><primary>NUL-Terminierung</primary></indexterm>
des Eingabepuffers so groß ist wie das Ziel.
Außerdem wird der Parameter length zwischen strncpy
und strncat inkonsistent definiert, weshalb Programmierer
leicht bezüglich der korrekten Verwendung durcheinander
kommen können. Weiterhin gibt es einen spürbaren
Leistungsverlust im Vergleich zu
<function>strcpy</function>, wenn eine kurze Zeichenkette in
einen großen Puffer kopiert wird. Denn
<function>strncpy</function> fült den Puffer bis zur
angegebenen Länge mit NUL auf.
</para>
<para>In OpenBSD wurde eine weitere Möglichkeit zum
<indexterm><primary>OpenBSD</primary></indexterm>
kopieren von Speicherbereichen implementiert, die dieses
Problem umgeht. Die Funktionen <function>strlcpy</function>
und <function>strlcat</function> garantieren, dass das Ziel
immer NUL-terminiert wird, wenn das Argument length ungleich
null ist. Für weitere Informationen über diese
Funktionen lesen Sie bitte <xref linkend="OpenBSD"/>. Die
OpenBSD-Funktionen <function>strlcpy</function> und
<function>strlcat</function> sind seit Version 3.3 auch in
FreeBSD verfügbar.</para>
<indexterm>
<primary>Zeichenketten-Kopierfunktionen</primary>
<secondary>strlcpy</secondary>
</indexterm>
<indexterm>
<primary>Zeichenketten-Kopierfunktionen</primary>
<secondary>strlcat</secondary>
</indexterm>
<sect3>
<title>Compiler-basierte Laufzeitüberprüfung
von Grenzen</title>
<indexterm>
<primary>Prüfung von Grenzen</primary>
<secondary>Compiler-basiert</secondary>
</indexterm>
<para>Unglücklicherweise gibt es immer noch sehr viel
Quelltext, der allgemein verwendet wird und blind Speicher
umherkopiert, ohne eine der gerade besprochenen Funktionen,
die Begrenzungen unterstützen, zu verwenden.
Glücklicherweise gibt es einen Weg, um solche Angriffe zu
verhindern - Überprüfung der Grenzen zur Laufzeit, die in
verschiedenen C/C++ Compilern eingebaut ist.</para>
<indexterm><primary>ProPolice</primary></indexterm>
<indexterm><primary>StackGuard</primary></indexterm>
<indexterm><primary>GCC</primary></indexterm>
<para>ProPolice ist eine solche Compiler-Eigenschaft und ist in den
&man.gcc.1; Versionen 4.1 und höher integriert. Es ersetzt und
erweitert die &man.gcc.1; StackGuard-Erweiterung von
früher.</para>
<para>ProPolice schützt gegen stackbasierte
Pufferüberläufe und andere Angriffe durch das Ablegen von
Pseudo-Zufallszahlen in Schlüsselbereichen des Stacks bevor es
irgendwelche Funktionen aufruft. Wenn eine Funktion beendet wird,
werden diese <quote>Kanarienvögel</quote> überprüft
und wenn festgestellt wird, dass diese verändert wurden wird das
Programm sofort abgebrochen. Dadurch wird jeglicher Versuch, die
Rücksprungadresse oder andere Variablen, die auf dem Stack
gespeichert werden, durch die Ausführung von Schadcode zu
manipulieren, nicht funktionieren, da der Angreifer auch die
Pseudo-Zufallszahlen unberührt lassen müsste.</para>
<indexterm><primary>Puffer-Überlauf</primary></indexterm>
<para>Ihre Anwendungen mit ProPolice neu zu kompilieren ist
eine effektive Maßnahme, um sie vor den meisten
Puffer-Überlauf-Angriffen zu schützen, aber die
Programme können noch immer kompromittiert werden.</para>
</sect3>
<sect3>
<title>Bibliotheks-basierte Laufzeitüberprüfung
von Grenzen</title>
<indexterm>
<primary>Prüfung von Grenzen</primary>
<secondary>Bibliotheks-basiert</secondary>
</indexterm>
<para>Compiler-basierte Mechanismen sind bei Software,
die nur im Binärformat vertrieben wird, und die somit
nicht neu kompiliert werden kann völlig nutzlos.
Für diesen Fall gibt es einige Bibliotheken, welche
die unsicheren Funktionen der C-Bibliothek
(<function>strcpy</function>, <function>fscanf</function>,
<function>getwd</function>, etc..) neu implementieren und
sicherstellen, dass nicht hinter den Stack-Pointer
geschrieben werden kann.</para>
<itemizedlist>
<listitem><simpara>libsafe</simpara></listitem>
<listitem><simpara>libverify</simpara></listitem>
<listitem><simpara>libparanoia</simpara></listitem>
</itemizedlist>
<para>Leider haben diese Bibliotheks-basierten
Verteidigungen mehrere Schwächen. Diese Bibliotheken
schützen nur vor einer kleinen Gruppe von
Sicherheitslücken und sie können das
eigentliche Problem nicht lösen. Diese
Maßnahmen können versagen, wenn die Anwendung
mit -fomit-frame-pointer kompiliert wurde.
Außerdem kann der Nutzer die Umgebungsvariablen
LD_PRELOAD und LD_LIBRARY_PATH überschreiben oder
löschen.</para>
</sect3>
</sect2>
</sect1>
<sect1 id="secure-setuid">
<title>SetUID-Themen</title>
<indexterm><primary>seteuid</primary></indexterm>
<para>Es gibt zu jedem Prozess mindestens sechs verschiedene
IDs, die diesem zugeordnet sind. Deshalb müssen Sie
sehr vorsichtig mit den Zugriffsrechten sein, die Ihr Prozess
zu jedem Zeitpunkt besitzt. Konkret bedeutet dass, das alle
seteuid-Anwendungen ihre Privilegien abgeben sollten, sobald
sie diese nicht mehr benötigen.</para>
<indexterm>
<primary>Benutzer-IDs</primary>
<secondary>reale Benutzer-ID</secondary>
</indexterm>
<indexterm>
<primary>Benutzer-IDs</primary>
<secondary>effective Benutzer-ID</secondary>
</indexterm>
<para>Die reale Benutzer-ID kann nur von einem
Superuser-Prozess geändert werden. Das Programm
<application>login</application> setzt sie, wenn sich ein
Benutzer am System anmeldet, und sie wird nur selten
geändert.</para>
<para>Die effektive Benutzer-ID wird von der Funktion
<function>exec()</function> gesetzt, wenn ein Programm
das seteuid-Bit gesetzt hat. Eine Anwendung kann
<function>seteuid()</function> jederzeit aufrufen, um die
effektive Benutzer-ID entweder auf die reale Benutzer-ID oder
die gespeicherte set-user-ID zu setzen. Wenn eine der
<function>exec()</function>-Funktionen die effektive
Benutzer-ID setzt, wird der vorherige Wert als
gespeicherte set-user-ID abgelegt.</para>
</sect1>
<sect1 id="secure-chroot">
<title>Die Umgebung ihrer Programme einschränken</title>
<indexterm><primary>chroot()</primary></indexterm>
<para>Die herkömmliche Methode, um einen Prozess
einzuschränken, besteht in dem Systemaufruf
<function>chroot()</function>. Dieser Aufruf
ändert das Wurzelverzeichnis, auf das sich alle
Pfadangaben des Prozesses und jegliche Kind-Prozesse beziehen.
Damit dieser Systemaufruf gelingt, muss der Prozess
Ausführungsrechte (Durchsuchungsrechte) für das
Verzeichnis haben, auf das er sich bezieht. Die neue Umgebung
wird erst wirksam, wenn Sie mittels
<function>chdir()</function> in Ihre neue Umgebung wechseln.
Es sollte erwähnt werden, dass ein Prozess recht einfach
aus der chroot-Umgebung ausbrechen kann, wenn er root-Rechte
besitzt. Das kann man erreichen, indem man Gerätedateien
anlegt, um Kernel-Speicher zu lesen, oder indem man einen
Debugger mit einem Prozess außerhalb seiner
&man.chroot.8;-Umgebung verbindet, oder auf viele andere
kreative Wege.</para>
<para>Das Verhalten des Systemaufrufs
<function>chroot()</function> kann durch die
kern.chroot.allow_open_directories
<command>sysctl</command>-Variable beeinflusst werden. Wenn
diese auf 0 gesetzt ist, wird <function>chroot()</function>
mit EPERM fehlschlagen, wenn irgendwelche Verzeichnisse
geöffnet sind. Wenn die Variable auf den Standardwert 1
gesetzt ist, wird <function>chroot()</function> mit EPERM
fehlschlagen, wenn irgendwelche Verzeichnisse geöffnet
sind und sich der Prozess bereits in einer
<function>chroot()</function>-Umgebung befindet. Bei jedem
anderen Wert wird die Überprüfung auf
geöffnete Verzeichnisse komplett umgangen.</para>
<sect2>
<title>Die Jail-Funktionalität in FreeBSD</title>
<indexterm><primary>Jail</primary></indexterm>
<para>Das Konzept einer Jail (Gefängnis) erweitert
<function>chroot()</function>, indem es die Macht des
Superusers einschränkt, um einen echten 'virtuellen
Server' zu erzeugen. Wenn ein solches Gefängnis einmal
eingerichtet ist, muss die gesamte Netzwerkkommunikation
über eine bestimmte IP-Adresse erfolgen und die
"root-Privilegien" innerhalb der Jail sind sehr stark
eingeschränkt.</para>
<para>Solange Sie sich in einer Jail befinden, werden alle
Tests auf Superuser-Rechte durch den Aufruf von
<function>suser()</function> fehlschlagen. Allerdings wurden
einige Aufrufe von <function>suser()</function>
abgeändert, um die neue
<function>suser_xxx()</function>-Schnittstelle zu
implementieren. Diese Funktion ist dafür verantwortlich,
festzustellen, ob bestimmte Superuser-Rechte einem
eingesperrten Prozess zur Verfügung stehen.</para>
<para>Ein Superuser-Prozess innerhalb einer Jail darf
folgendes:</para>
<itemizedlist>
<listitem>
<simpara>Berechtigungen verändern mittels:
<function>setuid</function>,
<function>seteuid</function>,
<function>setgid</function>,
<function>setegid</function>,
<function>setgroups</function>,
<function>setreuid</function>,
<function>setregid</function>,
<function>setlogin</function></simpara>
</listitem>
<listitem>
<simpara>Ressourcenbegrenzungen setzen mittels
<function>setrlimit</function></simpara>
</listitem>
<listitem>
<simpara>Einige sysctl-Variablen (kern.hostname)
verändern</simpara>
</listitem>
<listitem>
<simpara><function>chroot()</function></simpara>
</listitem>
<listitem>
<simpara>Ein Flag einer vnode setzen:
<function>chflags</function>,
<function>fchflags</function></simpara>
</listitem>
<listitem>
<simpara>Attribute einer vnode setzen wie Dateiberechtigungen,
Eigentümer, Gruppe, Größe, Zugriffszeit
und Modifikationszeit</simpara>
</listitem>
<listitem>
<simpara>Binden eines Prozesses an einen öffentlichen
privilegierten Port (ports &lt; 1024)</simpara>
</listitem>
</itemizedlist>
<para><function>Jail</function>s sind ein mächtiges
Werkzeug, um Anwendungen in einer sicheren Umgebung
auszuführen, aber sie haben auch ihre Nachteile.
Derzeit wurden die IPC-Mechanismen noch nicht an
<function>suser_xxx</function> angepasst, so dass Anwendungen
wie MySQL nicht innerhalb einer Jail ausgeführt werden
können. Der Superuser-Zugriff hat in einer Jail nur eine
sehr eingeschränkte Bedeutung, aber es gibt keine
Möglichkeit zu definieren was
"sehr eingeschränkt" heißt.</para>
</sect2>
<sect2>
<title>&posix;.1e Prozess Capabilities</title>
<indexterm><primary>POSIX.1e Process
Capabilities</primary></indexterm>
<indexterm><primary>TrustedBSD</primary></indexterm>
<para>&posix; hat einen funktionalen Entwurf (Working Draft)
herausgegeben, der Ereignisüberprüfung,
Zugriffskontrolllisten, feiner einstellbare Privilegien,
Informationsmarkierung und verbindliche Zugriffskontrolle
enthält.</para>
<para>Dies ist im Moment in Arbeit und das Hauptziel des <ulink
url="http://www.trustedbsd.org/">TrustedBSD</ulink>-Projekts.
Ein Teil der bisherigen Arbeit wurde in &os.current;
übernommen (cap_set_proc(3)).</para>
</sect2>
</sect1>
<sect1 id="secure-trust">
<title>Vertrauen</title>
<para>Eine Anwendung sollte niemals davon ausgehen, dass
irgendetwas in der Nutzerumgebung vernünftig ist.
Das beinhaltet (ist aber sicher nicht darauf
beschränkt): Nutzereingaben, Signale,
Umgebungsvariablen, Ressourcen, IPC, mmaps, das
Arbeitsverzeichnis im Dateisystem, Dateideskriptoren,
die Anzahl geöffneter Dateien, etc..</para>
<indexterm><primary>positive Filterung</primary></indexterm>
<indexterm><primary>Datenvalidierung</primary></indexterm>
<para>Sie sollten niemals annehmen, dass Sie jede Art von
inkorrekten Eingaben abfangen können, die ein Nutzer
machen kann. Stattdessen sollte Ihre Anwendung positive
Filterung verwenden, um nur eine bestimmte Teilmenge an
Eingaben zuzulassen, die Sie für sicher halten.
Ungeeignete Datenüberprüfung ist die Ursache
vieler Exploits, besonders für CGI-Skripte im Internet.
Bei Dateinamen müssen Sie besonders vorsichtig sein,
wenn es sich um Pfade ("../", "/"), symbolische
Verknüpfungen und Shell-Escape-Sequenzen handelt.</para>
<indexterm><primary>Perl Taint-Modus</primary></indexterm>
<para>Perl bietet eine wirklich coole Funktion, den sogenannten
"Taint"-Modus, der verwendet werden kann, um zu verhindern,
dass Skripte Daten, die von außerhalb des Programmes
stammen, auf unsichere Art und Weise verwenden. Dieser
Modus überprüft Kommandozeilenargumente,
Umgebungsvariablen, Lokalisierungsinformationen, die
Ergebnisse von Systemaufrufen
(<function>readdir()</function>,
<function>readlink()</function>,
<function>getpwxxx()</function>)
und alle Dateieingaben.</para>
</sect1>
<sect1 id="secure-race-conditions">
<title>Race-Conditions</title>
<para>Eine Race-Condition ist ein unnormales Verhalten, das von
einer unerwarteten Abhängigkeit beim Timing von Ereignissen
verursacht wird. Mit anderen Worten heißt das, ein
Programmierer nimmt irrtümlicher Weise an, dass ein
bestimmtes Ereignis immer vor einem anderen stattfindet.</para>
<indexterm><primary>Race-Conditions</primary>
<secondary>Signale</secondary></indexterm>
<indexterm><primary>Race-Conditions</primary>
<secondary>Zugriffsprüfungen</secondary></indexterm>
<indexterm><primary>Race-Conditions</primary>
<secondary>Öffnen von Dateien</secondary></indexterm>
<para>Einige der häufigsten Ursachen für
Race-Conditions sind Signale, Zugriffsprüfungen und das
Öffnen von Dateien. Signale sind von Natur aus
asynchrone Ereignisse, deshalb ist besondere Vorsicht im
Umgang damit geboten. Das Prüfen des Zugriffs mittels
der Aufrufe <function>access(2)</function> gefolgt von
<function>open(2)</function> ist offensichtlich nicht atomar.
Benutzer können zwischen den beiden Aufrufen Dateien
verschieben. Stattdessen sollten privilegierte Anwendungen
<function>seteuid()</function> direkt gefolgt von
<function>open()</function> aufrufen. Auf die gleiche Art
sollte eine Anwendung immer eine korrekte Umask vor dem
Aufruf von <function>open()</function> setzen, um
störende Aufrufe von <function>chmod()</function> zu
umgehen.</para>
</sect1>
</chapter>