- Do not add features to a program after a design/requirement spec for the program has been written. All three MaraDNS security problems existed because I added features to the program after the basic program was done. Namely:
- I added round-robin rotation to the codebase after the basic authoritative-only DNS server was written. This added a denial of service security bug to the code.
- I changed the authoritative code to give out nicer messages when invalid DNS packets were received. This added another denial of service security bug to the code.
- I added ipv6 to MaraDNS. This was the cause of a third, and final (so far; knock on wood) denial of service security bug to MaraDNS.
It also looks like the one known denial of service security bug in djbdns was the cause of a similar feature creep; basically, the existence of TCP code in dnscache caused the bug. - I added round-robin rotation to the codebase after the basic authoritative-only DNS server was written. This added a denial of service security bug to the code.
- Code in a style that make memory leaks difficult. For example, make sure there are a limited number of strings allocated at the beginning of a function, and use a variable to store the return value. Use gotos for error trapping if programming in C, since C does not have real Java-style error trapping, nor C++'s automatic destructors.
If a block of code needs a temporary string, declare the string at the beginning of the block and don't leave the block without zapping the string. For example:
function() {
/* This is *always* the first part of a
* block that allocates
* strings. Yes, we allocate every last
* string *before*
* doing anything else */
overflow_resistant_string *s1, *s2, *s3;
if(allocate_memory(s1) == 0) {
return ERROR;
} else if(allocate_memory(s2) == 0) {
deallocate(s1);
return ERROR;
} else if(allocate_memory(s3) == 0) {
deallocate(s1);
deallocate(s2);
return ERROR;
}
int return_code = OK; /* If you're using
* GCC2 still, upgrade */
/* Now we run normal code */
/* Lots of snipped code here */
if(do_something_important == FAILS) {
return_code = ERROR;
goto leave_function;
}
/* Lots more snipped code */
if(weve_already_funished == YES) {
return_code = YIPEE;
goto leave_function;
}
/* More snipped code */
leave_function:
deallocate(s1);
deallocate(s2);
deallocate(s3);
return return_code;
} - Use buffer-overflow resistant strings. Check; this is why MaraDNS (knock on wood) hasn't had a security problem worse than denial of service.
- Use as many operating system features to sandbox the code as possible. Check; this is why MaraDNS is in a chroot() environemt running as the "nobody" user (it is also possible to have MaraDNS run as a maradns-specific user if desired)
Friday, September 7, 2007
Making MaraDNS even more secure
Now that MaraDNS has had over five years of real-world testing, and a few minor security problems (nothing worse than denial of service) have been found, here are some thoughts on how to make a program have the minimum number of security problems possible:
Etiquetas:
MaraDNS