The security design of MaraDNS

MaraDNS should be a secure DNS server.

<p>

The reason why I say should be instead of "is" is because I
find claims of security very pretentious.  There is no way that I can
guarantee that a piece of code as complex as a recursive DNS server
is completely free from security bugs.  

<p>

What I can guarantee, however, is that such bugs are very unlikely in
MaraDNS, since the design has security checks and balances which 
minimize the chance of there being a security hazard in the code.

Why code is insecure

The main reason why code is insecure is because the code in question has 
undefined results when fed data which is in a different form than what the 
author of the code expected.  The simplest case of this is the buffer 
overflow, where a program is fed a string far longer than the program 
was designed to handle.

<p>

Another example is the "cache poison" bug which ancient versions of
another DNS implementation had.  With this bug, it was a trivial matter to
tell the DNS server that, for example, www.yahoo.com had an ip address of
say, 10.69.69.69, which really points to some sleazy
"paid-for-clickthrough" porn site.  Why did this bug exist?  Because the
original authors of this server did not expect remote servers to
deliberately give out incorrect IP addresses.

How MaraDNS avoids these problems

First of all, MaraDNS uses a special string library which is resistant to
buffer overflows.  It does this by having a maximum allowed size for a
string--any attempt to make a string larger than the maximum allowed size
causes the string library to return an error instead of overflowing a
buffer.  In addition, the string library allocates an extra three bytes
for each string object, as a cushion against possible boundary conditions
(there was one case with another program which strived to be secure where
a one-byte buffer overflow resulted in a remote root exploit).

<p>

Second of all, MaraDNS protects herself from cache poisoning without ever
discarding glue records is by handling out-of-bailiwick records
differently, depending on where the offending records are.  The actual
rules are fairly complex, and detailed in a document 
called "cache.poison.protection
 (http://www.maradns.org/cache_poison_protection.html)".

<p>

Third of all, I have extensively read Dan Bernstein's notes (http://cr.yp.to/djbdns.html) on DNS 
implementation before implementing MaraDNS.  Two ideas for 
implementing DNS security discussed on Dan's pages have been implemented in 
MaraDNS:

<UL>

- When the recursive nameserver is performing queries, MaraDNS uses a
securely generated pseudo-random-number-generator to generate the query ID,
and the lower 12 bits of the query source port. This means that a given
attempt to spoof a reply to MaraDNS has less than a 1 in 250 million
chance of succeeding.

- MaraDNS uses a FIFO queue to delete unused records when the cache 
starts to fill up.  The algorithm is simple:  Every time a record is 
accessed, it is placed at the top of the list.  When memory fills up, 
MaraDNS deletes records at the bottom of the list.  This allows MaraDNS 
to act in a very graceful manner when the cache starts to fill up.

Some known security problems are avoided: MaraDNS does not use printf() in
a manner which would make format string vulnerabilities possible; MaraDNS
does not use any of the potentially dangerous globing functions; and
MaraDNS will not have signal handlers until I can figure out a way to make
sure that the DNS server is not vulnerable to the known security pitfalls
of poor signal handler construction.

<p>

I go though the code, and when I find anything which has the possibility 
of allowing the data to be in an undefined state, I revise the code in 
question.  For example, when I was looking through the code in the 0.8.35 
release of MaraDNS; I found a case where the data could potentially 
become undefined.  In more detail, if certain strings could not be 
allocated or copied over--cases which can never happen--the code which 
removes elements from the cache would attempt to free() unallocated memory 
later on.  Even though this was a case where it was impossible to exploit 
the code in question, I felt it was prudent to update the code to not have 
this problem--hence the vaguely worded "security update" for the 0.8.99 
release of MaraDNS.

<p>

MaraDNS also mandates that the server is run as an unprivileged user, and
strongly encourages MaraDNS to be run in a chroot() environment.  In
addition, the DNS cache uses a separate data structure than the local DNS
records, making it difficult, if not impossible, for the cache at affect
the local records.  This design means that, even if there is a security
hole in MaraDNS, the possibility of such a security hole allowing the
attacker having elevated privileges is next to zero.

The security history of MaraDNS

There have been three security problems found with MaraDNS: two fairly 
major, and one minor security bug.

<p>

The major security problem was discovered by Roy Arends, one of the BIND
developers, and was caused by the fact the earlier versions of MaraDNS did
not check to see whether a given DNS packet was a question or an answer. 

<p>
 
Since a DNS answer looks like a DNS question, with the exception of a
one-bit difference, this bug allowed an attacker to send a spoofed DNS
packet which would result in MaraDNS sending an answer to herself (or to
another MaraDNS server), which would result in another answer being sent,
and so on.

<p>

The reason this security glitch passed through was because of an
overzealous effort to honor the RFC spirit to be "liberal in what one
accepts and conservative in what one sends". Since then, I have gone over
the DNS spec to see if their are any other cases where a malformed packet
could cause this kind of security problem, and have made an effort that
any such cases in MaraDNS no longer exist.

<p>

The other major security problem was found by myself when performing an 
audit of the code during the beta test cycle.  It involved the 
decompression code, and was caused because DNS compression is difficult to 
implement, and easy to create security holes with.  

<p>

In both cases, the problems only allowed denial of service attacks 
to be performed.  It was not possible to use MaraDNS to gain elevated
privledges.

<p>

The minor security problem involved the seed for the pseudo-random number 
generator.  In cases where there was an ASCII null in the key for the 
pseudo-random number generator, MaraDNS would have less than a full 128 
bits of entropy for the seed.  There was also a related issue, even more 
minor, where, in certain rare circumstances, multiple instances of MaraDNS 
could potentially generate the same pseudo-random numbers, if two copies of 
MaraDNS used the same static random seed file, and were started at the 
same time.  This has also been fixed.

