$Id: review.html,v 1.15 2001/11/06 20:47:32 adam Exp $
This is an early draft of the guidelines; it is being distributed in the hopes of providing a more transparent and predictable code review process. We do not mean to imply that the things listed here are the only issues we will raise in a review. We will attempt to keep this document up to date, so that over time, it becomes a more useful guide.
When networking computers that can access information of financial or personal value that Acme Widgets has entrusted to a computer system, it is essential that we consider information security. When network connections pass through networks outside of Acme Widgets's control, we are exposed to attacks from a variety of sources. Those sources are known to include vandals ("hackers") who will make changes to information as a means of gaining prestige in the underground community, or as a matter of revenge or disruption, and amateur thieves, who will attempt to steal. There may also be attacks by professional criminals or criminal groups who have access to substantial resources of both time and money, and can perform an in-depth attack. Acme Widgets is a large, high visibility target...
As such, the firewall architecture group is tasked with providing a state of the art Internet firewall that will protect us from all these threats, and simultaneously help Acme Widgets provide service to our customers over the Internet. We are interested in making it possible to deploy new applications that work over the internet, however, we must make sure that those applications are safe.
This means that we need to resist a variety of attacks, and we need to do so better than in our phone or mail businesses. Why better? Because on the phone, there is a person in the loop. In the mail room, there is a person in the loop. Online, it may be possible to scale an attack from annoying to disastrous, or from a small scam to a huge theft, because the entire attack might be automated.
So it is with a healthy paranoia that we approach screening new components to the firewall. We will examine the authentication and authorization methods that you use. We will look for confidentiality and integrity controls. We will look at administrative issues such as the documentation that the firewall support group needs, and how the program logs.
This document, in addition to making the process transparent, is intended to speed the code review process, by letting you know what we'll be looking for, so you can have it ready when we do the review. It also explains some of the coding practices and common mistakes that we will insist be changed, so you can come to us with code thats closer to being installable.
This is a requirements document. In some places things will be marked 'optional', or 'preferred.' This refers to a judgment call on the part of the Firewall Architecture group, with input from corporate security, the group whose code is being reviewed, and other participants in the code review process. The word optional may be construed to mean that we will not require a change, although we may strongly recommend it. Other things will be marked 'should,' and those things are open to discussion, if they are documented design decisions. In other words, the documentation must explain the choice at the start of the code review. Otherwise, we will require that the code be changed to confirm with accepted security practices.
The code review participants should remain constant from review to review. Participation by representatives from many groups is required for a successful code review. Those groups include, but are not limited to, (Firewall Operations), (Firewall Architecture) and Corporate Security. The code must be presented by a developer or group member who is qualified and able to answer technical questions about the code and design. There must be a scribe and a coordinator appointed. At the end of a review, all present must agree on an appraisal of the code. In the event of irreconcilable disagreements, the least positive appraisal that everyone can agree to will be the appraisal. At reviews beyond the first, copies of the diffs and the minutes of all previous meetings should be available, along with a full copy of the current code.
Does it run from the command line? Inetd? Cron?
Rc2.d/S99Acme? Are there arguments that the program expects?
Does it expect environment variables to be set? (We'd prefer they be
moved to a configuration file. We might mandate some options be moved
to a configuration file for reliability reasons.)
Does the program react to any signals other than SIGKILL and
SIGTERM? If it does, it should use SIGUSR1 to activate debugging,
and SIGUSR2 to turn it off. In any event, the programs signal
handling must be documented.
A complete description of all command line options is
required. A complete description of the configuration files is
required.
Programs must be careful to avoid logging passwords, cryptographic keys, and other sensitive data. In addition, be careful about the amount of user supplied data that syslog gets.
Passing debugging information to syslog is optional.
Log facility and levels to be used will be provided by (Firewall Architecture) on request. In general, use LOG_INFO for information, LOG_DEBUG for debug, and LOG_ALERT, LOG_CRIT, and LOG_ERR when those are reasonably called for.
It is not appropriate to assume that a connection is coming from the client that you expect, unless you take strong measures. It very difficult to ensure that you are not talking to a bad guy. Doing so requires that a connection use strong authentication up front and be encrypted and authenticated throughout its lifetime.
Even when this is done, there is a chance that a user might find it worth attacking through an authenticated connection. Consider verify the sanity of inbound data.
Certain library calls have historically, been found to be associated with security problems, because they do no checking, and user input is often passed to them. Use of these calls is strongly discouraged. Those calls include but are not limited to,
Its worth noting that even small bugs should be fixed. Read
this
to see an example of a small bug that was identified and blew up in
the designers faces. More recently, the Linux Security Audit Project
has a
FreeBSD has a page of Security Do's and don'ts for programmers.
The ACM Forum on Risks to the Public (news:comp.risks) is full
of great background.
Matt Bishop's Writing
Secure SetUID Programs page. Several well done papers that are
well worth reading.
Rain Forest Puppy wrote an article in Phrack
55-07 about common failures in perl coding. If you're
writing in perl, its worth reading.
Simon Burr has a web page explaining how to
break out of a chroot jail.
Also, be aware of the null byte issue when passing things to system calls: Perl allows nulls in strings, C does not, which can lead to interesting behavior. See Phrack 55-07 for details.
Legitimate address formats include:
user_name@company.com alex+@pitt.edu mi%aldan.UUCP@algebra.com user%host.domain@anon.penet.fi host1!host2!user /G=JABYML/S=MASONS/O=CUSTOMER/ADMD=FOOBAR/C=KZ/@gateway.sprint.com "JE Jones"@foo.x.400.net
$Log: review.html,v $ Revision 1.15 2001/11/06 20:47:32 adam updated for kragen Revision 1.14 2000/07/03 16:45:05 adam added pointer to chroot page. Revision 1.13 2000/05/02 18:30:55 adam added historical note. Revision 1.12 2000/05/02 18:27:52 adam added per zab Revision 1.11 1999/11/09 14:55:58 adam added pointers to RFP's 55-07 article Revision 1.10 1999/06/01 19:25:49 adam added open comments from Peter Revision 1.16 1999/06/01 19:14:23 adam added realloc comments (Thanks to pguttmann) Revision 1.15 1998/11/24 21:26:42 adam fixed system call/library call confusion pointed out by alert reader Olof Johansson Revision 1.14 1998/10/29 23:28:44 adam added that system calls must have their return status checked Revision 1.13 1998/09/02 22:44:03 adam David Landgren (david@landgren.net) provided improvements to Perl section about -T and strict. Revision 1.12 1998/07/24 12:58:39 adam added freebsd dos & don'ts Revision 1.11 1998/04/11 19:03:36 adam clarified chroot, added references to Matt Bishop's papers. Revision 1.10 1997/08/29 16:06:20 adam fixed link Revision 1.9 1996/10/05 05:19:31 adam VC System change Revision 1.8 1996/09/04 17:09:26 adam Added changelog section revision 1.7 1996/09/04 17:06:14 adam Added comments about possible syslog buffer overflows. Added a few lines about the unavailability of NFS Changed execve to exec moved email example to appendix, used hostnames instead. Moved most of compiler checking to appendix, left platitude about using available e tools Added requirement for paper, electronic copies from presenter a day before a review, included command line to print with. Pointers to SIRO, Cops' setuid man page Acknowledgements Filled out appendixes on proxies, dce, and cryptography revision 1.6 1996/08/29 17:51:07 adam mail addressing expanded acks spell checking revision 1.5 1996/08/15 21:03:24 adam rearranged acknowledgements, fixed font sizing revision 1.4 1996/08/15 20:55:21 adam added appendixes Fixed html for references Added some of JB's comments revision 1.3 1996/08/12 20:19:59 adam Made changes as per JB's large suggestions. revision 1.2 1996/08/07 19:08:30 adam Finished htmlizing docs revision 1.1 1996/08/07 18:44:48 adam Initial revision
/* Under Unix we try to defend against writing through links, but this is somewhat difficult since the there's no atomic way to do this, and without resorting to low-level I/O it can't be done at all. What we do is lstat() the file, open it as appropriate, and if it's an existing file ftstat() it and compare various important fields to make sure the file wasn't changed between the lstat() and the open(). If everything is OK, we then use the lstat() information to make sure it isn't a symlink (or at least that it's a normal file) and that the link count is 1. These checks also catch other weird things like STREAMS stuff fattach()'d over files. If these checks pass and the file already exists we truncate it to mimic the effect of an open with create. Finally, we use fdopen() to convert the file handle for stdio use */ struct stat lstatInfo; char *mode = "rb+"; int fd; /* lstat() the file. If it doesn't exist, create it with O_EXCL. If it does exist, open it for read/write and perform the fstat() check */ if( lstat( fileName, &lstatInfo ) == -1 ) { /* If the lstat() failed for reasons other than the file not existing, return a file open error */ if( errno != ENOENT ) return( -1 ); /* The file doesn't exist, create it with O_EXCL to make sure an attacker can't slip in a file between the lstat() and open() */ if( ( fd = open( fileName, O_CREAT | O_EXCL | O_RDWR, 0600 ) ) == -1 ) return( -1 ); mode = "wb"; } else { struct stat fstatInfo; /* Open an existing file */ if( ( fd = open( fileName, O_RDWR ) ) == -1 ) return( -1 ); /* fstat() the opened file and check that the file mode bits and inode and device match */ if( fstat( fd, &fstatInfo ) == -1 || \ lstatInfo.st_mode != fstatInfo.st_mode || \ lstatInfo.st_ino != fstatInfo.st_ino || \ lstatInfo.st_dev != fstatInfo.st_dev ) { close( fd ); return( -1 ); } /* If the above check was passed, we know that the lstat() and fstat() were done to the same file. Now check that there's only one link, and that it's a normal file (this isn't strictly necessary because the fstat() vs lstat() st_mode check would also find this) */ if( fstatInfo.st_nlink > 1 || !S_ISREG( lstatInfo.st_mode ) ) { close( fd ); return( -1 ); } /* On systems which don't support ftruncate() the best we can do is to close the file and reopen it in create mode which unfortunately leads to a race condition, however "systems which don't support ftruncate()" is pretty much SCO only, and if you're using that you deserve what you get ("Little sympathy has been extended") */ #ifdef NO_FTRUNCATE close( fd ); if( ( fd = open( fileName, O_CREAT | O_TRUNC | O_RDWR ) ) == -1 ) return( -1 ); mode = "wb"; #else ftruncate( fd, 0 ); #enndif /* NO_FTRUNCATE */ } /* Open a stdio file over the low-level one */ stream->filePtr = fdopen( fd, mode ); if( stream->filePtr == NULL ) { close( fd ); unlink( fileName ); return( -1 ); /* Internal error, should never happen */ } }