commit 14c90f733524a4f9142559f87584f377461fe4ef Author: dwheeler Date: Tue Jan 16 02:44:45 2007 +0000 Initial import git-svn-id: svn+ssh://svn.code.sf.net/p/flawfinder/code/trunk@1 5c01084b-1f27-0410-9f85-80411afe95dc diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..60549be --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..fe6328e --- /dev/null +++ b/ChangeLog @@ -0,0 +1,529 @@ +2004-06-15 David A. Wheeler + * Released version 1.26. + * NOTE: Due to an error on my part, + the tar file for version 1.25 was for a short period + (after 2004-06-05) actually version 1.26, + incorrectly labelled as 1.25. + My sincere apologies!! Please upgrade to 1.26, since that + way you'll be SURE to get the right version. + +2004-06-04 David A. Wheeler + * Reviewed and modified Jared's code somewhat, and added + support for _TEXT() as well as _T(). + See http://www.rpi.edu/~pudeyo/articles/unicode.html for more info + on Microsoft's approach to internationalization involving TCHAR. + * Wrote ChangeLog entries for Jared's code. + +2004-06-04 Jared Robinson (jarrob, at, symantec.com) + * Added more support for Microsoft's approach to internationalization. + Thus, it accepts _T() just like gettext(), and adds many more + functions: _getts(), vswprintf(), _stprintf(), _vstprintf(), + vwprintf(), vfwprintf(), _vtprintf(), _ftprintf(), _vftprintf(), + _sntprintf(), _vsntprintf(), _ftscanf(), _gettc(). + In this approach, TCHAR and various macros are typically used. + In particular, _T() of tchar.h converts character strings + to long character strings, if _UNICODE is defined + (this makes TCHAR a long 16-bit character). Thus, T() is: + #ifdef _UNICODE + #define _T(x) L ## x + #else + #define _T(x) x + #endif + +2004-06-02 David A. Wheeler + * Added two new rules for GLib functions, + "g_get_home_dir" and "g_get_tmp_dir", per a suggestion by + Steve Kemp, lead of the Debian Security Auditing Project. + This closes the wishlist item in Debian bug report #250432 + (see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=250432). + Contributors - please email wishlist items to me; + I can't monitor every distribution's local bug tracking system. + PLEASE tell upstream developers when there's a bug/wishlist + item, we can't fix it if we don't know. + * Added curl_getenv(). Kemp's suggestion reminded me to search + for other getenv()-like functions, and that one popped up. + * Added several rules for input functions (for -I) - + recv, recvfrom, recvmsg, fread, and readv. + * Tightened the false positive test slightly; if a name is + followed by = or - or + it's unlikely to be a function call, + so it'll be quietly discarded. + * Modified the summary report format slightly. + * Modified the getpass text to remove an extraneous character, + thanks to a bug report from Joerg Beyer (job, at, webde-ag.de) + * Modified installation instructions to clarify how to set + INSTALL_DIR at run-time so it installs elsewhere. + It uses the standard GNU conventions, but not everyone + knows about them. By default, it installs in /usr/local. + Just use normal make overrides to change that, e.g., + make INSTALL_DIR=/usr INSTALL_DIR_MAN=/usr/share/man install + I do NOT use the ?= macro-setting commands in the makefile, + because that's not standard (e.g., it's not in SUSv3), so + while that would work in GNU make, it wouldn't work in others. + +2004-05-31 David A. Wheeler + * Released version 1.25. + + +2004-05-30 David A. Wheeler + * Added more rules for finding problems by examining the + Red Hat Linux 9 documentation (the man3 man pages), + looking for phrases like "do not use", "security", and "obsolete". + Thus, added rules for + cuserid, getlogin, getpass, mkstemp, getpw, memalign, as + well as the obsolete functions gsignal, ssignal, ulimit, usleep. + * Modified text for strncat to clarify it. + My thanks to Christian Biere, christianbiere, at, gmx.de, for + reporting the problem. + * Added lengthy text to the manual to explain exactly how to use + flawfinder with vim and emacs. This should also help + integrate flawfinder into other text editors/IDEs. + * Fixed error in --columns format, so that the output is simply + "filename:linenumber:columnnumber" when --columns (-C) is used. + * Eliminated "Number of" phrase in the footer report + (it was redundant anyway) + * Added more statistical information to the footer report. + * Changed makefile to simplify running tests. + * Tests now autogenerate html and txt versions. + * Added shortcut single-letter commands (-D for --dataonly, + -Q for --quiet, -C for --columns), so that invoking from + editors is easier. + * Tries to autoremove some false positives. In particular, a function + name followed immediately by "=" (ignoring whitespace) + is automatically considered to be a variable and NOT a function, + and thus doesn't register as a hit. There are exotic cases + where this won't be correct, but they're pretty unlikely in + real code. + * Added a "--falsepositive" (-F) option, which tries to remove + many more likely false positives. The current heuristic is: + if -F is enabled, any function name must be + followed by "(" (ignoring whitespace) to be considered a + possible hit; otherwise, it's thrown away. + Thus, if you often use variable names that are + also the names of risky functions, like "access", you + might consider using this option. Note that flawfinder + uses simple lexical analysis; eliminating many more false positives + would require deeper code analysis + (to examine type information, buffer size declarations, etc.). + This option also disables reporting of static character + buffer arrays. + This -F option and the autoremoving of false positives above is + in response to a problem report from + Mike Ruscher (Mike.Ruscher, at, cse-cst.gc.ca), + though the approach and code is my own. This may not completely + solve Mr. Ruscher's problem, but it's a start. + * Documented that flawfinder output can be misunderstood if + there are source filenames whose names contain newline, linefeed, or + colon. Source filenames shouldn't have such characters anyway; + while flawfinder can handle them, many other tools can't. + * Modified the documentation to make it clear in the synopsis + which one-letter flags are short for which long names. + * Modified "make install" script slightly so that it creates + directories that don't yet exist when installing. + My thanks to Joerg Beyer (job, at webde-ag.de) for reporting + the problem and suggesting a solution. + This solution requires that "mkdir" support the "-p" option, + which shouldn't be a problem for nearly all users. + +2003-10-29 David A. Wheeler + * Released version 1.24. + * Fixed an incredibly obscure parsing error that caused some + false positives. If a constant C string, after the closing + double-quote, is followed by a \ and newline (instead of a comma), + the string might not be recognized as a constant string + (thus triggering warnings about non-constant values in some cases). + This kind of formatting is quite ugly and rare. + My thanks to Sascha Nitsch (sascha, at spsn.ath.cx) for pointing + this bug out and giving me a test case to work with. + * Added a warning for readlink. The implementation and warning + are mine, but the idea of warning about readlink came from + Stefan Kost (kost, at imn.htwk-leipzig.de). Thanks!! + +2003-09-27 David A. Wheeler + * Released version 1.23. Minor bugfixes. + +2003-09-27 David A. Wheeler + * Fixed subtle bug - in some circumstances single character constants + wouldn't be parsed correctly. My thanks to Scott Renfro + (scottdonotspam, at, renfro.org) for notifying me about this bug. + Scott Renfro also sent me a patch; I didn't use it + (the patch didn't handle other cases), but I'm grateful since it + illustrated the problem. + * Fixed documentation bug in man page. + The option "--minlevel=X" must be preceded by two dashes, + as are all GNU-style long options. The man page accidentally only + had one dash in the summary (it was correct elsewhere); it now + correctly shows both dashes. + * Modified man page to list filename extensions that are + interpreted as C/C++. + * Removed index.html from distribution - it's really only for the + website. + +2003-03-08 David A. Wheeler + * Released version 1.22. Output format slightly changed (colon added), + so that it's compatible with tools that expect compiler warnings + in the typical format "filename:line-number: warning". + To get the fully expected format (all in one line), use "-S". + Also, improved RPM packaging. + +2003-03-08 David A. Wheeler + * Changed makefile to be consistent with new RPM packaging approach. + * Changed makefile: now for testing, will automatically uninstall + old sloccount when creating rpm. Also (for me), make my_install + works (well, it helps me anyway). + +2003-02-01 Jose Pedro Oliveira + * Improved RPM packaging. + +2003-09-22 Jukka A. Ukkonen + * Recommended an extra colon in the output format, so that the + output format would like like typical compiler output (and thus + more compatible with existing tools that report warnings). + +2002-09-07 David A. Wheeler + * Released version 1.21, with the following changes: + * Improved the default output so it creates multiple formatted lines + instead of single very long lines for each hit. + Use the new "--singleline" (-S) option to get the original + "long line" format. + * Removed duplicate "getpass" entry in the ruleset; + this didn't hurt anything, but was unnecessary. + Thanks to the user who gave me that feedback, wish I'd kept your + email address so I could credit you properly :-). + * Added a short tutorial to man page. + * Fixed initial upper/lower case on many entries in the ruleset. + * Allow "--input" as a synonym for "--inputs". + +2002-07-07 David A. Wheeler + * Released version 1.20, with many more changes: + * Entries have been added to the database to detect file openings and + static character array definitions. + * The HTML format has been significantly improved. + * Joerg Beyer provided several nice improvements to flawfinder, + including a timing report. + * Now Flawfinder by default skips symbolic links, + and always skips special files, to counter attackers who + insert malicious files in their source code directories. + * The documentation has been improved in various ways. + +2002-07-05 David A. Wheeler + * Completely rewrote the functions handling opening the + files/directories named on the command line and when + walking down the directory tree. This was in part + to handle a new security requirement for source code web + hosting services, which may analyze code written by someone else + AND then send reports to someone else who doesn't have the + same rights to view files as the analysis program. + It's the last part that's different - the attacker may control + the code being analyzed and insert non-regular files or + symbolic links to "bad" files like /etc/passwd (to expose its + contents) or /dev/zero (to stall analysis). These are + annoying but not really a problem when the analyst is running on + his OWN machine. + To deal with this, now flawfinder NEVER opens a file type that isn't + a file or directory, and it skips symbolic + links by default (though this can be changed), + no matter if they're listed at the top or inside + a directory descendent. This is actually reasonable behavior + for everyone, since others may be analyzing programs + that they don't trust either. + * Added open() and fopen() as entries, now it has 127 entries + in the database. Modified test code to test it. + * Warning messages about skipping symlinks and + files that aren't regular files are now controlled by --quiet + instead of --dataonly; since --quiet controls printing + status messages this seems more reasonable. + * Changed the format of the HTML output - now it creates a list. + The ending is now in regular type, instead of
...
. + This seemed too look nicer. + * Reworked Beyer's patch that prints speed somewhat, e.g., to print + floating point time (on small programs or fast machines + the time would be reported as "0") and to avoid + divide-by-zero on systems where time really is reported + as zero. + * Added "--omittime", so that the regression test + results won't vary depending on the time the analysis takes. + * Fixed minor bug: now the filename "-" works to mean + standard input. This is rarely used, since usually files + are analyzed instead. + * Modified documentation to make clear that in many circumstances + you need to copy the source code to a separate area. + I removed the reference to "--nolink", since this is now + the default. + * Modified makefile to generate correct-results.html and + correct-results.txt, so that (1) there will be a standard + to compare with and (2) the web page has a demo. + +2002-07-05 Joerg Beyer + * Tiny patch to report the number of lines analyzed and + the analysis speed in lines/second. + +2002-07-04 David A. Wheeler + * Changed Joerg Beyer's patch that gives a nicer error + message if an invalid option flag is given. Now the patch + also works in Python 1.5. This involved using getopt.error + instead of getopt.GetoptError. + * Added a comment explicitly documenting that flawfinder + is written to run under both Python 1.5 and Python 2. + Lots of systems only include Python 1.5, or use Python 1.5 + as the default Python (e.g., Red Hat 7.2). + Someday that won't be a concern, but there's no reason it + can't easily port between the two for a while. + * Ran PyChecker and modified code to eliminate the errors it reports. + +2002-07-03 David A. Wheeler + * Changed the default to IGNORE symbolic links, and added the + --allowlink option to use symbolic links. This is a safer default, + and few people will really want to follow symbolic links anyway. + * Added option --dataonly to suppress headers and footers; + use this along with --quiet to get "just the facts" + (e.g., when processing the output with other tools). + This was inspired by a comment from A.T. Hofkamp. + +2002-07-03 Joerg Beyer + * Various small patches - thanks!! There were as follows: + * If you call flawfinder without input, + state that there was no input, not state that there's no hit. + * If interrupted with Control-C, flawfinder now prints cleanly + that it was interrupted. + * Print a nicer error message if an invalid option flag + is given. + * Just for completeness' sake, I'm including two of the patches: + --- flawfinder_orig Wed Jul 3 09:56:34 2002 + +++ flawfinder Wed Jul 3 10:25:49 2002 + @@ -1216,10 +1216,15 @@ + if loadhitlist: + f = open(loadhitlist) + hitlist = pickle.load(f) + else: + - for f in sys.argv[1:]: + + files = sys.argv[1:] + + if not files: + + print "*** no input files" + + return None + + for f in files: + process_dir_or_file(f) + + return 1 + + def show_final_results(): + global hitlist + count = 0 + @@ -1275,11 +1280,14 @@ + def flawfind(): + process_options() + display_header() + initialize_ruleset() + - process_files() + - show_final_results() + - save_if_desired() + + if process_files(): + + show_final_results() + + save_if_desired() + + + Detect control-C: + + --- flawfinder_orig Wed Jul 3 09:56:34 2002 + +++ flawfinder Wed Jul 3 09:58:37 2002 + @@ -1281,5 +1281,8 @@ + save_if_desired() + + if __name__ == '__main__': + - flawfind() + + try: + + flawfind() + + except KeyboardInterrupt: + + print "*** Flawfinder interrupted" + + --- flawfinder_orig Wed Jul 3 09:56:34 2002 + +++ flawfinder Wed Jul 3 09:58:37 2002 + @@ -1280,6 +1280,9 @@ + show_final_results() + save_if_desired() + + if __name__ == '__main__': + - flawfind() + + try: + + flawfind() + + except KeyboardInterrupt: + + print "*** Flawfinder interrupted" + + +2002-07-02 David A. Wheeler + * Added detection of static arrays of char, wchar_t, and TCHAR. + * Fixed typo in makefile uninstall script. My thanks to + Andrew Dalgleish for pointing this out. + * Modified installation to be friendlier to Cygwin. My thanks to + Andrew Dalgleish for pointing this out, too. + One step involved creating PYTHONEXT in the makefile + and documenting it, which was no problem. + A more surprising problem was that the INSTALL file needed to + be renamed to "INSTALL.txt", because otherwise "make install" + thinks that everything is already installed. + This is a nasty problem caused by Windows' type insensitivity + conflicting with normal Unix standards... this should really + be noted somewhere in various standard documents!! + I eventually added a ".PHONY:" target to the makefile, + which also solves the problem when using GNU make. + * Fixed ChangeLog - the 2002 dates were accidentally 2001. + +2002-07-02 David A. Wheeler + * Changed correct-results so that the version numbers are right. + * Created "make test-is-correct" which moves the test results + into the "correct-results" file. + +2002-07-02 David A. Wheeler + * Released version 1.01. + * Bugfix: Programs with getopt() or getopt_long() could trigger + a problem with flawfinder itself. Now fixed. + * Added the --nolink option, and a detailed description in the + man page. Basically, this foils attacks where malicious + programmers insert into their source tree symbolic links + to files like /etc/passwd or /dev/zero. + You still need to copy source code files into a separate area + if you are worried about malicious programmers; see the + new man page discussion about this. + +2002-07-01 David A. Wheeler + * Released version 1.00, a major step forward. + * I have significantly enlarged the database, from 55 rules + to 122 rules. Making the database this large is such a + major improvement in its usefulness that I've bumped the + version number up to 1.00. A number are from my book, + while others are suggested by "Writing Secure Code" by + Howard and LeBlanc (for the Windows-specific issues). + * Added HTML generation support. + * Significantly enlarged the test suite. + +2002-5-6 David A. Wheeler + * Released version 0.22, a very minor improvement. + * Modified the report about %s in scanf when a limit for %s + was provided; some found the error report very + confusing. My thanks to Agustin.Lopez, who asked a question + that led me to this understanding. + +2001-12-18 David A. Wheeler + * Released version 0.21. + * Fixed an error in the database entry for syslog(3), which + would cause incorrect hits. This resolves the Debian bug + "Bug#124009: flawfinder: wrong reports of format + fulnerabilities for syslog". + * Added simple "INSTALL" file. + * Fixed documentation, documenting --version and fixing a + format problem with "--neverignore". + * I accidentally wrote over version 0.20 with version 0.21's + contents. Sigh. + +2001-12-11 David A. Wheeler + * Released version 0.20. + * Added --version, which prints JUST the version number without + actually analyzing any programs. + +2001-11-08 David A. Wheeler + * Fixed MANIFEST.in to include "flawfinder.1*"; that way the + compressed man page is included when using MANIFEST.in. + Thanks to Jon Nelson for noting this. + The effect of this is quite tiny - + my tar file & rpm files already included the compressed + man page, so this error affects very few people. + Note also that this just meant that only the uncompressed + man page was in the MANIFEST, so I don't expect that this + error had any user-visible effects other than a few more K of man + page space (and with multi-Gigabyte drives, that's hard to notice). + +2001-11-04 David A. Wheeler + * Released version 0.19 + * Fixed a minor bug - flawfinder didn't realize that multiline strings + passed to gettext() are still constant strings. + My thanks to "Arthur", who reported this bug, and + Adam Lazur (Debian) who passed it on to me. + This closes Debian Bug#118025. + * Minor change - precomputed internationalization pattern for + a minor performance improvement. + * Output a reminder that not all hits are actually security + vulnerabilities, as well as that there may be other vulnerabilities. + The documentation mentioned this too, but including that in + the output of the program makes it clearer (apparantly some + expect flawfinder to perform amazing magic far beyond the + possible). I think ALL programs like this should include this + reminder; otherwise sane software developers somehow expect + programs like this to work miracles, instead of simply reporting + likely spots based on heuristics. + +2001-11-03 David A. Wheeler + * Added a "help" option and support for DistUtils, as well as + modification of the RPM spec file so it can be built by non-root. + My thanks to Jon Nelson for the patches to do this. + * Added "syslog" to the vulnerability database. + My thanks to Dave Aitel for this contribution. + * Generate and install compressed man page, rather than uncompressed. + My thanks to Marius Tomaschewski for this suggestion. + +2001-10-29 David A. Wheeler + * Released version 0.17. + * Created an RPM package, to simplify installation. + * Accepts RATS' "ignore" directive, as well as ITS4's, for + compatibility's sake with RATS. + * Trivial change: shortened processing status phrase to + "Processing" so long filenames are more likely to fit on one line. + * Modified the man page, in the hopes that the new one is even + easier to understand. + +2001-10-28 David A. Wheeler + * Released version 0.16. + * Added support for directories. If a directory (instead of a + file) is given on the command line as something to examine, + C/C++ files in that directory and its subdirectories (recursively) + are examined. This should make it easy to analyze entire projects, + and to make it easy to integrate flawfinder into project websites. + * Added to the vulnerability database: randomizing functions & getenv. + * Reports the number of hits at the end. + * Minor cleanup of text output. + * Print "processing" status every time a file is opened; this is + flushed, so that monitoring the status with "less" works well. + * Added the "--quiet" option, so that status information can be + suppressed. + +2001-06-06 David A. Wheeler + * Added support for file globbing on Windows/NT/DOS + (it's not needed for Cygwin - it's only needed when + run natively). File globbing characters are + correctly ignored in Unix-like ("posix") systems, since + the Unix shell does this for us. + +2001-05-29 David A. Wheeler + * Fixed manual page to close the "/*" comment with "*/". + +2001-05-29 David A. Wheeler + * Fixed a bug in directive handling, now directives work properly. + I only noticed this AFTER release of 0.14, sigh. + * Fixed the ChangeLog, to note the addition of --neverignore. + * Released version 0.15. + +2001-05-29 David A. Wheeler + * Fixed a minor problem in string handling; a string containing + \\ followed immediately by the double-quote mark (end of the string) + wasn't correctly handled. Now it is. + * Added information in the documentation describing how to ignore + hits on a specific line (a comment directive). Flawfinder has + always had this ability (since 0.12), but now it's documented. + Before, you had to read the test file test.c or the actual + flawfinder code to learn about this ability. + * Added the "--neverignore" / "-n" option. + * Having a number of conversations with John Viega comparing + RATS and flawfinder, with the goal of finding a way to + coordinate and have a "best of breed" scanner. This hasn't + produced a concrete result, but Viega will soon post a comparison + paper that I've had input on. + * Released version 0.14. + +2001-05-25 David A. Wheeler + * Fixed a minor error in that parameter parser; previously it + might have trouble with embedded preprocessor commands in + the middle of parameter lists. + * Added this ChangeLog. + * Released version 0.13. + +2001-05-21 David A. Wheeler + * Initial release of flawfinder version 0.12. + + diff --git a/INSTALL.txt b/INSTALL.txt new file mode 100644 index 0000000..991e7c7 --- /dev/null +++ b/INSTALL.txt @@ -0,0 +1,65 @@ +To install flawfinder: + +If you use an RPM-based system (e.g., Red Hat) or deb-based system +(e.g., Debian), use their respective RPM or debian installation program +and just install it; then ignore the rest of these instructions. +For a ports-based system where you have a current port, just use that. + +Otherwise, you'll need to install from the tarball. +So, here's how to do that. + +* Install the "tarball" and uncompress it. + GNU-based systems can run "tar xvzf flawfinder*.tar.gz" to do so, + then "cd" into the directory created. If that doesn't work + (e.g., you have an old tar program), use: + gunzip flawfinder*.tar.gz + tar xvf flawfinder*.tar + cd flawfinder-* + +* Decide where you want to put it. Flawfinder normally installs + in /usr/local, with the program in /usr/local/bin and the manual in + /usr/local/man, per GNU conventions. You can override this + using the normal GNU conventions when installing (with "make install") + by setting INSTALL_DIR (defaults to /usr/local), + INSTALL_DIR_BIN for the program location (defaults to INSTALL_DIR/bin), and + INSTALL_DIR_MAN for the manual location (defaults to INSTALL_DIR/man). + +* If you're using Cygwin on Windows, you can install it using "make install" + but you need to tell the makefile to use the .py extension + whenever you use make. This will be another make install override. + If you'll just install it, do this: + + make PYTHONEXT=.py install + + If you don't want to pass the "PYTHONEXT" extension each time, + you can change the file "makefile" to remember this. Just change + the line beginning with "PYTHONEXT=" so that it reads as follows: + PYTHONEXT=.py + +* Now install it, giving whatever overrides you need. + In most cases, you'll need to be root, so run this first: + su + + Then give the "make install" command appropriate for your system. + For an all-default installation, which is what you need for most cases: + make install + + (you need to be root; "make uninstall" reverses it). + + To install in /usr (the program in /usr/bin, the manual in /usr/man): + make INSTALL_DIR=/usr install + + To put the binaries in /usr/bin, and the manuals in /usr/share/man + (common for Red Hat Linux), do: + make INSTALL_DIR=/usr INSTALL_DIR_MAN=/usr/share/man install + + +* Windows systems should be able to run this on the command line (cmd.exe) + directly, but I haven't tried that. + +* You can also simply run the program in the directory you've unpacked it + into. It's a simple Python program, just type into a command line: + + ./flawfinder files_or_directory + + diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..c871528 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,14 @@ +include COPYING +include README +include announcement +include ChangeLog +include flawfinder.1* +include flawfinder.pdf +include flawfinder.ps + +include flawfinder +include makefile +include setup.cfg +include setup.py +include test.c +include test_result diff --git a/README b/README new file mode 100644 index 0000000..360c30a --- /dev/null +++ b/README @@ -0,0 +1,7 @@ +This is "flawfinder" by David A. Wheeler, . +It's a simple Python program for scanning source code for security problems. + +For more information, see: + http://www.dwheeler.com/flawfinder + +See INSTALL for installation instructions. diff --git a/announcement b/announcement new file mode 100644 index 0000000..2210ea8 --- /dev/null +++ b/announcement @@ -0,0 +1,29 @@ + +I've just released "flawfinder", a program that can scan source code +and identify out potential security flaws, ranking them by likely severity. +Unlike ITS4, flawfinder is completely open source / free software +(it's released under the GPL license). + +Flawfinder will miss some security problems, and point out issues that aren't +really security problems, but nevertheless I think it can help track +down security problems in code so that the code can be fixed. + +You can download flawfinder from: + http://www.dwheeler.com/flawfinder + +Flawfinder is in its very early stages - I'm labelling it version "0.12". +It works reliably, but its ruleset is currently small and rudimentary. +It can already find some security problems now, but expanding its ruleset +will give it much more power. Also, it currently can only examine C/C++ code. + +After I wrote flawfinder - and just before I released it - I found out that +Secure Software Solutions was also writing a program (RATS) to perform this +same task, also to be released under the GPL. We agreed to release our +programs simultaneously, and to mention each other's programs in our +announcements. Now that we've released our programs, we plan to coordinate +so that there will be a single open source / free software +source code scanner that will be a ``best of breed.'' + +--- David A. Wheeler + dwheeler@dwheeler.com + diff --git a/correct-results.html b/correct-results.html new file mode 100644 index 0000000..2535e58 --- /dev/null +++ b/correct-results.html @@ -0,0 +1,270 @@ + + + + +Flawfinder Results + + + + +

Flawfinder Results

+Here are the security scan results from +Flawfinder version 1.25, +(C) 2001-2004 David A. Wheeler. +Number of dangerous functions in C/C++ ruleset: 137 +

+Examining test.c
+Examining test2.c
+

    +
  • test.c:32: [5] (buffer) gets: + Does not check for buffer overflows. Use fgets() instead. +
    + gets(f);
    +
    +
  • test.c:56: [5] (buffer) strncat: + Easily used incorrectly (e.g., incorrectly computing the correct + maximum size to add). Consider strlcat or automatically resizing strings. + Risk is high; the length parameter appears to be a constant, instead of + computing the number of characters left. +
    +  strncat(d,s,sizeof(d)); /* Misuse - this should be flagged as riskier. */
    +
    +
  • test.c:57: [5] (buffer) _tcsncat: + Easily used incorrectly (e.g., incorrectly computing the correct + maximum size to add). Consider strlcat or automatically resizing strings. + Risk is high; the length parameter appears to be a constant, instead of + computing the number of characters left. +
    +  _tcsncat(d,s,sizeof(d)); /* Misuse - flag as riskier */
    +
    +
  • test.c:60: [5] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes. Risk is high, it + appears that the size is given as bytes, but the function requires size as + characters. +
    +  MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName));
    +
    +
  • test.c:62: [5] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes. Risk is high, it + appears that the size is given as bytes, but the function requires size as + characters. +
    +  MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName);
    +
    +
  • test.c:73: [5] (misc) SetSecurityDescriptorDacl: + Never create NULL ACLs; an attacker can set it to Everyone (Deny All + Access), which would even forbid administrator access. +
    +  SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE);
    +
    +
  • test.c:73: [5] (misc) SetSecurityDescriptorDacl: + Never create NULL ACLs; an attacker can set it to Everyone (Deny All + Access), which would even forbid administrator access. +
    +  SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE);
    +
    +
  • test.c:17: [4] (buffer) strcpy: + Does not check for buffer overflows when copying to destination. + Consider using strncpy or strlcpy (warning, strncpy is easily misused). +
    + strcpy(b, a);
    +
    +
  • test.c:20: [4] (buffer) sprintf: + Does not check for buffer overflows. Use snprintf or vsnprintf. +
    + sprintf(s, "hello %s", bug);
    +
    +
  • test.c:21: [4] (buffer) sprintf: + Does not check for buffer overflows. Use snprintf or vsnprintf. +
    + sprintf(s, gettext("hello %s"), bug);
    +
    +
  • test.c:22: [4] (format) sprintf: + Potential format string problem. Make format string constant. +
    + sprintf(s, unknown, bug);
    +
    +
  • test.c:23: [4] (format) printf: + If format strings can be influenced by an attacker, they can be + exploited. Use a constant for the format specification. +
    + printf(bf, x);
    +
    +
  • test.c:25: [4] (buffer) scanf: + The scanf() family's %s operation, without a limit specification, + permits buffer overflows. Specify a limit to %s, or use a different input + function. +
    + scanf("%s", s);
    +
    +
  • test.c:27: [4] (buffer) scanf: + The scanf() family's %s operation, without a limit specification, + permits buffer overflows. Specify a limit to %s, or use a different input + function. +
    + scanf("%s", s);
    +
    +
  • test.c:38: [4] (format) syslog: + If syslog's format strings can be influenced by an attacker, they can + be exploited. Use a constant format string for syslog. +
    + syslog(LOG_ERR, attacker_string);
    +
    +
  • test.c:49: [4] (buffer) _mbscpy: + Does not check for buffer overflows when copying to destination. + Consider using a function version that stops copying at the end of the + buffer. +
    +  _mbscpy(d,s); /* like strcpy, this doesn't check for buffer overflow */
    +
    +
  • test.c:52: [4] (buffer) lstrcat: + Does not check for buffer overflows when concatenating to destination. +
    +  lstrcat(d,s);
    +
    +
  • test.c:75: [3] (shell) CreateProcess: + This causes a new process to execute and is difficult to use safely. + Specify the application path in the first argument, NOT as part of the + second, or embedded spaces could allow an attacker to force a different + program to run. +
    +  CreateProcess(NULL, "C:\\Program Files\\GoodGuy\\GoodGuy.exe -x", "");
    +
    +
  • test.c:75: [3] (shell) CreateProcess: + This causes a new process to execute and is difficult to use safely. + Specify the application path in the first argument, NOT as part of the + second, or embedded spaces could allow an attacker to force a different + program to run. +
    +  CreateProcess(NULL, "C:\\Program Files\\GoodGuy\\GoodGuy.exe -x", "");
    +
    +
  • test.c:91: [3] (buffer) getopt_long: + Some older implementations do not protect against internal buffer + overflows . Check implementation on installation, or limit the size of all + string inputs. +
    +    while ((optc = getopt_long (argc, argv, "a",longopts, NULL )) != EOF) {
    +
    +
  • test.c:16: [2] (buffer) strcpy: + Does not check for buffer overflows when copying to destination. + Consider using strncpy or strlcpy (warning, strncpy is easily misused). Risk + is low because the source is a constant string. +
    + strcpy(a, gettext("Hello there")); // Did this work?
    +
    +
  • test.c:19: [2] (buffer) sprintf: + Does not check for buffer overflows. Use snprintf or vsnprintf. Risk + is low because the source has a constant maximum length. +
    + sprintf(s, "hello");
    +
    +
  • test.c:45: [2] (buffer) char: + Statically-sized arrays can be overflowed. Perform bounds checking, + use functions that limit length, or ensure that the size is larger than + the maximum possible length. +
    +  char d[20];
    +
    +
  • test.c:46: [2] (buffer) char: + Statically-sized arrays can be overflowed. Perform bounds checking, + use functions that limit length, or ensure that the size is larger than + the maximum possible length. +
    +  char s[20];
    +
    +
  • test.c:50: [2] (buffer) memcpy: + Does not check for buffer overflows when copying to destination. Make + sure destination can always hold the source data. +
    +  memcpy(d,s);
    +
    +
  • test.c:51: [2] (buffer) CopyMemory: + Does not check for buffer overflows when copying to destination. Make + sure destination can always hold the source data. +
    +  CopyMemory(d,s);
    +
    +
  • test.c:97: [2] (misc) fopen: + Check when opening files - can an attacker redirect it (via symlinks), + force the opening of special file type (e.g., device files), move + things around to create a race condition, control its ancestors, or change + its contents?. +
    +  f = fopen("/etc/passwd", "r"); 
    +
    +
  • test.c:15: [1] (buffer) strcpy: + Does not check for buffer overflows when copying to destination. + Consider using strncpy or strlcpy (warning, strncpy is easily misused). Risk + is low because the source is a constant character. +
    + strcpy(a, "\n"); // Did this work?
    +
    +
  • test.c:18: [1] (buffer) sprintf: + Does not check for buffer overflows. Use snprintf or vsnprintf. Risk + is low because the source is a constant character. +
    + sprintf(s, "\n");
    +
    +
  • test.c:26: [1] (buffer) scanf: + it's unclear if the %s limit in the format string is small enough. + Check that the limit is sufficiently small, or use a different input + function. +
    + scanf("%10s", s);
    +
    +
  • test.c:53: [1] (buffer) strncpy: + Easily used incorrectly; doesn't always \0-terminate or check for + invalid pointers. +
    +  strncpy(d,s);
    +
    +
  • test.c:54: [1] (buffer) _tcsncpy: + Easily used incorrectly; doesn't always \0-terminate or check for + invalid pointers. +
    +  _tcsncpy(d,s);
    +
    +
  • test.c:55: [1] (buffer) strncat: + Easily used incorrectly (e.g., incorrectly computing the correct + maximum size to add). Consider strlcat or automatically resizing strings. +
    +  strncat(d,s,10);
    +
    +
  • test.c:58: [1] (buffer) strlen: + Does not handle strings that are not \0-terminated (it could cause a + crash if unprotected). +
    +  n = strlen(d);
    +
    +
  • test.c:64: [1] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes. Risk is very low, + the length appears to be in characters not bytes. +
    +  MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName)/sizeof(wszUserName[0]));
    +
    +
  • test.c:66: [1] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes. Risk is very low, + the length appears to be in characters not bytes. +
    +  MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName /sizeof(wszUserName[0]));
    +
    +
+

+Hits = 36 +
+Lines analyzed = 118 +
+Physical Source Lines of Code (SLOC) = 80 +
+Hits @ level = [0] 0 [1] 9 [2] 7 [3] 3 [4] 10 [5] 7
+Hits @ level+ = [0+] 36 [1+] 36 [2+] 27 [3+] 20 [4+] 17 [5+] 7
+Hits/KSLOC @ level+ = [0+] 450 [1+] 450 [2+] 338 [3+] 250 [4+] 213 [5+] 88
+Suppressed hits = 2 (use --neverignore to show them) +
+Minimum risk level = 1 +
+Not every hit is necessarily a security vulnerability. +
+There may be other security vulnerabilities; review your code! + + diff --git a/correct-results.txt b/correct-results.txt new file mode 100644 index 0000000..d199548 --- /dev/null +++ b/correct-results.txt @@ -0,0 +1,139 @@ +Flawfinder version 1.25, (C) 2001-2004 David A. Wheeler. +Number of dangerous functions in C/C++ ruleset: 137 +Examining test.c +Examining test2.c +test.c:32: [5] (buffer) gets: + Does not check for buffer overflows. Use fgets() instead. +test.c:56: [5] (buffer) strncat: + Easily used incorrectly (e.g., incorrectly computing the correct + maximum size to add). Consider strlcat or automatically resizing strings. + Risk is high; the length parameter appears to be a constant, instead of + computing the number of characters left. +test.c:57: [5] (buffer) _tcsncat: + Easily used incorrectly (e.g., incorrectly computing the correct + maximum size to add). Consider strlcat or automatically resizing strings. + Risk is high; the length parameter appears to be a constant, instead of + computing the number of characters left. +test.c:60: [5] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes. Risk is high, it + appears that the size is given as bytes, but the function requires size as + characters. +test.c:62: [5] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes. Risk is high, it + appears that the size is given as bytes, but the function requires size as + characters. +test.c:73: [5] (misc) SetSecurityDescriptorDacl: + Never create NULL ACLs; an attacker can set it to Everyone (Deny All + Access), which would even forbid administrator access. +test.c:73: [5] (misc) SetSecurityDescriptorDacl: + Never create NULL ACLs; an attacker can set it to Everyone (Deny All + Access), which would even forbid administrator access. +test.c:17: [4] (buffer) strcpy: + Does not check for buffer overflows when copying to destination. + Consider using strncpy or strlcpy (warning, strncpy is easily misused). +test.c:20: [4] (buffer) sprintf: + Does not check for buffer overflows. Use snprintf or vsnprintf. +test.c:21: [4] (buffer) sprintf: + Does not check for buffer overflows. Use snprintf or vsnprintf. +test.c:22: [4] (format) sprintf: + Potential format string problem. Make format string constant. +test.c:23: [4] (format) printf: + If format strings can be influenced by an attacker, they can be + exploited. Use a constant for the format specification. +test.c:25: [4] (buffer) scanf: + The scanf() family's %s operation, without a limit specification, + permits buffer overflows. Specify a limit to %s, or use a different input + function. +test.c:27: [4] (buffer) scanf: + The scanf() family's %s operation, without a limit specification, + permits buffer overflows. Specify a limit to %s, or use a different input + function. +test.c:38: [4] (format) syslog: + If syslog's format strings can be influenced by an attacker, they can + be exploited. Use a constant format string for syslog. +test.c:49: [4] (buffer) _mbscpy: + Does not check for buffer overflows when copying to destination. + Consider using a function version that stops copying at the end of the + buffer. +test.c:52: [4] (buffer) lstrcat: + Does not check for buffer overflows when concatenating to destination. +test.c:75: [3] (shell) CreateProcess: + This causes a new process to execute and is difficult to use safely. + Specify the application path in the first argument, NOT as part of the + second, or embedded spaces could allow an attacker to force a different + program to run. +test.c:75: [3] (shell) CreateProcess: + This causes a new process to execute and is difficult to use safely. + Specify the application path in the first argument, NOT as part of the + second, or embedded spaces could allow an attacker to force a different + program to run. +test.c:91: [3] (buffer) getopt_long: + Some older implementations do not protect against internal buffer + overflows . Check implementation on installation, or limit the size of all + string inputs. +test.c:16: [2] (buffer) strcpy: + Does not check for buffer overflows when copying to destination. + Consider using strncpy or strlcpy (warning, strncpy is easily misused). Risk + is low because the source is a constant string. +test.c:19: [2] (buffer) sprintf: + Does not check for buffer overflows. Use snprintf or vsnprintf. Risk + is low because the source has a constant maximum length. +test.c:45: [2] (buffer) char: + Statically-sized arrays can be overflowed. Perform bounds checking, + use functions that limit length, or ensure that the size is larger than + the maximum possible length. +test.c:46: [2] (buffer) char: + Statically-sized arrays can be overflowed. Perform bounds checking, + use functions that limit length, or ensure that the size is larger than + the maximum possible length. +test.c:50: [2] (buffer) memcpy: + Does not check for buffer overflows when copying to destination. Make + sure destination can always hold the source data. +test.c:51: [2] (buffer) CopyMemory: + Does not check for buffer overflows when copying to destination. Make + sure destination can always hold the source data. +test.c:97: [2] (misc) fopen: + Check when opening files - can an attacker redirect it (via symlinks), + force the opening of special file type (e.g., device files), move + things around to create a race condition, control its ancestors, or change + its contents?. +test.c:15: [1] (buffer) strcpy: + Does not check for buffer overflows when copying to destination. + Consider using strncpy or strlcpy (warning, strncpy is easily misused). Risk + is low because the source is a constant character. +test.c:18: [1] (buffer) sprintf: + Does not check for buffer overflows. Use snprintf or vsnprintf. Risk + is low because the source is a constant character. +test.c:26: [1] (buffer) scanf: + it's unclear if the %s limit in the format string is small enough. + Check that the limit is sufficiently small, or use a different input + function. +test.c:53: [1] (buffer) strncpy: + Easily used incorrectly; doesn't always \0-terminate or check for + invalid pointers. +test.c:54: [1] (buffer) _tcsncpy: + Easily used incorrectly; doesn't always \0-terminate or check for + invalid pointers. +test.c:55: [1] (buffer) strncat: + Easily used incorrectly (e.g., incorrectly computing the correct + maximum size to add). Consider strlcat or automatically resizing strings. +test.c:58: [1] (buffer) strlen: + Does not handle strings that are not \0-terminated (it could cause a + crash if unprotected). +test.c:64: [1] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes. Risk is very low, + the length appears to be in characters not bytes. +test.c:66: [1] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes. Risk is very low, + the length appears to be in characters not bytes. + +Hits = 36 +Lines analyzed = 118 +Physical Source Lines of Code (SLOC) = 80 +Hits @ level = [0] 0 [1] 9 [2] 7 [3] 3 [4] 10 [5] 7 +Hits @ level+ = [0+] 36 [1+] 36 [2+] 27 [3+] 20 [4+] 17 [5+] 7 +Hits/KSLOC @ level+ = [0+] 450 [1+] 450 [2+] 338 [3+] 250 [4+] 213 [5+] 88 +Suppressed hits = 2 (use --neverignore to show them) +Minimum risk level = 1 +Not every hit is necessarily a security vulnerability. +There may be other security vulnerabilities; review your code! diff --git a/flaw-defect-report b/flaw-defect-report new file mode 100644 index 0000000..0152996 --- /dev/null +++ b/flaw-defect-report @@ -0,0 +1,114 @@ +From - Sun Nov 4 11:39:04 2001 +X-UIDL: 4bd5a7eeb0e24a21ff091e0d7f4cec01 +X-Mozilla-Status: 0001 +X-Mozilla-Status2: 00000000 +Return-Path: +Received: from cs.ida.org by fricka.csed.ida.org (SMI-8.6/SMI-SVR4) + id WAA06993; Fri, 2 Nov 2001 22:22:00 -0500 +Received: from mailhost.nl (webframe.nl [212.204.207.201]) + by cs.ida.org (Switch-2.2.0/Switch-2.2.0) with SMTP id fA33Lxp18254 + for ; Fri, 2 Nov 2001 22:21:59 -0500 (EST) +Received: from x-o.clustermonkey.org (postfix@x-o.clustermonkey.org [64.242.77.225]) + by mailhost.nl (8.9.3/8.9.3) with ESMTP id EAA12369 + for ; Sat, 3 Nov 2001 04:21:56 +0100 +Received: by x-o.clustermonkey.org (Postfix, from userid 1000) + id 6B96B61E92B; Fri, 2 Nov 2001 22:21:54 -0500 (EST) +Date: Fri, 2 Nov 2001 22:21:54 -0500 +From: Adam Lazur +To: "David A. Wheeler" +Subject: [arthur@tiefighter.et.tudelft.nl: Bug#118025: flawfinder does not detect multiline strings right] +Message-ID: <20011102222154.B24827@clustermonkey.org> +Mime-Version: 1.0 +Content-Type: multipart/mixed; boundary="rwEMma7ioTxnRzrJ" +Content-Disposition: inline +User-Agent: Mutt/1.3.23i +X-UIDL: 4bd5a7eeb0e24a21ff091e0d7f4cec01 + + +--rwEMma7ioTxnRzrJ +Content-Type: text/plain; charset=us-ascii +Content-Disposition: inline + +Attached is the first bug report from the Debian package of flawfinder. + +Replies can be sent to 118025@bugs.debian.org and they will be appended +to the bug's history and also sent to the bug submitter. The bug history +can be found at: http://bugs.debian.org/118025 + +-- +Adam Lazur, Cluster Monkey + +--rwEMma7ioTxnRzrJ +Content-Type: message/rfc822 +Content-Disposition: inline + +X-Envelope-From: debbugs@master.debian.org Fri Nov 2 10:09:37 2001 +Return-Path: +Delivered-To: laz@clustermonkey.org +Received: from master.debian.org (unknown [216.234.231.5]) + by x-o.clustermonkey.org (Postfix) with ESMTP id 981EF61E913 + for ; Fri, 2 Nov 2001 10:09:37 -0500 (EST) +Received: from debbugs by master.debian.org with local (Exim 3.12 1 (Debian)) + id 15zfqY-0007Zt-00; Fri, 02 Nov 2001 09:03:02 -0600 +Subject: Bug#118025: flawfinder does not detect multiline strings right +Reply-To: arthur@tiefighter.et.tudelft.nl, 118025@bugs.debian.org +Resent-From: arthur@tiefighter.et.tudelft.nl +Resent-To: debian-bugs-dist@lists.debian.org +Resent-Cc: Adam Lazur +Resent-Date: Fri, 02 Nov 2001 15:03:02 GMT +Resent-Message-ID: +X-Debian-PR-Message: report 118025 +X-Debian-PR-Package: flawfinder +X-Loop: owner@bugs.debian.org +Received: via spool by submit@bugs.debian.org id=B.100471287428113 + (code B ref -1); Fri, 02 Nov 2001 15:03:02 GMT +From: arthur@tiefighter.et.tudelft.nl +X-Authentication-Warning: ch.twi.tudelft.nl: arthur owned process doing -bs +Date: Fri, 2 Nov 2001 15:54:02 +0100 (CET) +X-Sender: arthur@ch.twi.tudelft.nl +To: submit@bugs.debian.org +Message-ID: +MIME-Version: 1.0 +Content-Type: TEXT/PLAIN; charset=US-ASCII +Delivered-To: submit@bugs.debian.org +Resent-Sender: Debian BTS + + +Package: flawfinder +Version: 0.17-1 +Severity: normal + + +Does strange things with respect to strings that are spread over multiple +lines. + +Sample code: + +1: static void a() +2: { +3: printf(_("a")); +4: printf(_("b" +5: "c")); +6: printf("a"); +7: printf("b" +8: "c"); +9: } + +Flawfinder output (partial): +/tmp/tst.c:4 [4] (format) printf: if format strings can be influenced by an attacker, they can be exploited. Use a constant for the format specification. + +One would expect flawfinder either to report lines 3 and 4 as possible +security riscs or lines 4 and 7. This is not expected behaviour. + +On a sindenote a disclaimer may be in order about the accuracy of the +results. All things flawfinder reported on my code were no security +threats. + +-- arthur - arthur@tiefighter.et.tudelft.nl - http://tiefighter.et.tudelft.nl/~arthur -- + + + +--rwEMma7ioTxnRzrJ-- + + + diff --git a/flawfinder b/flawfinder new file mode 100755 index 0000000..9db2e63 --- /dev/null +++ b/flawfinder @@ -0,0 +1,1664 @@ +#!/usr/bin/env python + +"""flawfinder: Find potential security flaws ("hits") in source code. + Usage: + flawfinder [options] [source_code_file]+ + + See the man page for a description of the options.""" + +version="1.26" + +# The default output is as follows: +# filename:line_number [risk_level] (type) function_name: message +# where "risk_level" goes from 0 to 5. 0=no risk, 5=maximum risk. +# The final output is sorted by risk level, most risky first. +# Optionally ":column_number" can be added after the line number. +# +# Currently this program can only analyze C/C++ code. +# Note: this code is designed to run under both Python 1.5 and 2. +# Thus, it avoids constructs not in Python 1.5 such as "+=" +# and "print >> stderr". + +# Copyright (C) 2001-2004 David A. Wheeler +# This is released under the General Public License (GPL): +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + +import sys, re, string, getopt +import pickle # To support load/save/diff of hitlist +import os, glob, operator # To support filename expansion on Windows +import os.path +import time +# import formatter + +# Program Options - these are the default values: +show_context = 0 +minimum_level = 1 +show_immediately = 0 +show_inputs = 0 # Only show inputs? +falsepositive = 0 # Work to remove false positives? +allowlink = 0 # Allow symbolic links? +num_links_skipped = 0 # Number of links skipped. +show_columns = 0 +never_ignore = 0 # If true, NEVER ignore problems, even if directed. +list_rules = 0 # If true, list the rules (helpful for debugging) +loadhitlist = None +savehitlist = None +diffhitlist = None +quiet = 0 +showheading = 1 # --dataonly turns this off +output_format = 0 # 0 = normal, 1 = html. +single_line = 0 # 1 = singleline (can 't be 0 if html) +omit_time = 0 # 1 = omit time-to-run (needed for testing) + +displayed_header = 0 # Have we displayed the header yet? +num_ignored_hits = 0 # Number of ignored hits (used if never_ignore==0) + +def error(message): + sys.stderr.write("Error: %s\n"% message) + + +# Support routines: find a pattern. +# To simplify the calling convention, several global variables are used +# and these support routines are defined, in an attempt to make the +# actual calls simpler and clearer. +# + +filename = "" # Source filename. +linenumber = 0 # Linenumber from original file. +ignoreline = -1 # Line number to ignore. +sumlines = 0 # Number of lines (total) examined. +sloc = 0 # Physical SLOC +starttime = time.time() # Used to determine analyzed lines/second. + + +line_beginning = re.compile( r'(?m)^' ) +blank_line = re.compile( r'(?m)^\s+$' ) + +def htmlize(s): + # Take s, and return legal (UTF-8) HTML. + s1 = string.replace(s,"&","&") + s2 = string.replace(s1,"<","<") + s3 = string.replace(s2,">",">") + return s3 + +def h(s): + # htmlize s if we're generating html, otherwise just return s. + if output_format: return htmlize(s) + else: return s + +def print_multi_line(text): + # Print text as multiple indented lines. + width = 72 + prefix = " " + starting_position = len(prefix) + 1 + printed_something = 0 # Have we printed on this line? + position = starting_position + nextword = "" + + print prefix, + for c in text: + if (c == " "): + print nextword, + position = position + 1 # account for space we just printed. + printed_something = 1 + nextword = "" + else: # NonSpace. + nextword = nextword + c + position = position + 1 + if position > width: # Whups, out of space + if (printed_something): # We've printed something out. + print # Done with this line, move to next. + print prefix, + position = starting_position + print nextword, # Print remainder (can be overlong if no spaces) + + +class Hit: + """ + Each instance of Hit is a warning of some kind in a source code file. + See the rulesets, which define the conditions for triggering a hit. + Hit is initialized with a tuple containing the following: + hook: function to call when function name found. + level: (default) warning level, 0-5. 0=no problem, 5=very risky. + warning: warning (text saying what's the problem) + suggestion: suggestion (text suggesting what to do instead) + category: One of "buffer" (buffer overflow), "race" (race condition), + "tmpfile" (temporary file creation), "format" (format string). + Use "" if you don't have a better category. + url: URL fragment reference. + other: A dictionary with other settings. + + Other settings usually set: + + name: function name + parameter: the function parameters (0th parameter null) + input: set to 1 if the function inputs from external sources. + start: start position (index) of the function name (in text) + end: end position of the function name (in text) + filename: name of file + line: line number in file + column: column in line in file + context_text: text surrounding hit""" + + # Set default values: + source_position = 2 # By default, the second parameter is the source. + format_position = 1 # By default, the first parameter is the format. + input = 0 # By default, this doesn't read input. + note = "" # No additional notes. + filename = "" # Empty string is filename. + extract_lookahead = 0 # Normally don't extract lookahead. + + def __init__(self, data): + hook, level, warning, suggestion, category, url, other = data + self.hook, self.level = hook, level + self.warning, self.suggestion = warning, suggestion + self.category, self.url = category, url + # These will be set later, but I set them here so that + # analysis tools like PyChecker will know about them. + self.column = 0 + self.line = 0 + self.name = "" + self.context_text = "" + for key in other.keys(): + setattr(self, key, other[key]) + + def __cmp__(self, other): + return (cmp(other.level, self.level) or # Highest risk first. + cmp(self.filename, other.filename) or + cmp(self.line, other.line) or + cmp(self.column, other.column) or + cmp(self.name, other.name)) + + def __getitem__(self, X): # Define this so this works: "%(line)" % hit + return getattr(self, X) + + def show(self): + if output_format: print "

  • ", + sys.stdout.write(h(self.filename)) + + if show_columns: print ":%(line)s:%(column)s:" % self, + else: print ":%(line)s:" % self, + + if output_format: print "", + # Extra space before risk level in text, makes it easier to find: + print " [%(level)s]" % self, + if output_format: print "", + print "(%(category)s)" % self, + if output_format: print "", + print h("%(name)s:" % self), + if single_line: + print h("%(warning)s." % self), + if self.suggestion: print h(self.suggestion)+".", + print h(self.note), + else: + main_text = h("%(warning)s. " % self) + if self.suggestion: main_text = main_text + h(self.suggestion) + ". " + main_text = main_text + h(self.note) + print + print_multi_line(main_text) + if output_format: print "", + print + if show_context: + if output_format: print "
    "
    +      print h(self.context_text)
    +      if output_format: print "
    " + + + +# The "hitlist" is the list of all hits (warnings) found so far. +# Use add_warning to add to it. + +hitlist = [] + +def add_warning(hit): + global hitlist, num_ignored_hits + if show_inputs and not hit.input: return + if hit.level >= minimum_level: + if linenumber == ignoreline: + num_ignored_hits = num_ignored_hits + 1 + else: + hitlist.append(hit) + if show_immediately: + hit.show() + +def internal_warn(message): + print h(message) + +# C Language Specific + +def extract_c_parameters(text, pos=0): + "Return a list of the given C function's parameters, starting at text[pos]" + # '(a,b)' produces ['', 'a', 'b'] + i = pos + # Skip whitespace and find the "("; if there isn't one, return []: + while i < len(text): + if text[i] == '(': break + elif text[i] in string.whitespace: i = i + 1 + else: return [] + else: # Never found a reasonable ending. + return [] + i = i + 1 + parameters = [""] # Insert 0th entry, so 1st parameter is parameter[1]. + currentstart = i + parenlevel = 1 + instring = 0 # 1=in double-quote, 2=in single-quote + incomment = 0 + while i < len(text): + c = text[i] + if instring: + if c == '"' and instring == 1: instring = 0 + elif c == "'" and instring == 2: instring = 0 + # if \, skip next character too. The C/C++ rules for + # \ are actually more complex, supporting \ooo octal and + # \xhh hexadecimal (which can be shortened), but we don't need to + # parse that deeply, we just need to know we'll stay in string mode: + elif c == '\\': i = i + 1 + elif incomment: + if c == '*' and text[i:i+2]=='*/': + incomment = 0 + i = i + 1 + else: + if c == '"': instring = 1 + elif c == "'": instring = 2 + elif c == '/' and text[i:i+2]=='/*': + incomment = 1 + i = i + 1 + elif c == '/' and text[i:i+2]=='//': + while i < len(text) and text[i] != "\n": + i = i + 1 + elif c == '\\' and text[i:i+2]=='\\"': i = i + 1 # Handle exposed '\"' + elif c == '(': parenlevel = parenlevel + 1 + elif c == ',' and (parenlevel == 1): + parameters.append(string.strip( + p_trailingbackslashes.sub('', text[currentstart:i]))) + currentstart = i + 1 + elif c == ')': + parenlevel = parenlevel - 1 + if parenlevel <= 0: + parameters.append(string.strip( + p_trailingbackslashes.sub('', text[currentstart:i]))) + # Re-enable these for debugging: + # print " EXTRACT_C_PARAMETERS: ", text[pos:pos+80] + # print " RESULTS: ", parameters + return parameters + elif c == ';': + internal_warn("Parsing failed to find end of parameter list; " + "semicolon terminated it in %s" % text[pos:pos+200]) + return parameters + i = i + 1 + internal_warn("Parsing failed to find end of parameter list in %s" % + text[pos:pos+200]) + + +# These patterns match gettext() and _() for internationalization. +# This is compiled here, to avoid constant recomputation. +# FIXME: assumes simple function call if it ends with ")", +# so will get confused by patterns like gettext("hi") + function("bye") +# In practice, this doesn't seem to be a problem; gettext() is usually +# wrapped around the entire parameter. +# The ?s makes it posible to match multi-line strings. +gettext_pattern = re.compile(r'(?s)^\s*' + 'gettext' + r'\s*\((.*)\)\s*$') +undersc_pattern = re.compile(r'(?s)^\s*' + '_(T(EXT)?)?' + r'\s*\((.*)\)\s*$') + +def strip_i18n(text): + "Strip any internationalization function calls surrounding 'text', " + "such as gettext() and _()." + match = gettext_pattern.search(text) + if match: return string.strip(match.group(1)) + match = undersc_pattern.search(text) + if match: return string.strip(match.group(3)) + return text + +p_trailingbackslashes = re.compile( r'(\s|\\(\n|\r))*$') + +p_c_singleton_string = re.compile( r'^\s*"([^\\]|\\[^0-6]|\\[0-6]+)?"\s*$') + +def c_singleton_string(text): + "Returns true if text is a C string with 0 or 1 character." + if p_c_singleton_string.search(text): return 1 + else: return 0 + +# This string defines a C constant. +p_c_constant_string = re.compile( r'^\s*"([^\\]|\\[^0-6]|\\[0-6]+)*"$') + +def c_constant_string(text): + "Returns true if text is a constant C string." + if p_c_constant_string.search(text): return 1 + else: return 0 + + +# Precompile patterns for speed. + + +def c_buffer(hit): + source_position = hit.source_position + if source_position <= len(hit.parameters)-1: + source=hit.parameters[source_position] + if c_singleton_string(source): + hit.level = 1 + hit.note = "Risk is low because the source is a constant character." + elif c_constant_string(strip_i18n(source)): + hit.level = max( hit.level - 2, 1) + hit.note = "Risk is low because the source is a constant string." + add_warning(hit) + + +p_dangerous_strncat = re.compile(r'^\s*sizeof\s*(\(\s*)?[A-Za-z_$0-9]+' + + r'\s*(\)\s*)?(-\s*1\s*)?$') +# This is a heuristic: constants in C are usually given in all upper case letters. +# Yes, this need not be true, but it's true often enough that it's worth +# using as a heuristic. strncat better not be passed a constant as the length! +p_looks_like_constant = re.compile(r'^\s*[A-Z][A-Z_$0-9]+\s*(-\s*1\s*)?$') + +def c_strncat(hit): + if len(hit.parameters) > 3: + # A common mistake is to think that when calling strncat(dest,src,len), that + # "len" means the ENTIRE length of the destination. This isn't true, it must + # be the length of the characters TO BE ADDED at most. Which is one reason that + # strlcat is better than strncat. We'll detect a common case of this error; + # if the length parameter is of the form "sizeof(dest)", we have this error. + # Actually, sizeof(dest) is okay if the dest's first character is always \0, + # but in that case the programmer should use strncpy, NOT strncat. + # The following heuristic will certainly miss some dangerous cases, but + # it at least catches the most obvious situation. + # This particular heuristic is overzealous; it detects ANY sizeof, instead of + # only the sizeof(dest) (where dest is given in hit.parameters[1]). + # However, there aren't many other likely candidates for sizeof; some people + # use it to capture just the length of the source, but this is just as dangerous, + # since then it absolutely does NOT take care of the destination maximum length + # in general. It also detects if a constant is given as a length, if the + # constant follows common C naming rules. + length_text=hit.parameters[3] + if p_dangerous_strncat.search(length_text) or p_looks_like_constant.search(length_text): + hit.level = 5 + hit.note = ( "Risk is high; the length parameter appears to be a constant, " + + "instead of computing the number of characters left.") + add_warning(hit) + return + c_buffer(hit) + +def c_printf(hit): + format_position = hit.format_position + if format_position <= len(hit.parameters)-1: + # Assume that translators are trusted to not insert "evil" formats: + source = strip_i18n(hit.parameters[format_position]) + if c_constant_string(source): + # Parameter is constant, so there's no risk of format string problems. + if hit.name == "snprintf" or hit.name == "vsnprintf": + hit.level = 1 + hit.warning = \ + "On some very old systems, snprintf is incorrectly implemented " \ + "and permits buffer overflows; there are also incompatible " \ + "standard definitions of it" + hit.suggestion = "Check it during installation, or use something else" + hit.category = "port" + else: + # We'll pass it on, just in case it's needed, but at level 0 risk. + hit.level = 0 + hit.note = "Constant format string, so not considered very risky (there's some residual risk, especially in a loop)." + add_warning(hit) + + +p_dangerous_sprintf_format = re.compile(r'%-?([0-9]+|\*)?s') + +# sprintf has both buffer and format vulnerabilities. +def c_sprintf(hit): + source_position = hit.source_position + if source_position <= len(hit.parameters)-1: + source=hit.parameters[source_position] + if c_singleton_string(source): + hit.level = 1 + hit.note = "Risk is low because the source is a constant character." + else: + source = strip_i18n(source) + if c_constant_string(source): + if not p_dangerous_sprintf_format.search(source): + hit.level = max( hit.level - 2, 1) + hit.note = "Risk is low because the source has a constant maximum length." + # otherwise, warn of potential buffer overflow (the default) + else: + # Ho ho - a nonconstant format string - we have a different problem. + hit.warning = "Potential format string problem" + hit.suggestion = "Make format string constant" + hit.level = 4 + hit.category = "format" + hit.url = "" + add_warning(hit) + +p_dangerous_scanf_format = re.compile(r'%s') +p_low_risk_scanf_format = re.compile(r'%[0-9]+s') + +def c_scanf(hit): + format_position = hit.format_position + if format_position <= len(hit.parameters)-1: + # Assume that translators are trusted to not insert "evil" formats; + # it's not clear that translators will be messing with INPUT formats, + # but it's possible so we'll account for it. + source = strip_i18n(hit.parameters[format_position]) + if c_constant_string(source): + if p_dangerous_scanf_format.search(source): pass # Accept default. + elif p_low_risk_scanf_format.search(source): + # This is often okay, but sometimes extremely serious. + hit.level = 1 + hit.warning = "it's unclear if the %s limit in the format string is small enough" + hit.suggestion = "Check that the limit is sufficiently small, or use a different input function" + else: + # No risky scanf request. + # We'll pass it on, just in case it's needed, but at level 0 risk. + hit.level = 0 + hit.note = "No risky scanf format detected." + else: + # Format isn't a constant. + hit.note = "If the scanf format is influenceable by an attacker, it's exploitable." + add_warning(hit) + + +p_dangerous_multi_byte = re.compile(r'^\s*sizeof\s*(\(\s*)?[A-Za-z_$0-9]+' + + r'\s*(\)\s*)?(-\s*1\s*)?$') +p_safe_multi_byte = re.compile(r'^\s*sizeof\s*(\(\s*)?[A-Za-z_$0-9]+\s*(\)\s*)?' + + r'/\s*sizeof\s*\(\s*?[A-Za-z_$0-9]+\s*' + + r'\[\s*0\s*\]\)\s*(-\s*1\s*)?$') + +def c_multi_byte_to_wide_char(hit): + # Unfortunately, this doesn't detect bad calls when it's a #define or constant + # set by a sizeof(), but trying to do so would create FAR too many false positives. + if len(hit.parameters)-1 >= 6: + num_chars_to_copy=hit.parameters[6] + if p_dangerous_multi_byte.search(num_chars_to_copy): + hit.level = 5 + hit.note = ("Risk is high, it appears that the size is given as bytes, but the " + + "function requires size as characters.") + elif p_safe_multi_byte.search(num_chars_to_copy): + # This isn't really risk-free, since it might not be the destination, or the + # destination might be a character array (if it's a char pointer, the pattern + # is actually quite dangerous, but programmers are unlikely to make that error). + hit.level = 1 + hit.note = "Risk is very low, the length appears to be in characters not bytes." + add_warning(hit) + +p_null_text = re.compile(r'^ *(NULL|0|0x0) *$') + +def c_hit_if_null(hit): + null_position = hit.check_for_null + if null_position <= len(hit.parameters)-1: + null_text=hit.parameters[null_position] + if p_null_text.search(null_text): + add_warning(hit) + else: + return + add_warning(hit) # If insufficient # of parameters. + +p_static_array = re.compile(r'^[A-Za-z_]+\s+[A-Za-z0-9_$,\s\*()]+\[[^]]') + +def c_static_array(hit): + # This is cheating, but it does the job for most real code. + # In some cases it will match something that it shouldn't. + # We don't match ALL arrays, just those of certain types (e.g., char). + # In theory, any array can overflow, but in practice it seems that + # certain types are far more prone to problems, so we just report those. + if p_static_array.search(hit.lookahead): + add_warning(hit) # Found a static array, warn about it. + +def normal(hit): + add_warning(hit) + + +# "c_ruleset": the rules for identifying "hits" in C (potential warnings). +# It's a dictionary, where the key is the function name causing the hit, +# and the value is a tuple with the following format: +# (hook, level, warning, suggestion, category, {other}) +# See the definition for class "Hit". +# The key can have multiple values separated with "|". + +c_ruleset = { + "strcpy" : + (c_buffer, 4, + "Does not check for buffer overflows when copying to destination", + "Consider using strncpy or strlcpy (warning, strncpy is easily misused)", + "buffer", "", {}), + "lstrcpy|wcscpy|_tcscpy|_mbscpy" : + (c_buffer, 4, + "Does not check for buffer overflows when copying to destination", + "Consider using a function version that stops copying at the end of the buffer", + "buffer", "", {}), + "memcpy|CopyMemory|bcopy" : + (normal, 2, # I've found this to have a lower risk in practice. + "Does not check for buffer overflows when copying to destination", + "Make sure destination can always hold the source data", + "buffer", "", {}), + "strcat" : + (c_buffer, 4, + "Does not check for buffer overflows when concatenating to destination", + "Consider using strncat or strlcat (warning, strncat is easily misused)", + "buffer", "", {}), + "lstrcat|wcscat|_tcscat|_mbscat" : + (c_buffer, 4, + "Does not check for buffer overflows when concatenating to destination", + "", + "buffer", "", {}), + "strncpy" : + (c_buffer, + 1, # Low risk level, because this is often used correctly when FIXING security + # problems, and raising it to a higher risk level would cause many false positives. + "Easily used incorrectly; doesn't always \\0-terminate or " + + "check for invalid pointers", + "", + "buffer", "", {}), + "lstrcpyn|wcsncpy|_tcsncpy|_mbsnbcpy" : + (c_buffer, + 1, # Low risk level, because this is often used correctly when FIXING security + # problems, and raising it to a higher risk levle would cause many false positives. + "Easily used incorrectly; doesn't always \\0-terminate or " + + "check for invalid pointers", + "", + "buffer", "", {}), + "strncat" : + (c_strncat, + 1, # Low risk level, because this is often used correctly when + # FIXING security problems, and raising it to a + # higher risk level would cause many false positives. + "Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add)", + "Consider strlcat or automatically resizing strings", + "buffer", "", {}), + "lstrcatn|wcsncat|_tcsncat|_mbsnbcat" : + (c_strncat, + 1, # Low risk level, because this is often used correctly when FIXING security + # problems, and raising it to a higher risk level would cause many false positives. + "Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add)", + "Consider strlcat or automatically resizing strings", + "buffer", "", {}), + "strccpy|strcadd": + (normal, 1, + "Subject to buffer overflow if buffer is not as big as claimed", + "Ensure that destination buffer is sufficiently large", + "buffer", "", {}), + "char|TCHAR|wchar_t": # This isn't really a function call, but it works. + (c_static_array, 2, + "Statically-sized arrays can be overflowed", + ("Perform bounds checking, use functions that limit length, " + + "or ensure that the size is larger than the maximum possible length"), + "buffer", "", {'extract_lookahead' : 1}), + + "gets|_getts": + (normal, 5, "Does not check for buffer overflows", + "Use fgets() instead", "buffer", "", {'input' : 1}), + + # The "sprintf" hook will raise "format" issues instead if appropriate: + "sprintf|vsprintf|swprintf|vswprintf|_stprintf|_vstprintf": + (c_sprintf, 4, + "Does not check for buffer overflows", + "Use snprintf or vsnprintf", + "buffer", "", {}), + + # TODO: Add "wide character" versions of these functions. + "printf|vprintf|vwprintf|vfwprintf|_vtprintf": + (c_printf, 4, + "If format strings can be influenced by an attacker, they can be exploited", + "Use a constant for the format specification", + "format", "", {}), + + "fprintf|vfprintf|_ftprintf|_vftprintf": + (c_printf, 4, + "If format strings can be influenced by an attacker, they can be exploited", + "Use a constant for the format specification", + "format", "", { 'format_position' : 2}), + + # The "syslog" hook will raise "format" issues. + "syslog": + (c_printf, 4, + "If syslog's format strings can be influenced by an attacker, " + + "they can be exploited", + "Use a constant format string for syslog", + "format", "", { 'format_position' : 2} ), + + "snprintf|vsnprintf|_snprintf|_sntprintf|_vsntprintf": + (c_printf, 4, + "If format strings can be influenced by an attacker, they can be " + + "exploited, and note that sprintf variations do not always \\0-terminate", + "Use a constant for the format specification", + "format", "", { 'format_position' : 3}), + + "scanf|vscanf|wscanf|_tscanf": + (c_scanf, 4, + "The scanf() family's %s operation, without a limit specification, " + + "permits buffer overflows", + "Specify a limit to %s, or use a different input function", + "buffer", "", {'input' : 1}), + + "fscanf|sscanf|vsscanf|vfscanf|_ftscanf": + (c_scanf, 4, + "The scanf() family's %s operation, without a limit specification, " + "permits buffer overflows", + "Specify a limit to %s, or use a different input function", + "buffer", "", {'input' : 1, 'format_position' : 2}), + + "strlen|wcslen|_tcslen|_mbslen" : + (normal, + 1, # Often this isn't really a risk, and even when, it usually at worst causes + # program crash (and nothing worse). + "Does not handle strings that are not \\0-terminated (it could cause a crash " + + "if unprotected)", + "", + "buffer", "", {}), + + "MultiByteToWideChar" : # Windows + (c_multi_byte_to_wide_char, + 2, # Only the default - this will be changed in many cases. + "Requires maximum length in CHARACTERS, not bytes", + "", + "buffer", "", {}), + + "streadd|strecpy": + (normal, 4, + "This function does not protect against buffer overflows", + "Ensure the destination has 4 times the size of the source, to leave room for expansion", + "buffer", "dangers-c", {}), + + "strtrns": + (normal, 3, + "This function does not protect against buffer overflows", + "Ensure that destination is at least as long as the source", + "buffer", "dangers-c", {}), + + "realpath": + (normal, 3, + "This function does not protect against buffer overflows, " + + "and some implementations can overflow internally", + "Ensure that the destination buffer is at least of size MAXPATHLEN, and" + + "to protect against implementation problems, the input argument should also " + + "be checked to ensure it is no larger than MAXPATHLEN", + "buffer", "dangers-c", {}), + + "getopt|getopt_long": + (normal, 3, + "Some older implementations do not protect against internal buffer overflows ", + "Check implementation on installation, or limit the size of all string inputs", + "buffer", "dangers-c", {'input' : 1}), + + "getpass": + (normal, 3, + "Some implementations may overflow buffers", + "", + "buffer", "dangers-c", {'input' : 1}), + + "getwd": + (normal, 3, + "This does not protect against buffer overflows " + "by itself, so use with caution", + "Use getcwd instead", + "buffer", "dangers-c", {'input' : 1}), + + # fread not included here; in practice I think it's rare to mistake it. + "getchar|fgetc|getc|read|_gettc": + (normal, 1, + "Check buffer boundaries if used in a loop", # loops may be via recursion, too. + "", + "buffer", "dangers-c", {'input' : 1}), + + "access": # ???: TODO: analyze TOCTOU more carefully. + (normal, 4, + "This usually indicates a security flaw. If an " + + "attacker can change anything along the path between the " + + "call to access() and the file's actual use (e.g., by moving " + + "files), the attacker can exploit the race condition", + "Set up the correct permissions (e.g., using setuid()) and " + + "try to open the file directly", + "race", + "avoid-race#atomic-filesystem", {}), + "chown": + (normal, 5, + "This accepts filename arguments; if an attacker " + + "can move those files, a race condition results. ", + "Use fchown( ) instead", + "race", "", {}), + "chgrp": + (normal, 5, + "This accepts filename arguments; if an attacker " + + "can move those files, a race condition results. ", + "Use fchgrp( ) instead", + "race", "", {}), + "chmod": + (normal, 5, + "This accepts filename arguments; if an attacker " + + "can move those files, a race condition results. ", + "Use fchmod( ) instead", + "race", "", {}), + "vfork": + (normal, 2, + "On some old systems, vfork() permits race conditions, and it's " + + "very difficult to use correctly", + "Use fork() instead", + "race", "", {}), + "readlink": + (normal, 5, + "This accepts filename arguments; if an attacker " + + "can move those files or change the link content, " + + "a race condition results. Also, it does not terminate with ASCII NUL", + # This is often just a bad idea, and it's hard to suggest a + # simple alternative: + "Reconsider approach", + "race", "", {'input' : 1}), + + "tmpfile": + (normal, 2, + "Function tmpfile() has a security flaw on some systems (e.g., older System V systems)", + "", + "tmpfile", "", {}), + "tmpnam|tempnam": + (normal, 3, + "Temporary file race condition", + "", + "tmpfile", "avoid-race", {}), + + # TODO: Detect GNOME approach to mktemp and ignore it. + "mktemp": + (normal, 4, + "Temporary file race condition", + "", + "tmpfile", "avoid-race", {}), + + "mkstemp": + (normal, 2, + "Potential for temporary file vulnerability in some circumstances. Some older Unix-like systems create temp files with permission to write by all by default, so be sure to set the umask to override this. Also, some older Unix systems might fail to use O_EXCL when opening the file, so make sure that O_EXCL is used by the library", + "", + "tmpfile", "avoid-race", {}), + + "fopen|open": + (normal, 2, + "Check when opening files - can an attacker redirect it (via symlinks), force the opening of special file type (e.g., device files), move things around to create a race condition, control its ancestors, or change its contents?", + "", + "misc", "", {}), + + "umask": + (normal, 1, + "Ensure that umask is given most restrictive possible setting (e.g., 066 or 077)", + "", + "access", "", {}), + + # Windows. TODO: Detect correct usage approaches and ignore it. + "GetTempFileName": + (normal, 3, + "Temporary file race condition in certain cases " + + "(e.g., if run as SYSTEM in many versions of Windows)", + "", + "tmpfile", "avoid-race", {}), + + # TODO: Need to detect varying levels of danger. + "execl|execlp|execle|execv|execvp|system|popen|WinExec|ShellExecute": + (normal, 4, + "This causes a new program to execute and is difficult to use safely", + "try using a library call that implements the same functionality " + + "if available", + "shell", "", {}), + + # TODO: Need to detect varying levels of danger. + "execl|execlp|execle|execv|execvp|system|popen|WinExec|ShellExecute": + (normal, 4, + "This causes a new program to execute and is difficult to use safely", + "try using a library call that implements the same functionality " + + "if available", + "shell", "", {}), + + # TODO: Be more specific. The biggest problem involves "first" param NULL, + # second param with embedded space. Windows. + "CreateProcessAsUser|CreateProcessWithLogon": + (normal, 3, + "This causes a new process to execute and is difficult to use safely", + "Especially watch out for embedded spaces", + "shell", "", {}), + + # TODO: Be more specific. The biggest problem involves "first" param NULL, + # second param with embedded space. Windows. + "CreateProcess": + (c_hit_if_null, 3, + "This causes a new process to execute and is difficult to use safely", + "Specify the application path in the first argument, NOT as part of the second, " + + "or embedded spaces could allow an attacker to force a different program to run", + "shell", "", {'check_for_null' : 1}), + + # Random values. Don't trigger on "initstate", it's too common a term. + "drand48|erand48|jrand48|lcong48|lrand48|mrand48|nrand48|random|seed48|setstate|srand|strfry|srandom": + (normal, 3, + "This function is not sufficiently random for security-related functions such as key and nonce creation", + "use a more secure technique for acquiring random values", + "random", "", {}), + + "crypt": + (normal, 4, + "Function crypt is a poor one-way hashing algorithm; since it only accepts passwords of 8 " + + "characters or less, and only a two-byte salt, it is excessively vulnerable to " + + "dictionary attacks given today's faster computing equipment", + "Use a different algorithm, such as SHA-1, with a larger non-repeating salt", + "crypto", "", {}), + + # OpenSSL EVP calls to use DES. + "EVP_des_ecb|EVP_des_cbc|EVP_des_cfb|EVP_des_ofb|EVP_desx_cbc": + (normal, 4, + "DES only supports a 56-bit keysize, which is too small given today's computers", + "Use a different patent-free encryption algorithm with a larger keysize, " + + "such as 3DES or AES", + "crypto", "", {}), + + # Other OpenSSL EVP calls to use small keys. + "EVP_rc4_40|EVP_rc2_40_cbc|EVP_rc2_64_cbc": + (normal, 4, + "These keysizes are too small given today's computers", + "Use a different patent-free encryption algorithm with a larger keysize, " + + "such as 3DES or AES", + "crypto", "", {}), + + "chroot": + (normal, 3, + "chroot can be very helpful, but is hard to use correctly", + "Make sure the program immediately chdir(\"/\"), closes file descriptors, " + + "and drops root privileges, and that all necessary files (and no more!) are " + + "in the new root", + "misc", "", {}), + + "getenv|curl_getenv": + (normal, 3, "Environment variables are untrustable input if they can be" + "it returns untrustable input if the environment can be" + + "set by an attacker. It can have any content and length, " + + "and the same variable can be set more than once", + "Check environment variables carefully before using them", + "buffer", "", {'input' : 1}), + + "g_get_home_dir": + (normal, 3, "This function is synonymous with 'getenv(\"HOME\")';" + + "it returns untrustable input if the environment can be" + + "set by an attacker. It can have any content and length, " + + "and the same variable can be set more than once", + "Check environment variables carefully before using them", + "buffer", "", {'input' : 1}), + + "g_get_tmp_dir": + (normal, 3, "This function is synonymous with 'getenv(\"TMP\")';" + + "it returns untrustable input if the environment can be" + + "set by an attacker. It can have any content and length, " + + "and the same variable can be set more than once", + "Check environment variables carefully before using them", + "buffer", "", {'input' : 1}), + + + # These are Windows-unique: + + # TODO: Should have lower risk if the program checks return value. + "RpcImpersonateClient|ImpersonateLoggedOnUser|CoImpersonateClient|" + + "ImpersonateNamedPipeClient|ImpersonateDdeClientWindow|ImpersonateSecurityContext|" + + "SetThreadToken": + (normal, 4, "If this call fails, the program could fail to drop heightened privileges", + "Make sure the return value is checked, and do not continue if a failure is reported", + "access", "", {}), + + "InitializeCriticalSection": + (normal, 3, "Exceptions can be thrown in low-memory situations", + "Use InitializeCriticalSectionAndSpinCount instead", + "misc", "", {}), + + "EnterCriticalSection": + (normal, 3, "On some versions of Windows, exceptions can be thrown in low-memory situations", + "Use InitializeCriticalSectionAndSpinCount instead", + "misc", "", {}), + + "LoadLibrary|LoadLibraryEx": + (normal, 3, "Ensure that the full path to the library is specified, or current directory may be used", + "Use registry entry or GetWindowsDirectory to find library path, if you aren't already", + "misc", "", {'input' : 1}), + + "SetSecurityDescriptorDacl": + (c_hit_if_null, 5, + "Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), " + + "which would even forbid administrator access", + "", + "misc", "", {'check_for_null' : 3}), + + "AddAccessAllowedAce": + (normal, 3, + "This doesn't set the inheritance bits in the access control entry (ACE) header", + "Make sure that you set inheritance by hand if you wish it to inherit", + "misc", "", {}), + + "getlogin": + (normal, 4, + "It's often easy to fool getlogin. Sometimes it does not work at all, because some program messed up the utmp file. Often, it gives only the first 8 characters of the login name. The user currently logged in on the controlling tty of our program need not be the user who started it. Avoid getlogin() for security-related purposes", + "Use getpwuid(geteuid()) and extract the desired information instead", + "misc", "", {}), + + "cuserid": + (normal, 4, + "Exactly what cuserid() does is poorly defined (e.g., some systems use the effective uid, like Linux, while others like System V use the real uid). Thus, you can't trust what it does. It's certainly not portable (The cuserid function was included in the 1988 version of POSIX, but removed from the 1990 version). Also, if passed a non-null parameter, there's a risk of a buffer overflow if the passed-in buffer is not at least L_cuserid characters long", + "Use getpwuid(geteuid()) and extract the desired information instead", + "misc", "", {}), + + "getpw": + (normal, 4, + "This function is dangerous; it may overflow the provided buffer. It extracts data from a 'protected' area, but most systems have many commands to let users modify the protected area, and it's not always clear what their limits are. Best to avoid using this function altogether", + "Use getpwuid() instead", + "buffer", "", {}), + + "getpass": + (normal, 4, + "This function is obsolete and not portable. It was in SUSv2 but removed by POSIX.2. What it does exactly varies considerably between systems, particularly in where its prompt is displayed and where it gets its data (e.g., /dev/tty, stdin, stderr, etc.)", + "Make the specific calls to do exactly what you want. If you continue to use it, or write your own, be sure to zero the password as soon as possible to avoid leaving the cleartext password visible in the process' address space", + "misc", "", {}), + + "gsignal|ssignal": + (normal, 2, + "These functions are considered obsolete on most systems, and very non-poertable (Linux-based systems handle them radically different, basically if gsignal/ssignal were the same as raise/signal respectively, while System V considers them a separate set and obsolete)", + "Switch to raise/signal, or some other signalling approach", + "obsolete", "", {}), + + "memalign": + (normal, 1, + "On some systems (though not Linux-based systems) an attempt to free() results from memalign() may fail. This may, on a few systems, be exploitable. Also note that memalign() may not check that the boundary parameter is correct", + "Use posix_memalign instead (defined in POSIX's 1003.1d). Don't switch to valloc(); it is marked as obsolete in BSD 4.3, as legacy in SUSv2, and is no longer defined in SUSv3. In some cases, malloc()'s alignment may be sufficient", + "free", "", {}), + + "ulimit": + (normal, 1, + "This C routine is considered obsolete (as opposed to the shell command by the same name, which is NOT obsolete)", + "Use getrlimit(2), setrlimit(2), and sysconf(3) instead", + "obsolete", "", {}), + + "usleep": + (normal, 1, + "This C routine is considered obsolete (as opposed to the shell command by the same name). The interaction of this function with SIGALRM and other timer functions such as sleep(), alarm(), setitimer(), and nanosleep() is unspecified", + "Use nanosleep(2) or setitimer(2) instead", + "obsolete", "", {}), + + + # Input functions, useful for -I + "recv|recvfrom|recvmsg|fread|readv": + (normal, 0, "Function accepts input from outside program", + "Make sure input data is filtered, especially if an attacker could manipulate it", + "input", "", {'input' : 1}), + + + # TODO: detect C++'s: cin >> charbuf, where charbuf is a char array; the problem + # is that flawfinder doesn't have type information, and ">>" is safe with + # many other types. + # ("send" and friends aren't todo, because they send out.. not input.) + # TODO: cwd("..") in user's space - TOCTOU vulnerability + # TODO: There are many more rules to add, esp. for TOCTOU. + } + +template_ruleset = { + # This is a template for adding new entries (the key is impossible): + "9": + (normal, 2, + "", + "", + "tmpfile", "", {}), + } + + +def find_column(text, position): + "Find column number inside line." + newline = string.rfind(text, "\n", 0, position) + if newline == -1: + return position + 1 + else: + return position - newline + +def get_context(text, position): + "Get surrounding text line starting from text[position]" + linestart = string.rfind(text, "\n", 0, position+1) + 1 + lineend = string.find(text, "\n", position, len(text)) + if lineend == -1: lineend = len(text) + return text[linestart:lineend] + +def c_valid_match(text, position): + # Determine if this is a valid match, or a false positive. + # If false positive controls aren't on, always declare it's a match: + i = position + while i < len(text): + c = text[i] + if c == '(': return 1 + elif c in string.whitespace: i = i + 1 + else: + if falsepositive: return 0 # No following "(", presume invalid. + if c in "=+-": + # This is very unlikely to be a function use. If c is '=', + # the name is followed by an assignment or is-equal operation. + # Since the names of library functions are really unlikely to be + # followed by an assignment statement or 'is-equal' test, + # while this IS common for variable names, let's declare it invalid. + # It's possible that this is a variable function pointer, pointing + # to the real library function, but that's really improbable. + # If c is "+" or "-", we have a + or - operation. + # In theory "-" could be used for a function pointer difference + # computation, but this is extremely improbable. + # More likely: this is a variable in a computation, so drop it. + return 0 + return 1 + return 0 # Never found anything other than "(" and whitespace. + +def process_directive(): + "Given a directive, process it." + global ignoreline, num_ignored_hits + # TODO: Currently this is just a stub routine that simply removes + # hits from the current line, if any, and sets a flag if not. + # Thus, any directive is considered the "ignore" directive. + # Currently that's okay because we don't have any other directives yet. + if never_ignore: return + hitfound = 0 + # Iterate backwards over hits, to be careful about the destructive iterator + for i in xrange(len(hitlist)-1, -1, -1): + if hitlist[i].line == linenumber: + del hitlist[i] # DESTROY - this is a DESTRUCTIVE iterator. + hitfound = 1 # Don't break, because there may be more than one. + num_ignored_hits = num_ignored_hits + 1 + if not hitfound: + ignoreline = linenumber + 1 # Nothing found - ignore next line. + +# Characters that can be in a string. +# 0x4, 4.4e4, etc. +numberset=string.hexdigits+"_x.Ee" + +# Patterns for various circumstances: +p_include = re.compile( r'#\s*include\s+(<.*?>|".*?")' ) +p_digits = re.compile( r'[0-9]' ) +p_alphaunder = re.compile( r'[A-Za-z_]' ) # Alpha chars and underline. +# A "word" in C. Note that "$" is permitted -- it's not permitted by the +# C standard in identifiers, but gcc supports it as an extension. +p_c_word = re.compile( r'[A-Za-z_][A-Za-z_0-9$]*' ) +# We'll recognize ITS4 and RATS ignore directives, as well as our own, +# for compatibility's sake: +p_directive = re.compile( r'(?i)\s*(ITS4|Flawfinder|RATS):\s*([^\*]*)' ) + +max_lookahead=500 # Lookahead limit for c_static_array. + +def process_c_file(f): + global filename, linenumber, ignoreline, sumlines, num_links_skipped + global sloc + filename=f + linenumber = 1 + ignoreline = -1 + + incomment = 0 + instring = 0 + linebegin = 1 + codeinline = 0 # 1 when we see some code (so increment sloc at newline) + + if f == "-": + input = sys.stdin + else: + # This should never happen. + if ((not allowlink) and os.path.islink(f)): + print "BUG! Somehow got a symlink in process_c_file!" + num_links_skipped = num_links_skipped + 1 + return + input = open(f, "r") + + # Read ENTIRE file into memory. Use readlines() to convert \n if necessary. + # This turns out to be very fast in Python, even on large files, and it + # eliminates lots of range checking later, making the result faster. + # We're examining source files, and today, it would be EXTREMELY bad practice + # to create source files larger than main memory space. + # Better to load it all in, and get the increased speed and reduced + # development time that results. + + if not quiet: + if output_format: + print "Examining", h(f), "
    " + else: + print "Examining", f + sys.stdout.flush() + + text = string.join(input.readlines(),"") + + i = 0 + while i < len(text): + # This is a trivial tokenizer that just tries to find "words", which + # match [A-Za-z_][A-Za-z0-9_]*. It skips comments & strings. + # It also skips "#include <...>", which must be handled specially + # because "<" and ">" aren't usually delimiters. + # It doesn't bother to tokenize anything else, since it's not used. + # The following is a state machine with 3 states: incomment, instring, + # and "normal", and a separate state "linebegin" if at BOL. + c = text[i] + if linebegin: # If at beginning of line, see if #include is there. + linebegin = 0 + if c == "#": codeinline = 1 # A directive, count as code. + m = p_include.match(text,i) + if m: # Found #include, skip it. Otherwise: #include + i = m.end(0) + continue + if c == "\n": + linenumber = linenumber + 1 + sumlines = sumlines + 1 + linebegin = 1 + if codeinline: sloc = sloc + 1 + codeinline = 0 + i = i +1 + continue + i = i + 1 # From here on, text[i] points to next character. + # Skip whitespace: + if (c == " ") or (c == "\t") or (c == "\v") or (c == "\f"): continue + if i < len(text): nextc = text[i] + else: nextc = '' + if incomment: + if c=='*' and nextc=='/': + i = i + 1 + incomment = 0 + elif instring: + if c == '\\': i = i + 1 + elif c == '"' and instring == 1: instring = 0 + elif c == "'" and instring == 2: instring = 0 + else: + if c=='/' and nextc=='*': + m = p_directive.match(text, i+1) # Is there a directive here? + if m: + process_directive() + i = i + 1 + incomment = 1 + elif c=='/' and nextc=='/': # "//" comments - skip to EOL. + m = p_directive.match(text, i+1) # Is there a directive here? + if m: + process_directive() + while i" + if list_rules: + display_ruleset(c_ruleset) + sys.exit(0) + + +# Show the header, but only if it hasn't been shown yet. +def display_header(): + global displayed_header + if not showheading: return + if not displayed_header: + if output_format: + print ('') + print "" + print "" + print '' + print "Flawfinder Results" + print '' + print '' + print "" + print "" + print "

    Flawfinder Results

    " + print "Here are the security scan results from" + print 'Flawfinder version %s,' % version + print '(C) 2001-2004 David A. Wheeler.' + else: + print "Flawfinder version %s, (C) 2001-2004 David A. Wheeler." % version + displayed_header = 1 + + +c_extensions = { '.c' : 1, '.h' : 1, + '.ec': 1, '.ecp': 1, # Informix embedded C. + '.pgc': 1, # Postgres embedded C. + '.C': 1, '.cpp': 1, '.CPP': 1, '.cxx': 1, '.cc': 1, '.CC' : 1, # C++. + '.pcc': 1, # Oracle C++ + '.hpp': 1, '.H' : 1, # .h - usually C++. + } + + +def maybe_process_file(f): + # process f, but only if (1) it's a directory (so we recurse), or + # (2) it's source code in a language we can handle. + # Currently, for files that means only C/C++, and we check if the filename + # has a known C/C++ filename extension. If it doesn't, we ignore the file. + # We accept symlinks only if allowlink is true. + global num_links_skipped + if os.path.isdir(f): + if (not allowlink) and os.path.islink(f): + if not quiet: print "Warning: skipping symbolic link directory", h(f) + num_links_skipped = num_links_skipped + 1 + return + for file in os.listdir(f): + maybe_process_file(os.path.join(f, file)) + # Now we will FIRST check if the file appears to be a C/C++ file, and + # THEN check if it's a regular file or symlink. This is more complicated, + # but I do it this way so that there won't be a lot of pointless + # warnings about skipping files we wouldn't have used anyway. + dotposition = string.rfind(f, ".") + if dotposition > 1: + extension = f[dotposition:] + if c_extensions.has_key(extension): + # Its name appears to be a C/C++ source code file. + if (not allowlink) and os.path.islink(f): + if not quiet: print "Warning: skipping symbolic link file", h(f) + num_links_skipped = num_links_skipped + 1 + elif not os.path.isfile(f): + # Skip anything not a normal file. This is so that + # device files, etc. won't cause trouble. + if not quiet: print "Warning: skipping non-regular file", h(f) + else: + process_c_file(f) + + +def process_file_args(files): + # Process the list of "files", some of which may be directories, + # which were given on the command line. + # This is handled differently than anything not found on the command line + # (i.e. through recursing into a directory) because flawfinder + # ALWAYS processes normal files given on the command line. + # This is done to give users control over what's processed; + # if a user really, really wants to analyze a file, name it! + # If user wants to process "this directory and down", just say ".". + # We handle symlinks specially, handle normal files and directories, + # and skip the rest to prevent security problems. "-" is stdin. + global num_links_skipped + for f in files: + if (not allowlink) and os.path.islink(f): + if not quiet: print "Warning: skipping symbolic link", h(f) + num_links_skipped = num_links_skipped + 1 + elif os.path.isfile(f) or f == "-": + # If on the command line, FORCE processing of it. + # Currently, we only process C/C++. + process_c_file(f) + elif os.path.isdir(f): + # At one time flawfinder used os.path.walk, but that Python + # built-in doesn't give us enough control over symbolic links. + # So, we'll walk the filesystem hierarchy ourselves: + maybe_process_file(f) + else: + if not quiet: print "Warning: skipping non-regular file", h(f) + +def usage(): + print """ +flawfinder [--help] [--context] [-c] [--columns | -C] [--html] + [--dataonly | -D] + [--minlevel=X | -m X] + [--immediate] [-i] [--inputs | -I] [--neverignore | -n] + [--quiet | -Q] [--singleline | -S ] + [--loadhitlist=F ] [ --savehitlist=F ] [ --diffhitlist=F ] + [--listrules] + [--] [ source code file or source root directory ]+ + + --help Show this usage help + + --allowlink + Allow symbolic links. + + --context + -c Show context (the line having the "hit"/potential flaw) + + --columns Show the column number (as well as the file name and + line number) of each hit; this is shown after the line number + by adding a colon and the column number in the line (the first + character in a line is column number 1). + + --html Display as HTML output. + + -m X + --minlevel=X + Set minimum risk level to X for inclusion in hitlist. This + can be from 0 (``no risk'') to 5 (``maximum risk''); the + default is 1. + + -S + --singleline Single-line output. + + --neverignore + -n Never ignore security issues, even if they have an ``ignore'' + directive in a comment. + + --immediate + -i Immediately display hits (don't just wait until the end). + + --inputs Show only functions that obtain data from outside the program; + -I this also sets minlevel to 0. + + --nolink Skip symbolic links (ignored). + + --omittime Omit time to run. + + --Q + --quiet Don't display status information (i.e., which files are being + examined) while the analysis is going on. + + --D + --dataonly Don't display the headers and footers of the analysis; + use this along with --quiet to get just the results. + + --listrules List the rules in the ruleset (rule database). + + --loadhitlist=F + Load hits from F instead of analyzing source programs. + + --savehitlist=F + Save all hits (the "hitlist") to F. + + --diffhitlist=F + Show only hits (loaded or analyzed) not in F. + + + For more information, please consult the manpage or available + documentation. +""" + +def process_options(): + global show_context, show_inputs, allowlink, omit_time + global output_format, minimum_level, show_immediately, single_line + global falsepositive + global show_columns, never_ignore, quiet, showheading, list_rules + global loadhitlist, savehitlist, diffhitlist + try: + # Note - as a side-effect, this sets sys.argv[]. + optlist, args = getopt.getopt(sys.argv[1:], "cm:nih?CSDQIF", + ["context", "minlevel=", "immediate", "inputs", "input", + "nolink", "falsepositive", "falsepositives", + "columns", "listrules", "omittime", "allowlink", + "neverignore", "quiet", "dataonly", "html", "singleline", + "loadhitlist=", "savehitlist=", "diffhitlist=", + "version", "help" ]) + for (opt,value) in optlist: + if opt == "--context" or opt == "-c": + show_context = 1 + elif opt == "--columns" or opt == "-C": + show_columns = 1 + elif opt == "--quiet" or opt == "-Q": + quiet = 1 + elif opt == "--dataonly" or opt == "-D": + showheading = 0 + elif opt == "--inputs" or opt == "--input" or opt == "-I": + show_inputs = 1 + minimum_level = 0 + elif opt == "--falsepositive" or opt == "falsepositives" or opt == "-F": + falsepositive = 1 + elif opt == "--nolink": + allowlink = 0 + elif opt == "--omittime": + omit_time = 1 + elif opt == "--allowlink": + allowlink = 1 + elif opt == "--listrules": + list_rules = 1 + elif opt == "--html": + output_format = 1 + single_line = 0 + elif opt == "--minlevel" or opt == "-m": + minimum_level = string.atoi(value) + elif opt == "--singleline" or opt == "-S": + single_line = 1 + elif opt == "--immediate" or opt == "-i": + show_immediately = 1 + elif opt == "-n" or opt == "--neverignore": + never_ignore = 1 + elif opt == "--loadhitlist": + loadhitlist = value + display_header() + if showheading: print "Loading hits from", value + elif opt == "--savehitlist": + savehitlist = value + display_header() + if showheading: print "Saving hitlist to", value + elif opt == "--diffhitlist": + diffhitlist = value + display_header() + if showheading: print "Showing hits not in", value + elif opt == "--version": + print version + sys.exit(0) + elif opt in [ '-h', '-?', '--help' ]: + usage() + sys.exit(0) + # For DOS/Windows, expand filenames; for Unix, DON'T expand them + # (the shell will expand them for us). Some sloppy Python programs + # always call "glob", but that's WRONG -- on Unix-like systems that + # will expand twice. Python doesn't have a clean way to detect + # "has globbing occurred", so this is the best I've found: + if os.name == "windows" or os.name == "nt" or os.name == "dos": + sys.argv[1:] = reduce(operator.add, map(glob.glob, args)) + else: + sys.argv[1:] = args + # In Python 2 the convention is "getopt.GetoptError", but we + # use "getopt.error" here so it's compatible with both + # Python 1.5 and Python 2. + except getopt.error, text: + print "*** getopt error:", text + usage() + sys.exit(1) + + + +def process_files(): + global hitlist + if loadhitlist: + f = open(loadhitlist) + hitlist = pickle.load(f) + else: + files = sys.argv[1:] + if not files: + print "*** No input files" + return None + process_file_args(files) + return 1 + + +def show_final_results(): + global hitlist + count = 0 + count_per_level = {} + count_per_level_and_up = {} + for i in range(0,6): # Initialize count_per_level + count_per_level[i] = 0 + for i in range(0,6): # Initialize count_per_level + count_per_level_and_up[i] = 0 + if show_immediately: # Separate the final results. + print + if showheading: + if output_format: + print "

    Final Results

    " + else: + print "FINAL RESULTS:" + print + hitlist.sort() + # Display results. The HTML format now uses + #
      so that the format differentiates each entry. + # I'm not using
        , because its numbers might be confused with + # the risk levels or line numbers. + if diffhitlist: + diff_file = open(diffhitlist) + diff_hitlist = pickle.load(diff_file) + if output_format: print "
          " + for h in hitlist: + if h not in diff_hitlist: + h.show() + count_per_level[h.level] = count_per_level[h.level] + 1 + count = count + 1 + if output_format: print "
        " + diff_file.close() + if showheading: + if output_format: + print "

        " + if count > 0: + print "Hits not in original histlist =", count + else: + print "No hits found that weren't already in the hitlist." + if output_format: + print "
        " + else: + if output_format: print "

          " + for h in hitlist: + h.show() + count_per_level[h.level] = count_per_level[h.level] + 1 + if output_format: print "
        " + count = len(hitlist) + if showheading: + if output_format: + print "

        " + else: + print + if count > 0: + print "Hits =", count + else: + print "No hits found." + if output_format: + print "
        " + if showheading: + # Compute the amount of time spent, and lines analyzed/second. + # By computing time here, we also include the time for + # producing the list of hits, which is reasonable. + time_analyzing = time.time() - starttime + print "Lines analyzed = %d" % sumlines, + if time_analyzing > 0 and not omit_time: # Avoid divide-by-zero. + print "in %.2f seconds (%d lines/second)" % ( + time_analyzing + 0.5, + (int) (sumlines / time_analyzing + 0.5) ) + else: + print + if output_format: print "
        " + print "Physical Source Lines of Code (SLOC) = %d" % sloc + if output_format: print "
        " + # Output hits@each level. + print "Hits@level =", + for i in range(0,6): + print "[%d] %3d" % (i, count_per_level[i]), + if output_format: + print "
        " + else: + print + # Compute hits at "level x or higher" + print "Hits@level+ =", + for i in range(0,6): + for j in range(i,6): + count_per_level_and_up[i] = count_per_level_and_up[i] + count_per_level[j] + # Display hits at "level x or higher" + for i in range(0,6): + print "[%d+] %3d" % (i, count_per_level_and_up[i]), + if output_format: + print "
        " + else: + print + print "Hits/KSLOC@level+ =", + for i in range(0,6): + print "[%d+] %3g" % (i, count_per_level_and_up[i]*1000.0/sloc), + if output_format: + print "
        " + else: + print + # + if num_links_skipped: + print "Symlinks skipped =", num_links_skipped, "(--allowlink overrides but see doc for security issue)" + if output_format: + print "
        " + if num_ignored_hits > 0: + print "Suppressed hits =", num_ignored_hits, "(use --neverignore to show them)" + if output_format: + print "
        " + print "Minimum risk level = %d" % minimum_level + if output_format: print "
        " + if count > 0: + print "Not every hit is necessarily a security vulnerability." + if output_format: + print "
        " + print "There may be other security vulnerabilities; review your code!" + if output_format: + print "" + print "" + + +def save_if_desired(): + # We'll save entire hitlist, even if only differences displayed. + if savehitlist: + print "Saving hitlist to", savehitlist + f = open(savehitlist, "w") + pickle.dump(hitlist, f) + f.close() + +def flawfind(): + process_options() + display_header() + initialize_ruleset() + if process_files(): + show_final_results() + save_if_desired() + +if __name__ == '__main__': + try: + flawfind() + except KeyboardInterrupt: + print "*** Flawfinder interrupted" + diff --git a/flawfinder.1 b/flawfinder.1 new file mode 100644 index 0000000..2bc548b --- /dev/null +++ b/flawfinder.1 @@ -0,0 +1,737 @@ +'\" +.\" (C) Copyright 2001 David A. Wheeler (dwheeler@dwheeler.com) +.\" +.\" This program is free software; you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published by +.\" the Free Software Foundation; either version 2 of the License, or +.\" (at your option) any later version. +.\" +.\" This program is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public License +.\" along with this program; if not, write to the Free Software +.\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +.\" +.\" +.\" +.\" Man page created 17 May 2001 by David A. Wheeler (dwheeler@dwheeler.com) +.\" +.TH FLAWFINDER 1 "30 May 2004" "Flawfinder" "Flawfinder" +.SH NAME +flawfinder \- find potential security flaws ("hits") in source code +.SH SYNOPSIS +.B flawfinder +.\" Documentation: +.RB [ \-\-help ] +.RB [ \-\-version ] +.\" Selecting Hits: +.RB [ \-\-allowlink ] +.RB [ \-\-inputs | \-I ] +[ \fB\-\-minlevel=\fR\fIX\fR | \fB-m\fR \fIX\fR ] +.RB [ \-\-falsepositive | \-F ] +.RB [ \-\-neverignore | \-n ] +.\" Selecting Output Format: +.RB [ \-\-context | \-c ] +.RB [ \-\-columns | \-C ] +.RB [ \-\-dataonly | \-D ] +.RB [ \-\-html ] +.RB [ \-\-immediate | -i ] +.RB [ \-\-singleline | \-S ] +.RB [ \-\-omittime ] +.RB [ \-\-quiet | \-Q ] +.\" Managing hit list. +[ \fB\-\-loadhitlist=\fR\fIF\fR ] +[ \fB\-\-savehitlist=\fR\fIF\fR ] +[ \fB\-\-diffhitlist=\fR\fIF\fR ] +.RB [ \-\- ] +.I [ source code file or source root directory ]+ +.SH DESCRIPTION +.PP +Flawfinder searches through C/C++ source code looking for +potential security flaws. +To run flawfinder, simply give flawfinder a list of directories or files. +For each directory given, all files that have C/C++ filename extensions +in that directory (and its subdirectories, recursively) will be examined. +Thus, for most projects, simply give flawfinder the name of the source +code's topmost directory (use ``.'' for the current directory), +and flawfinder will examine all of the project's C/C++ source code. +.PP +Flawfinder will produce a list of ``hits'' (potential +security flaws), sorted by risk; the riskiest hits are shown first. +The risk level is shown inside square brackets and +varies from 0, very little risk, to 5, great risk. +This risk level depends not only on the function, but on the values of the +parameters of the function. +For example, constant strings are often less risky than fully variable +strings in many contexts, and in those contexts the hit will have a +lower risk level. +Flawfinder knows about gettext (a common library for internationalized +programs) and will treat constant strings +passed through gettext as though they were constant strings; this reduces +the number of false hits in internationalized programs. +Flawfinder will do the same sort of thing with _T() and _TEXT(), +common Microsoft macros for handling internationalized programs +.\" For more info, see: http://www.rpi.edu/~pudeyo/articles/unicode.html +Flawfinder correctly ignores most text inside comments and strings. +Normally flawfinder shows all hits with a risk level of at least 1, +but you can use the \-\-minlevel option +to show only hits with higher risk levels if you wish. +.PP +Not every hit is actually a security vulnerability, +and not every security vulnerability is necessarily found. +Nevertheless, flawfinder can be an aid in finding and removing +security vulnerabilities. +A common way to use flawfinder is to first +apply flawfinder to a set of source code and examine the +highest-risk items. +Then, use \-\-inputs to examine the input locations, and check to +make sure that only legal and safe input values are +accepted from untrusted users. +.PP +Once you've audited a program, you can mark source code lines that +are actually fine but cause spurious warnings so that flawfinder will +stop complaining about them. +To mark a line so that these warnings are suppressed, +put a specially-formatted comment either on the same +line (after the source code) or all by itself in the previous line. +The comment must have one of the two following formats: +.IP \(bu + // Flawfinder: ignore +.IP \(bu + /* Flawfinder: ignore */ +.PP +Note that, for compatibility's sake, you can replace "Flawfinder:" with +"ITS4:" or "RATS:" in these specially-formatted comments. +Since it's possible that such lines are wrong, you can use the +``\-\-neverignore'' option, which causes flawfinder to never ignore any line +no matter what the comments say. +Thus, responses that would otherwise be ignored would be included +(or, more confusingly, \-\-neverignore ignores the ignores). +This comment syntax is actually a more general syntax for special directives +to flawfinder, but currently only ignoring lines is supported. +.PP +Flawfinder uses an internal database called the ``ruleset''; +the ruleset identifies functions that are common causes of security flaws. +The standard ruleset includes a large number of different potential +problems, including both general issues that can impact any +C/C++ program, as well as a number of specific Unix-like and Windows +functions that are especially problematic. +As noted above, every potential security flaw found in a given source code file +(matching an entry in the ruleset) +is called a ``hit,'' and the set of hits found during any particular +run of the program is called the ``hitlist.'' +Hitlists can be saved (using \-\-savehitlist), reloaded back for redisplay +(using \-\-loadhitlist), and you can show only the hits that are different +from another run (using \-\-diffhitlist). +.PP +Any filename given on the command line will be examined (even if +it doesn't have a usual C/C++ filename extension); thus you can force +flawfinder to examine any specific files you desire. +While searching directories recursively, flawfinder only opens and +examines regular files that have C/C++ filename extensions. +Flawfinder presumes that, files are C/C++ files if they have the extensions +".c", ".h", ".ec", ".ecp", ".pgc", ".C", ".cpp", +".CPP", ".cxx", ".cc", ".CC", ".pcc", ".hpp", or ".H". +The filename ``\-'' means the standard input. +To prevent security problems, +special files (such as device special files and named pipes) are +always skipped, and by default symbolic links are skipped, +.PP +After the list of hits is a brief summary of the results +(use -D to remove this information). +It will show the number of hits, lines analyzed (as reported by wc \-l), +and the physical source lines of code (SLOC) analyzed. +A physical SLOC is a non-blank, non-comment line. +It will then show the number of hits at each level; note that there will +never be a hit at a level lower than minlevel (1 by default). +Thus, "[0] 0 [1] 9" means that at level 0 there were 0 hits reported, +and at level 1 there were 9 hits reported. +It will next show the number of hits at a given level or larger +(so level 3+ has the sum of the number of hits at level 3, 4, and 5). +Thus, an entry of "[0+] 37" shows that at level 0 or higher there were +37 hits (the 0+ entry will always be the same as the "hits" number above). +Hits per KSLOC is next shown; this is each of the "level or higher" +values multiplied by 1000 and divided by the physical SLOC. +If symlinks were skipped, the count of those is reported. +If hits were suppressed (using the "ignore" directive +in source code comments as described above), the number suppressed is reported. +The minimum risk level to be included in the report +is displayed; by default this is 1 (use \-\-minlevel to change this). +The summary ends with important reminders: +Not every hit is necessarily a security vulnerability, and +there may be other security vulnerabilities not reported by the tool. +.PP +Flawfinder intentionally works similarly to another program, ITS4, which is not +fully open source software (as defined in the Open Source Definition) +nor free software (as defined by the Free Software Foundation). +The author of Flawfinder has never seen ITS4's source code. +.SH "BRIEF TUTORIAL" + +Here's a brief example of how flawfinder might be used. +Imagine that you have the C/C++ source code for some program named xyzzy +(which you may or may not have written), and you're +searching for security vulnerabilities (so you can fix them before +customers encounter the vulnerabilities). +For this tutorial, I'll assume that you're using a Unix-like system, +such as Linux, OpenBSD, or MacOS X. + +.PP +If the source code is in a subdirectory named xyzzy, you would probably +start by opening a text window and using flawfinder's default settings, to +analyze the program and report a prioritized list of potential +security vulnerabilities (the ``less'' just makes sure the results +stay on the screen): +.RS +flawfinder xyzzy | less +.RE + +.PP +At this point, you will a large number of entries; +each entry begins with a filename, a colon, a line number, a +risk level in brackets (where 5 is the most risky), a category, +the name of the function, and +a description of why flawfinder thinks the line is a vulnerability. +Flawfinder normally sorts by risk level, showing the riskiest items +first; if you have limited time, it's probably best to start working on +the riskiest items and continue until you run out of time. +If you want to limit the display to risks with only +a certain risk level or higher, use +the \-\-minlevel option. +If you're getting an extraordinary number of false positives because +variable names look like dangerous function names, use the \-F option +to remove reports about them. +If you don't understand the error message, please see documents such as the +.UR "http://www.dwheeler.com/secure-programs" +.I "Writing Secure Programs for Linux and Unix HOWTO" +.UE +at +http://www.dwheeler.com/secure-programs +which provides more information on writing secure programs. + +.PP +Once you identify the problem and understand it, you can fix it. +Occasionally you may want to re-do the analysis, both because the +line numbers will change \fIand\fP to make sure that the new code +doesn't introduce yet a different vulnerability. + +.PP +If you've determined that some line isn't really a problem, and +you're sure of it, you can insert just before or on the offending +line a comment like +.RS + /* Flawfinder: ignore */ +.RE +to keep them from showing up in the output. + +.PP +Once you've done that, you should go back and search for the +program's inputs, to make sure that the program strongly filters +any of its untrusted inputs. +Flawfinder can identify many program inputs by using the \-\-inputs +option, like this: +.RS +flawfinder \-\-inputs xyzzy +.RE + +.PP +Flawfinder can integrate well with text editors and +integrated development environments; see the examples for +more information. + +.PP +Flawfinder includes many other options, including ones to +create HTML versions of the output (useful for prettier displays). +The next section describes those options in more detail. + +.SH OPTIONS + +Flawfinder has a number of options, which can be grouped into options that +control its own documentation, +select which hits to display, +select the output format, +and perform hitlist management. + +.SS "Documentation" + +.TP 12 +.BI \-\-help +.\" Leave -h and -? undocumented... they also invoke help, but it's +.\" easier just to document the single help option. +Show usage (help) information. + +.TP +.BI \-\-version +Shows (just) the version number and exits. + +.SS "Selecting Hits to Display" + +.TP 12 +.BI \-\-allowlink +Allow the use of symbolic links; normally symbolic links are skipped. +Don't use this option if you're analyzing code by others; +attackers could do many things to cause problems for an analysis +with this option enabled. +For example, an attacker +could insert symbolic links to files such as /etc/passwd +(leaking information about the file) or create a circular loop, +which would cause flawfinder to run ``forever''. +Another problem with enabling this option is that +if the same file is referenced multiple times using symbolic links, +it will be analyzed multiple times (and thus reported multiple times). +Note that flawfinder already includes some protection against symbolic links +to special file types such as device file types (e.g., /dev/zero or +C:\\mystuff\\com1). +Note that for flawfinder version 1.01 and before, this was the default. + +.TP +.BI "\-\-inputs" +.TP +.BI \-I +Show only functions that obtain data from outside the program; +this also sets minlevel to 0. + +.TP +\fB\-\-minlevel=\fIX\fR +.TP +.BI -m " X" +Set minimum risk level to X for inclusion in hitlist. +This can be from 0 (``no risk'') to 5 (``maximum risk''); +the default is 1. + +.TP +.BI "\-\-falsepositive" +.TP +.BI \-F +Do not include hits that are likely to be false positives. +Currently, this means that function names are ignored if they're +not followed by "(", and that declarations of character arrays aren't +noted. +Thus, if you have use a variable named "access" everywhere, this will +eliminate references to this ordinary variable. +This isn't the default, because this also increases the likelihood +of missing important hits; in particular, function names in #define +clauses and calls through function pointers will be missed. + +.TP +.BI \-\-neverignore +.TP +.BI -n +Never ignore security issues, even if they have an ``ignore'' directive +in a comment. + + +.SS "Selecting Output Format" + +.TP 12 +.BI \-\-columns +.TP +.BI \-C +Show the column number (as well as the file name and line number) +of each hit; this is shown after the line number by adding a colon +and the column number in the line (the first character in a line is +column number 1). +This is useful for editors that can jump to specific columns, or +for integrating with other tools (such as those to further filter out +false positives). + +.TP +.BI \-\-context +.TP +.BI \-c +Show context, i.e., the line having the "hit"/potential flaw. +By default the line is shown immediately after the warning. + +.TP +.BI "\-\-dataonly" +.TP +.BI \-D +Don't display the header and footer. +Use this along with \-\-quiet to see just the data itself. + +.TP +.BI \-\-html +Format the output as HTML instead of as simple text. + +.TP +.BI "\-\-immediate" +.TP +.BI -i +Immediately display hits (don't just wait until the end). + +.TP +.BI "\-\-singleline" +.TP +.BI -S +Display as single line of text output for each hit. +Useful for interacting with compilation tools. + +.TP +.BI "\-\-omittime" +Omit timing information. +This is useful for regression tests of flawfinder itself, so that +the output doesn't vary depending on how long the analysis takes. + +.TP +.BI "\-\-quiet" +.TP +.BI \-Q +Don't display status information (i.e., which files are being examined) +while the analysis is going on. + + +.SS "Hitlist Management" + +.\" This isn't sorted as usual, because logically saving comes +.\" before loading and differencing. +.TP 12 +\fB\-\-savehitlist=\fR\fIF\fR +Save all resulting hits (the "hitlist") to F. + +.TP +\fB\-\-loadhitlist=\fR\fIF\fR +Load the hitlist from F instead of analyzing source programs. + +.TP +\fB\-\-diffhitlist=\fR\fIF\fR +Show only hits (loaded or analyzed) not in F. +F was presumably created previously using \-\-savehitlist. +If the \-\-loadhitlist option is not provided, this will show the hits in +the analyzed source code files that were not previously stored in F. +If used along with \-\-loadhitlist, this will show the hits in the +loaded hitlist not in F. +The difference algorithm is conservative; +hits are only considered the ``same'' if they have the same +filename, line number, column position, function name, and risk level. + + +.SH EXAMPLES + +Here are various examples of how to invoke flawfinder. +The first examples show various simple command-line options. +Flawfinder is designed to work well with text editors and +integrated development environments, so the next sections +show how to integrate flawfinder into vim and emacs. + +.SS "Simple command-line options" + +.TP 12 +.B "flawfinder /usr/src/linux-2.4.12" +Examine all the C/C++ files in the directory +/usr/src/linux-2.4.12 and all its subdirectories (recursively), +reporting on all hits found. + +.TP +.B "flawfinder \-\-minlevel=4 ." +Examine all the C/C++ files in the current directory +and its subdirectories (recursively); +only report vulnerabilities level 4 and up (the two highest risk levels). + +.TP +.B "flawfinder \-\-inputs mydir" +Examine all the C/C++ files in mydir +and its subdirectories (recursively), and report functions +that take inputs (so that you can ensure that they filter the +inputs appropriately). + +.TP +.B "flawfinder \-\-neverignore mydir" +Examine all the C/C++ files in the directory mydir and its subdirectories, +including even the hits marked for ignoring in the code comments. + +.TP +.B "flawfinder -QD mydir" +Examine mydir and report only the actual results +(removing the header and footer of the output). +This form is useful +if the output will be piped into other tools for further analysis. +The \-C (\-\-columns) and \-S (\-\-singleline) +options can also be useful if you're piping the data +into other tools. + +.TP +.B "flawfinder \-\-quiet \-\-html \-\-context mydir > results.html" +Examine all the C/C++ files in the directory mydir and its subdirectories, +and produce an HTML formatted version of the results. +Source code management systems (such as SourceForge and Savannah) +might use a command like this. + +.TP +.B "flawfinder \-\-quiet \-\-savehitlist saved.hits *.[ch]" +Examine all .c and .h files in the current directory. +Don't report on the status of processing, and save the resulting hitlist +(the set of all hits) in the file saved.hits. + +.TP +.B "flawfinder \-\-diffhitlist saved.hits *.[ch]" +Examine all .c and .h files in the current directory, and show any +hits that weren't already in the file saved.hits. +This can be used to show only the ``new'' vulnerabilities in a +modified program, if saved.hits was created from the +older version of the program being analyzed. + +.SS "Invoking from vim" + +.PP +The text editor +vim includes a "quickfix" mechanism that works well with flawfinder, +so that you can easily view the warning messages and jump to +the relevant source code. +.PP +First, you need to invoke flawfinder to create a list of hits, and +there are two ways to do this. +The first way is to start flawfinder first, and then (using its output) +invoke vim. +The second way is to start (or continue to run) vim, and then invoke +flawfinder (typically from inside vim). +.PP +For the first way, run flawfinder and store its output in some +FLAWFILE (say "flawfile"), +then invoke vim using its -q option, like this: "vim -q flawfile". +The second way (starting flawfinder after starting vim) can be done +a legion of ways. +One is to invoke flawfinder using a shell command, +":!flawfinder-command > FLAWFILE", then follow that with the command +":cf FLAWFILE". +Another way is to store the flawfinder command in your makefile +(as, say, a pseudocommand like "flaw"), and then run +":make flaw". +.PP +In all these cases you need a command for flawfinder to run. +A plausible command, which places each hit in its own line (-S) and +removes headers and footers that would confuse it, is: +.PP +.B "flawfinder \-SQD ." + +.PP +You can now use various editing commands to view the results. +The command ":cn" displays the next hit; ":cN" displays the +previous hit, and ":cr" rewinds back to the first hit. +":copen" will open a window to show the current list of hits, called +the "quickfix window"; ":cclose" will close the quickfix window. +If the buffer in the used window has changed, and the error is in +another file, jumping to the error will fail. +You have to make sure the window contains a buffer which can be abandoned +before trying to jump to a new file, say by saving the file; +this prevents accidental data loss. + +.SS "Invoking from emacs" +The text editor / operating system +emacs includes "grep mode" and "compile mode" mechanisms +that work well with flawfinder, making it easy to +view warning messages, jump to the relevant source code, and fix +any problems you find. +.PP +First, you need to invoke flawfinder to create a list of warning messages. +You can use "grep mode" or "compile mode" to create this list. +Often "grep mode" is more convenient; +it leaves compile mode untouched so you can easily recompile +once you've changed something. +However, if you want to jump to the exact column position of a hit, +compile mode may be more convenient because emacs can use +the column output of flawfinder to directly jump to the right location +without any special configuration. +.PP +To use grep mode, +enter the command "M-x grep" +and then enter the needed flawfinder command. +To use compile mode, enter the command +"M-x compile" and enter the needed flawfinder command. +This is a meta-key command, so you'll need to use the meta key for your +keyboard (this is usually the ESC key). +As with all emacs commands, you'll need to press RETURN after +typing "grep" or "compile". +So on many systems, the grep mode is invoked by typing +ESC x g r e p RETURN. +.PP +You then need to enter a command, removing whatever was there before if +necessary. +A plausible command is: +.PP +.B "flawfinder \-SQDC ." +.PP +This command makes every hit report a single line, +which is much easier for tools to handle. +The quiet and dataonly options remove the other status information not needed +for use inside emacs. +The trailing period means that the current directory and all descendents +are searched for C/C++ code, and analyzed for flaws. +.PP +Once you've invoked flawfinder, you can use emacs to jump around +in its results. +The command C-x \` +(Control-x backtick) +visits the source code location for the next warning message. +C-u C-x \` (control-u control-x backtick) +restarts from the beginning. +You can visit the source for any particular error message by moving +to that hit message in the *compilation* buffer or *grep* buffer +and typing the return key. +(Technical note: in the compilation buffer, this invokes +compile-goto-error). +You can also click the Mouse-2 button on the error message +(when using the mouse you don't need to switch to the *compilation* buffer +first). +.PP +If you want to use grep mode to jump to specific columns of a hit, +you'll need to specially configure emacs to do this. +To do this, modify the emacs variable "grep-regexp-alist". +This variable tells Emacs how to +parse output of a "grep" command, similar to the +variable "compilation-error-regexp-alist" which lists various formats +of compilation error messages. + +.SH SECURITY + +You should always analyze a \fIcopy\fP of the source program being analyzed, +not a directory that can be modified by a developer while flawfinder +is performing the analysis. +This is \fIespecially\fP true if you don't necessily trust a +developer of the program being analyzed. +If an attacker has control over the files while you're analyzing them, +the attacker could move files around or change their contents to +prevent the exposure of a security problem (or create the impression +of a problem where there is none). +If you're worried about malicious programmers you should do this anyway, +because after analysis you'll need to verify that the code eventually run +is the code you analyzed. +Also, do not use the \-\-allowlink option in such cases; +attackers could create malicious symbolic links to files outside of their +source code area (such as /etc/passwd). +.PP +Source code management systems (like SourceForge and Savannah) +definitely fall into this category; if you're maintaining one of those +systems, first copy or extract the files into a separate directory +(that can't be controlled by attackers) +before running flawfinder or any other code analysis tool. +.PP +Note that flawfinder only opens regular files, directories, and +(if requested) symbolic links; it will never open other kinds of files, +even if a symbolic link is made to them. +This counters attackers who insert unusual file types into the +source code. +However, this only works if the filesystem being analyzed can't +be modified by an attacker during the analysis, as recommended above. +This protection also doesn't work on Cygwin platforms, unfortunately. +.PP +Cygwin systems (Unix emulation on top of Windows) +have an additional problem if flawfinder is used to analyze +programs the analyzer cannot trust +due to a design flaw in Windows (that it inherits from MS-DOS). +On Windows and MS-DOS, certain filenames (e.g., ``com1'') are +automatically treated by the operating system as the names of peripherals, +and this is true even when a full pathname is given. +Yes, Windows and MS-DOS really are designed this badly. +Flawfinder deals with this by checking what a filesystem object is, +and then only opening directories and regular files +(and symlinks if enabled). +Unfortunately, this doesn't work on Cygwin; on at least some versions +of Cygwin on some versions of Windows, +merely trying to determine if a file is a device type +can cause the program to hang. +A workaround is to delete or rename any filenames that are interpreted +as device names before performing the analysis. +These so-called ``reserved names'' are CON, PRN, AUX, CLOCK$, NUL, +COM1-COM9, and LPT1-LPT9, optionally followed by an extension +(e.g., ``com1.txt''), in any directory, and in any case +(Windows is case-insensitive). +.\" See 'Writing Secure Code' by Howard and LeBlanc, pg. 223 + + +.SH BUGS + +Flawfinder is currently limited to C/C++. +It's designed so that adding support for other languages should be easy. +.PP +Flawfinder can be fooled by user-defined functions or method names that +happen to be the same as those defined as ``hits'' in its database, +and will often trigger on definitions (as well as uses) of functions +with the same name. +This is because flawfinder is based on text pattern matching, which is +part of its fundamental design and not easily changed. +This isn't as much of a problem for C code, but it can be more of a problem +for some C++ code which heavily uses classes and namespaces. +On the positive side, flawfinder doesn't get confused by many +complicated preprocessor sequences that other tools sometimes choke on. +Also, having the same name as a common library routine name can +indicate that the developer is simply rewriting a common library routine, +say for portability's sake. +Thus, there are reasonable odds that +these rewritten routines will be vulnerable to the same kinds of misuse. +The \-\-falsepositive option can help somewhat. +If this is a serious problem, feel free to modify the program, or process +the flawfinder output through other tools to remove the false positives. +.PP +Preprocessor commands embedded in the middle of a parameter list +of a call can cause problems in parsing, in particular, if a string +is opened and then closed multiple times using an #ifdef .. #else +construct, flawfinder gets confused. +Such constructs are bad style, and will confuse many other tools too. +If you must analyze such files, rewrite those lines. +Thankfully, these are quite rare. +.PP +The routine to detect statically defined character arrays uses +simple text matching; some complicated expresions can cause it to +trigger or not trigger unexpectedly. +.PP +Flawfinder looks for specific patterns known to be common mistakes. +Flawfinder (or any tool like it) is not a good tool for finding intentionally +malicious code (e.g., Trojan horses); malicious programmers can easily +insert code that would not be detected by this kind of tool. +.PP +Flawfinder looks for specific patterns known to be common mistakes +in application code. +Thus, it is likely to be less effective +analyzing programs that aren't application-layer code +(e.g., kernel code or self-hosting code). +The techniques may still be useful; feel free to replace the database +if your situation is significantly different from normal. +.PP +Flawfinder's output format (filename:linenumber, followed optionally +by a :columnnumber) can be misunderstood if any source files have +very weird filenames. +Filenames embedding a newline/linefeed character will cause odd breaks, +and filenames including colon (:) are likely to be misunderstood. +This is especially important if flawfinder's output is being used +by other tools, such as filters or text editors. +If you're looking at new code, examine the files for such characters. +It's incredibly unwise to have such filenames anyway; +many tools can't handle such filenames at all. +Newline and linefeed are often used as internal data delimeters. +The colon is often used as special characters in filesystems: +MacOS uses it as a directory separator, Windows/MS-DOS uses it +to identify drive letters, Windows/MS-DOS inconsistently uses it +to identify special devices like CON:, and applications on many platforms +use the colon to identify URIs/URLs. +Filenames including spaces and/or tabs don't cause problems for flawfinder, +though note that other tools might have problems with them. +.PP +In general, flawfinder attempts to err on the side of caution; it tends +to report hits, so that they can be examined further, instead of silently +ignoring them. +Thus, flawfinder prefers to have false positives (reports that +turn out to not be problems) rather than false negatives +(failure to report on a security vulnerability). +But this is a generality; flawfinder uses simplistic heuristics and +simply can't get everything "right". +.PP +Security vulnerabilities might not be identified as such by flawfinder, +and conversely, some hits aren't really security vulnerabilities. +This is true for all static security scanners, especially those like +flawfinder that use a simple pattern-based approach to identifying problems. +Still, it can serve as a useful aid for humans, helping to identify +useful places to examine further, and that's the point of this tool. + +.SH "SEE ALSO" +See the flawfinder website at http://www.dwheeler.com/flawfinder. +You should also see the +.I "Secure Programming for Unix and Linux HOWTO" +at +http://www.dwheeler.com/secure-programs. + +.SH AUTHOR +David A. Wheeler (dwheeler@dwheeler.com). + + diff --git a/flawfinder.1.gz b/flawfinder.1.gz new file mode 100644 index 0000000..c50e12c Binary files /dev/null and b/flawfinder.1.gz differ diff --git a/flawfinder.pdf b/flawfinder.pdf new file mode 100644 index 0000000..5aaaf4d Binary files /dev/null and b/flawfinder.pdf differ diff --git a/flawfinder.ps b/flawfinder.ps new file mode 100644 index 0000000..4bf02da --- /dev/null +++ b/flawfinder.ps @@ -0,0 +1,1464 @@ +%!PS-Adobe-3.0 +%%Creator: groff version 1.18.1 +%%CreationDate: Sat Jun 5 00:37:01 2004 +%%DocumentNeededResources: font Times-Roman +%%+ font Times-Bold +%%+ font Times-Italic +%%DocumentSuppliedResources: procset grops 1.18 1 +%%Pages: 8 +%%PageOrder: Ascend +%%Orientation: Portrait +%%EndComments +%%BeginProlog +%%BeginResource: procset grops 1.18 1 +/setpacking where{ +pop +currentpacking +true setpacking +}if +/grops 120 dict dup begin +/SC 32 def +/A/show load def +/B{0 SC 3 -1 roll widthshow}bind def +/C{0 exch ashow}bind def +/D{0 exch 0 SC 5 2 roll awidthshow}bind def +/E{0 rmoveto show}bind def +/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def +/G{0 rmoveto 0 exch ashow}bind def +/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/I{0 exch rmoveto show}bind def +/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def +/K{0 exch rmoveto 0 exch ashow}bind def +/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/M{rmoveto show}bind def +/N{rmoveto 0 SC 3 -1 roll widthshow}bind def +/O{rmoveto 0 exch ashow}bind def +/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/Q{moveto show}bind def +/R{moveto 0 SC 3 -1 roll widthshow}bind def +/S{moveto 0 exch ashow}bind def +/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/SF{ +findfont exch +[exch dup 0 exch 0 exch neg 0 0]makefont +dup setfont +[exch/setfont cvx]cvx bind def +}bind def +/MF{ +findfont +[5 2 roll +0 3 1 roll +neg 0 0]makefont +dup setfont +[exch/setfont cvx]cvx bind def +}bind def +/level0 0 def +/RES 0 def +/PL 0 def +/LS 0 def +/MANUAL{ +statusdict begin/manualfeed true store end +}bind def +/PLG{ +gsave newpath clippath pathbbox grestore +exch pop add exch pop +}bind def +/BP{ +/level0 save def +1 setlinecap +1 setlinejoin +72 RES div dup scale +LS{ +90 rotate +}{ +0 PL translate +}ifelse +1 -1 scale +}bind def +/EP{ +level0 restore +showpage +}bind def +/DA{ +newpath arcn stroke +}bind def +/SN{ +transform +.25 sub exch .25 sub exch +round .25 add exch round .25 add exch +itransform +}bind def +/DL{ +SN +moveto +SN +lineto stroke +}bind def +/DC{ +newpath 0 360 arc closepath +}bind def +/TM matrix def +/DE{ +TM currentmatrix pop +translate scale newpath 0 0 .5 0 360 arc closepath +TM setmatrix +}bind def +/RC/rcurveto load def +/RL/rlineto load def +/ST/stroke load def +/MT/moveto load def +/CL/closepath load def +/Fr{ +setrgbcolor fill +}bind def +/Fk{ +setcmykcolor fill +}bind def +/Fg{ +setgray fill +}bind def +/FL/fill load def +/LW/setlinewidth load def +/Cr/setrgbcolor load def +/Ck/setcmykcolor load def +/Cg/setgray load def +/RE{ +findfont +dup maxlength 1 index/FontName known not{1 add}if dict begin +{ +1 index/FID ne{def}{pop pop}ifelse +}forall +/Encoding exch def +dup/FontName exch def +currentdict end definefont pop +}bind def +/DEFS 0 def +/EBEGIN{ +moveto +DEFS begin +}bind def +/EEND/end load def +/CNT 0 def +/level1 0 def +/PBEGIN{ +/level1 save def +translate +div 3 1 roll div exch scale +neg exch neg exch translate +0 setgray +0 setlinecap +1 setlinewidth +0 setlinejoin +10 setmiterlimit +[]0 setdash +/setstrokeadjust where{ +pop +false setstrokeadjust +}if +/setoverprint where{ +pop +false setoverprint +}if +newpath +/CNT countdictstack def +userdict begin +/showpage{}def +}bind def +/PEND{ +clear +countdictstack CNT sub{end}repeat +level1 restore +}bind def +end def +/setpacking where{ +pop +setpacking +}if +%%EndResource +%%IncludeResource: font Times-Roman +%%IncludeResource: font Times-Bold +%%IncludeResource: font Times-Italic +grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 +def/PL 841.89 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron +/Zcaron/scaron/zcaron/Ydieresis/trademark/quotesingle/Euro/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/space/exclam/quotedbl/numbersign/dollar/percent +/ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen +/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon +/semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O +/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/circumflex +/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y +/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase/guillemotleft +/guillemotright/bullet/florin/fraction/perthousand/dagger/daggerdbl +/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut +/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash +/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen +/brokenbar/section/dieresis/copyright/ordfeminine/guilsinglleft +/logicalnot/minus/registered/macron/degree/plusminus/twosuperior +/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior +/ordmasculine/guilsinglright/onequarter/onehalf/threequarters +/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE +/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex +/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis +/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn +/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla +/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis +/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash +/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]def +/Times-Italic@0 ENC0/Times-Italic RE/Times-Bold@0 ENC0/Times-Bold RE +/Times-Roman@0 ENC0/Times-Roman RE +%%EndProlog +%%Page: 1 1 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF<464c41>72 48 Q 134.71 +<5746494e44455228312920466c61>-.9 F 134.71<778c6e64657220464c41>-.15 F +<5746494e444552283129>-.9 E/F1 10.95/Times-Bold@0 SF -.219<4e41>72 84 S +<4d45>.219 E F0<8d61>108 96 Q +<778c6e64657220ad208c6e6420706f74656e7469616c207365637572697479208d61> +-.15 E<777320282268697473222920696e20736f7572636520636f6465>-.15 E F1 +<53594e4f50534953>72 112.8 Q/F2 10/Times-Bold@0 SF<8d61778c6e646572>108 +124.8 Q F0<5b>4.474 E F2A F0 4.474<5d5b>C F2-4.474 +E<657273696f6e>-.1 E F0 4.474<5d5b>C F2-4.474 E +<776c696e6b>-.1 E F0 4.474<5d5b>C F2-4.474 E F0<7c>A +F2A F0 4.474<5d5b>C F2A -.1<7665>-.15 G<6c3d>.1 E +/F3 10/Times-Italic@0 SF<58>A F0<7c>4.474 E F2<2d6d>4.473 E F3<58>4.473 +E F0 4.473<5d5b>4.473 G F2-4.473 E<7469>108 +136.8 Q -.1<7665>-.1 G F0<7c>.1 E F2A F0 4.855<5d5b>C F2 +-4.855 E -.1<7665>-.15 G<7269676e6f72>.1 E<65>-.18 E F0<7c>A F2A +F0 4.855<5d5b>C F2-4.855 E F0<7c>A F2A F0 +4.855<5d5b>C F2-4.855 E F0<7c>A F2A F0 4.855 +<5d5b>C F2-4.855 E F0<7c>A F2A F0 4.855 +<5d5b>C F2-4.855 E F0 4.855<5d5b>C F2 +-4.855 E<617465>108 148.8 Q F0<7c>A F2<2d69>A F0 7.658<5d5b>C F2 +-7.658 E F0<7c>A F2A F0 7.658<5d5b>C F2 +-7.658 E F0 7.658<5d5b>C F2-7.658 +E F0<7c>A F2A F0 7.658<5d5b>C F2A F3 +<46>A F0 7.658<5d5b>7.658 G F2A -.1<7665>-.25 G +<6869746c6973743d>.1 E F3<46>A F0 7.658<5d5b>7.658 G F2 +108 160.8 Q F3<46>A F0 2.5<5d5b>2.5 G F2 +-2.5 E F0<5d>A F3 2.5<5b73>2.79 G<6f7572>-2.5 E +<636520636f6465208c6c65206f7220736f7572>-.37 E<63652072>-.37 E +<6f6f7420646972>-.45 E<6563746f7279205d2b>-.37 E F1 +<4445534352495054494f4e>72 177.6 Q F0<466c61>108 189.6 Q 1.383<778c6e64 +6572207365617263686573207468726f75676820432f432b2b20736f7572636520636f64 +65206c6f6f6b696e6720666f7220706f74656e7469616c207365637572697479208d61> +-.15 F 3.883<77732e2054>-.15 F 3.883<6f72>-.8 G 1.384<756e208d61>-3.883 +F<778c6e646572>-.15 E<2c>-.4 E .509<73696d706c79206769>108 201.6 R .809 +-.15<7665208d>-.25 H -.15<6177>.15 G .509<8c6e6465722061206c697374206f66 +206469726563746f72696573206f72208c6c65732e>.15 F -.15<466f>5.508 G 3.008 +<7265>.15 G .508<616368206469726563746f7279206769>-3.008 F -.15<7665> +-.25 G .508<6e2c20616c6c208c6c65732074686174206861>.15 F .808 -.15 +<76652043>-.2 H .508<2f432b2b208c6c652d>.15 F 1.347<6e616d652065>108 +213.6 R 1.348<7874656e73696f6e7320696e2074686174206469726563746f72792028 +616e6420697473207375626469726563746f726965732c2072656375727369>-.15 F +-.15<7665>-.25 G 1.348<6c79292077696c6c2062652065>.15 F 3.848 +<78616d696e65642e20546875732c>-.15 F 1.348<666f72206d6f7374>3.848 F 1.03 +<70726f6a656374732c2073696d706c79206769>108 225.6 R 1.33 -.15<7665208d> +-.25 H -.15<6177>.15 G 1.03 +<8c6e64657220746865206e616d65206f662074686520736f7572636520636f646527> +.15 F 3.53<7374>-.55 G 1.03 +<6f706d6f7374206469726563746f727920287573652060>-3.53 F<602e>-.74 E 2.51 +-.74<27272066>-.7 H 1.03<6f72207468652063757272656e74>.74 F +<6469726563746f7279292c20616e64208d61>108 237.6 Q +<778c6e6465722077696c6c2065>-.15 E +<78616d696e6520616c6c206f66207468652070726f6a65637427>-.15 E 2.5<7343> +-.55 G<2f432b2b20736f7572636520636f64652e>-2.5 E<466c61>108 254.4 Q .272 +<778c6e6465722077696c6c2070726f647563652061206c697374206f662060>-.15 F +<606869747327>-.74 E 2.772<2728>-.74 G .272 +<706f74656e7469616c207365637572697479208d61>-2.772 F .273<7773292c20736f +72746564206279207269736b3b20746865207269736b6965737420686974732061726520 +73686f>-.15 F<776e>-.25 E 2.73<8c7273742e20546865>108 266.4 R .23 +<7269736b206c65>2.73 F -.15<7665>-.25 G 2.73<6c69>.15 G 2.73<7373>-2.73 +G<686f>-2.73 E .23<776e20696e736964652073717561726520627261636b>-.25 F +.23<65747320616e642076>-.1 F .229<61726965732066726f6d20302c2076>-.25 F +.229 +<657279206c6974746c65207269736b2c20746f20352c206772656174207269736b2e> +-.15 F<54686973>5.229 E .373<7269736b206c65>108 278.4 R -.15<7665>-.25 G +2.873<6c64>.15 G .373 +<6570656e6473206e6f74206f6e6c79206f6e207468652066756e6374696f6e2c2062> +-2.873 F .374<7574206f6e207468652076>-.2 F .374<616c756573206f6620746865 +20706172616d6574657273206f66207468652066756e6374696f6e2e>-.25 F -.15 +<466f>5.374 G 2.874<7265>.15 G<78616d2d>-3.024 E .612<706c652c20636f6e73 +74616e7420737472696e677320617265206f6674656e206c657373207269736b>108 +290.4 R 3.111<7974>-.15 G .611<68616e2066756c6c792076>-3.111 F .611 +<61726961626c6520737472696e677320696e206d616e>-.25 F 3.111<7963>-.15 G +<6f6e7465>-3.111 E .611<7874732c20616e6420696e2074686f736520636f6e7465> +-.15 F<787473>-.15 E .156<746865206869742077696c6c206861>108 302.4 R +.456 -.15<76652061206c>-.2 H -.25<6f77>.15 G .156<6572207269736b206c65> +.25 F -.15<7665>-.25 G 2.656<6c2e20466c61>.15 F .156 +<778c6e646572206b6e6f>-.15 F .156<77732061626f7574206765747465>-.25 F +.157<787420286120636f6d6d6f6e206c69627261727920666f7220696e7465726e6174 +696f6e616c697a6564>-.15 F .73<70726f6772616d732920616e642077696c6c207472 +65617420636f6e7374616e7420737472696e677320706173736564207468726f75676820 +6765747465>108 314.4 R .73<78742061732074686f75676820746865>-.15 F 3.23 +<7977>-.15 G .73<65726520636f6e7374616e7420737472696e67733b2074686973> +-3.23 F .873<7265647563657320746865206e756d626572206f662066>108 326.4 R +.873<616c7365206869747320696e20696e7465726e6174696f6e616c697a6564207072 +6f6772616d732e>-.1 F<466c61>5.873 E .873<778c6e6465722077696c6c20646f20 +7468652073616d6520736f7274206f66207468696e67>-.15 F 1.515<77697468205f54 +282920616e64205f5445585428292c20636f6d6d6f6e204d6963726f736f6674206d6163 +726f7320666f722068616e646c696e6720696e7465726e6174696f6e616c697a65642070 +726f6772616d7320466c61>108 338.4 R<778c6e646572>-.15 E 1.264 +<636f72726563746c792069676e6f726573206d6f7374207465>108 350.4 R 1.264 +<787420696e7369646520636f6d6d656e747320616e6420737472696e67732e>-.15 F +1.264<4e6f726d616c6c79208d61>6.264 F 1.264<778c6e6465722073686f>-.15 F +1.264<777320616c6c206869747320776974682061207269736b>-.25 F<6c65>108 +362.4 Q -.15<7665>-.25 G 3.329<6c6f>.15 G 3.329<6661>-3.329 G 3.328 +<746c>-3.329 G .828<6561737420312c2062>-3.328 F .828 +<757420796f752063616e207573652074686520adad6d696e6c65>-.2 F -.15<7665> +-.25 G 3.328<6c6f>.15 G .828<7074696f6e20746f2073686f>-3.328 F 3.328 +<776f>-.25 G .828 +<6e6c792068697473207769746820686967686572207269736b206c65>-3.328 F -.15 +<7665>-.25 G .828<6c7320696620796f75>.15 F<776973682e>108 374.4 Q .734 +<4e6f742065>108 391.2 R -.15<7665>-.25 G .734<72792068697420697320616374 +75616c6c7920612073656375726974792076756c6e65726162696c697479>.15 F 3.234 +<2c61>-.65 G .734<6e64206e6f742065>-3.234 F -.15<7665>-.25 G .734<727920 +73656375726974792076756c6e65726162696c697479206973206e65636573736172696c +7920666f756e642e>.15 F<4e65>108 403.2 Q -.15<7665>-.25 G .413 +<727468656c6573732c208d61>.15 F .413<778c6e6465722063616e20626520616e20 +61696420696e208c6e64696e6720616e642072656d6f>-.15 F .413 +<76696e672073656375726974792076756c6e65726162696c69746965732e>-.15 F +2.912<4163>5.412 G .412<6f6d6d6f6e2077>-2.912 F .412<617920746f>-.1 F +.37<757365208d61>108 415.2 R .37 +<778c6e64657220697320746f208c727374206170706c79208d61>-.15 F .371<778c6e +64657220746f206120736574206f6620736f7572636520636f646520616e642065>-.15 +F .371<78616d696e652074686520686967686573742d7269736b206974656d732e>-.15 +F<5468656e2c>5.371 E .715<75736520adad696e7075747320746f2065>108 427.2 R +.715<78616d696e652074686520696e707574206c6f636174696f6e732c20616e642063 +6865636b20746f206d616b>-.15 F 3.214<6573>-.1 G .714 +<7572652074686174206f6e6c79206c65>-3.214 F -.05<6761>-.15 G 3.214<6c61> +.05 G .714<6e64207361666520696e7075742076>-3.214 F<616c756573>-.25 E +<6172652061636365707465642066726f6d20756e747275737465642075736572732e> +108 439.2 Q .892<4f6e636520796f7527>108 456 R 1.192 -.15<76652061>-.5 H +.892<75646974656420612070726f6772616d2c20796f752063616e206d61726b20736f +7572636520636f6465206c696e65732074686174206172652061637475616c6c79208c6e +652062>.15 F .893<75742063617573652073707572696f7573>-.2 F -.1<7761>108 +468 S .923<726e696e677320736f2074686174208d61>.1 F .923<778c6e6465722077 +696c6c2073746f7020636f6d706c61696e696e672061626f7574207468656d2e>-.15 F +2.523 -.8<546f206d>5.923 H .923 +<61726b2061206c696e6520736f20746861742074686573652077>.8 F .922 +<61726e696e677320617265>-.1 F 1.398<737570707265737365642c20707574206120 +7370656369616c6c792d666f726d617474656420636f6d6d656e7420656974686572206f +6e207468652073616d65206c696e65202861667465722074686520736f7572636520636f +646529206f7220616c6c206279>108 480 R<697473656c6620696e2074686520707265> +108 492 Q<76696f7573206c696e652e>-.25 E +<54686520636f6d6d656e74206d757374206861>5 E .3 -.15<7665206f>-.2 H +<6e65206f6620746865207477>.15 E 2.5<6f66>-.1 G<6f6c6c6f>-2.5 E +<77696e6720666f726d6174733a>-.25 E 35<832f>108 508.8 S 2.5<2f46>-35 G +<6c61>-2.5 E<778c6e6465723a2069676e6f7265>-.15 E 35<832f>108 525.6 S 2.5 +<2a46>-35 G<6c61>-2.5 E<778c6e6465723a2069676e6f7265202a2f>-.15 E 1.095 +<4e6f746520746861742c20666f7220636f6d7061746962696c69747927>108 542.4 R +3.595<7373>-.55 G<616b>-3.595 E 1.095 +<652c20796f752063616e207265706c6163652022466c61>-.1 F 1.095 +<778c6e6465723a2220776974682022495453343a22206f7220225241>-.15 F 1.094 +<54533a2220696e207468657365207370652d>-1.11 F .131 +<6369616c6c792d666f726d617474656420636f6d6d656e74732e>108 554.4 R .131 +<53696e636520697427>5.131 F 2.631<7370>-.55 G .132<6f737369626c65207468 +61742073756368206c696e6573206172652077726f6e672c20796f752063616e20757365 +207468652060>-2.631 F<60adad6e65>-.74 E -.15<7665>-.25 G +<7269676e6f726527>.15 E<27>-.74 E .075 +<6f7074696f6e2c20776869636820636175736573208d61>108 566.4 R .075 +<778c6e64657220746f206e65>-.15 F -.15<7665>-.25 G 2.575<7269>.15 G .074 +<676e6f726520616e>-2.575 F 2.574<796c>-.15 G .074 +<696e65206e6f206d617474657220776861742074686520636f6d6d656e747320736179> +-2.574 F 5.074<2e54>-.65 G .074<6875732c20726573706f6e736573>-5.074 F +2.174<746861742077>108 578.4 R 2.174 +<6f756c64206f74686572776973652062652069676e6f7265642077>-.1 F 2.175 +<6f756c6420626520696e636c7564656420286f72>-.1 F 4.675<2c6d>-.4 G 2.175 +<6f726520636f6e667573696e676c79>-4.675 F 4.675<2cad>-.65 G-4.675 +E -.15<7665>-.25 G 2.175<7269676e6f72652069676e6f72657320746865>.15 F +3.566<69676e6f726573292e2054686973>108 590.4 R 1.066<636f6d6d656e742073 +796e7461782069732061637475616c6c792061206d6f72652067656e6572616c2073796e +74617820666f72207370656369616c2064697265637469>3.566 F -.15<7665>-.25 G +3.566<7374>.15 G 3.566<6f8d>-3.566 G -.15<6177>-3.566 G<8c6e646572>.15 E +3.566<2c62>-.4 G<7574>-3.766 E<63757272656e746c79206f6e6c792069676e6f72 +696e67206c696e657320697320737570706f727465642e>108 602.4 Q<466c61>108 +619.2 Q .701<778c6e646572207573657320616e20696e7465726e616c206461746162 +6173652063616c6c6564207468652060>-.15 F<6072756c6573657427>-.74 E .702< +273b207468652072756c65736574206964656e74698c65732066756e6374696f6e732074 +6861742061726520636f6d6d6f6e>-.74 F 1.679 +<636175736573206f66207365637572697479208d61>108 631.2 R 4.179 +<77732e20546865>-.15 F 1.679 +<7374616e646172642072756c6573657420696e636c756465732061206c6172>4.179 F +1.678<6765206e756d626572206f6620646966>-.18 F 1.678 +<666572656e7420706f74656e7469616c2070726f626c656d732c>-.25 F .027<696e63 +6c7564696e6720626f74682067656e6572616c2069737375657320746861742063616e20 +696d7061637420616e>108 643.2 R 2.528<7943>-.15 G .028<2f432b2b2070726f67 +72616d2c2061732077656c6c2061732061206e756d626572206f662073706563698c6320 +556e69782d6c696b>-2.528 F<65>-.1 E 1.942<616e642057>108 655.2 R +<696e646f>-.4 E 1.942<77732066756e6374696f6e7320746861742061726520657370 +656369616c6c792070726f626c656d617469632e>-.25 F 1.941 +<4173206e6f7465642061626f>6.942 F -.15<7665>-.15 G 4.441<2c65>.15 G -.15 +<7665>-4.691 G 1.941<727920706f74656e7469616c207365637572697479208d61> +.15 F<77>-.15 E 1.147<666f756e6420696e2061206769>108 667.2 R -.15<7665> +-.25 G 3.647<6e73>.15 G 1.148<6f7572636520636f6465208c6c6520286d61746368 +696e6720616e20656e74727920696e207468652072756c65736574292069732063616c6c +656420612060>-3.647 F<606869742c>-.74 E 2.628 -.74<27272061>-.7 H 1.148 +<6e642074686520736574206f662068697473>.74 F 2.554 +<666f756e6420647572696e6720616e>108 679.2 R 5.053<7970>-.15 G 2.553<6172 +746963756c61722072756e206f66207468652070726f6772616d2069732063616c6c6564 +207468652060>-5.053 F<606869746c6973742e>-.74 E 6.533 -.74<27272048>-.7 +H 2.553<69746c697374732063616e206265207361>.74 F -.15<7665>-.2 G 5.053 +<6428>.15 G<7573696e67>-5.053 E108 691.2 Q -.15<7665>-.2 G .04 +<6869746c697374292c2072656c6f61646564206261636b20666f72207265646973706c +617920287573696e6720adad6c6f61646869746c697374292c20616e6420796f75206361 +6e2073686f>.15 F 2.541<776f>-.25 G .041 +<6e6c79207468652068697473207468617420617265206469662d>-2.541 F<66657265 +6e742066726f6d20616e6f746865722072756e20287573696e6720adad646966>108 +703.2 Q<666869746c697374292e>-.25 E<416e>108 720 Q 2.757<798c>-.15 G +.257<6c656e616d65206769>-2.757 F -.15<7665>-.25 G 2.757<6e6f>.15 G 2.757 +<6e74>-2.757 G .257<686520636f6d6d616e64206c696e652077696c6c2062652065> +-2.757 F .257<78616d696e6564202865>-.15 F -.15<7665>-.25 G 2.757<6e69> +.15 G 2.757<6669>-2.757 G 2.756<7464>-2.757 G<6f65736e27>-2.756 E 2.756 +<7468>-.18 G -2.25 -.2<61762065>-2.756 H 2.756<6175>2.956 G .256 +<7375616c20432f432b2b208c6c656e616d65>-2.756 F<466c61>72 768 Q 161.655 +<778c6e646572203330>-.15 F<4d61792032303034>2.5 E<31>202.335 E 0 Cg EP +%%Page: 2 2 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF<464c41>72 48 Q 134.71 +<5746494e44455228312920466c61>-.9 F 134.71<778c6e64657220464c41>-.15 F +<5746494e444552283129>-.9 E -.15<6578>108 84 S .197 +<74656e73696f6e293b207468757320796f752063616e20666f726365208d61>.15 F +.197<778c6e64657220746f2065>-.15 F .197<78616d696e6520616e>-.15 F 2.697 +<7973>-.15 G .198<706563698c63208c6c657320796f75206465736972652e>-2.697 +F .198<5768696c6520736561726368696e67206469726563746f2d>5.198 F 1.603 +<726965732072656375727369>108 96 R -.15<7665>-.25 G<6c79>.15 E 4.103 +<2c8d>-.65 G -.15<6177>-4.103 G 1.603 +<8c6e646572206f6e6c79206f70656e7320616e642065>.15 F 1.602 +<78616d696e6573207265>-.15 F 1.602<67756c6172208c6c65732074686174206861> +-.15 F 1.902 -.15<76652043>-.2 H 1.602<2f432b2b208c6c656e616d652065>.15 +F<7874656e73696f6e732e>-.15 E<466c61>108 108 Q .76<778c6e64657220707265 +73756d657320746861742c208c6c65732061726520432f432b2b208c6c65732069662074 +6865>-.15 F 3.26<7968>-.15 G -2.25 -.2<61762065>-3.26 H .76<7468652065> +3.46 F .76<7874656e73696f6e7320222e63222c20222e68222c20222e6563222c2022 +2e656370222c20222e706763222c>-.15 F .964<222e43222c20222e637070222c2022 +2e435050222c20222e637878222c20222e6363222c20222e4343222c20222e706363222c +20222e687070222c206f7220222e48222e>108 120 R .963 +<546865208c6c656e616d652060>5.963 F<60ad27>-.74 E 3.463<276d>-.74 G .963 +<65616e7320746865207374616e64617264>-3.463 F 2.82<696e7075742e2054>108 +132 R 2.82<6f70>-.8 G<7265>-2.82 E -.15<7665>-.25 G .32<6e74207365637572 +6974792070726f626c656d732c207370656369616c208c6c657320287375636820617320 +6465>.15 F .32<76696365207370656369616c208c6c657320616e64206e616d656420 +7069706573292061726520616c>-.25 F -.1<7761>-.1 G<7973>.1 E +<736b69707065642c20616e6420627920646566>108 144 Q +<61756c742073796d626f6c6963206c696e6b732061726520736b69707065642c>-.1 E +.375<416674657220746865206c697374206f6620686974732069732061206272696566 +2073756d6d617279206f662074686520726573756c74732028757365202d4420746f2072 +656d6f>108 160.8 R .675 -.15<76652074>-.15 H .374 +<68697320696e666f726d6174696f6e292e>.15 F .374<49742077696c6c2073686f> +5.374 F 2.874<7774>-.25 G<6865>-2.874 E .793<6e756d626572206f6620686974 +732c206c696e657320616e616c797a656420286173207265706f72746564206279207763 +20ad6c292c20616e6420746865207068>108 172.8 R .794<79736963616c20736f7572 +6365206c696e6573206f6620636f64652028534c4f432920616e612d>-.05 F 3.263 +<6c797a65642e2041>108 184.8 R<7068>3.263 E .763<79736963616c20534c4f4320 +69732061206e6f6e2d626c616e6b2c206e6f6e2d636f6d6d656e74206c696e652e>-.05 +F .763<49742077696c6c207468656e2073686f>5.763 F 3.263<7774>-.25 G .762 +<6865206e756d626572206f6620686974732061742065616368>-3.263 F<6c65>108 +196.8 Q -.15<7665>-.25 G .241 +<6c3b206e6f746520746861742074686572652077696c6c206e65>.15 F -.15<7665> +-.25 G 2.741<7262>.15 G 2.741<656168>-2.741 G .241<69742061742061206c65> +-2.741 F -.15<7665>-.25 G 2.741<6c6c>.15 G -.25<6f77>-2.741 G .241 +<6572207468616e206d696e6c65>.25 F -.15<7665>-.25 G 2.742<6c28>.15 G +2.742<3162>-2.742 G 2.742<7964>-2.742 G<6566>-2.742 E 2.742 +<61756c74292e20546875732c20225b305d>-.1 F 2.742<305b>7.742 G 5.242 +<315d203922>-2.742 F .365<6d65616e732074686174206174206c65>108 208.8 R +-.15<7665>-.25 G 2.864<6c3074>.15 G .364<686572652077657265203020686974 +73207265706f727465642c20616e64206174206c65>-2.864 F -.15<7665>-.25 G +2.864<6c3174>.15 G .364 +<68657265207765726520392068697473207265706f727465642e>-2.864 F .364 +<49742077696c6c206e65>5.364 F .364<78742073686f>-.15 F<77>-.25 E .25 +<746865206e756d626572206f6620686974732061742061206769>108 220.8 R -.15 +<7665>-.25 G 2.75<6e6c>.15 G -2.15 -.25<65762065>-2.75 H 2.75<6c6f>.25 G +2.75<726c>-2.75 G<6172>-2.75 E .25<6765722028736f206c65>-.18 F -.15 +<7665>-.25 G 2.75<6c33>.15 G 2.75<2b68>-2.75 G .251<6173207468652073756d +206f6620746865206e756d626572206f662068697473206174206c65>-2.75 F -.15 +<7665>-.25 G 2.751<6c33>.15 G 2.751<2c34>-2.751 G 2.751<2c61>-2.751 G +<6e64>-2.751 E 2.785<35292e20546875732c>108 232.8 R .285 +<616e20656e747279206f6620225b302b5d>2.785 F .285<3337222073686f>5.285 F +.285<77732074686174206174206c65>-.25 F -.15<7665>-.25 G 2.785<6c306f>.15 +G 2.784<7268>-2.785 G .284<69676865722074686572652077657265203337206869 +7473202874686520302b20656e7472792077696c6c20616c>-2.784 F -.1<7761>-.1 G +<7973>.1 E 1.406<6265207468652073616d652061732074686520226869747322206e +756d6265722061626f>108 244.8 R -.15<7665>-.15 G 3.906<292e2048697473>.15 +F 1.407<706572204b534c4f43206973206e65>3.906 F 1.407<78742073686f>-.15 F +1.407<776e3b20746869732069732065616368206f662074686520226c65>-.25 F -.15 +<7665>-.25 G 3.907<6c6f>.15 G<72>-3.907 E .34<686967686572222076>108 +256.8 R .34 +<616c756573206d756c7469706c696564206279203130303020616e64206469>-.25 F +.34<766964656420627920746865207068>-.25 F .34<79736963616c20534c4f432e> +-.05 F .34 +<49662073796d6c696e6b73207765726520736b69707065642c2074686520636f756e74> +5.34 F 1.589<6f662074686f7365206973207265706f727465642e>108 268.8 R +1.589<496620686974732077657265207375707072657373656420287573696e67207468 +65202269676e6f7265222064697265637469>6.589 F 1.89 -.15<76652069>-.25 H +4.09<6e73>.15 G 1.59<6f7572636520636f646520636f6d6d656e7473206173>-4.09 +F .538<6465736372696265642061626f>108 280.8 R -.15<7665>-.15 G .538<292c +20746865206e756d6265722073757070726573736564206973207265706f727465642e> +.15 F .537<546865206d696e696d756d207269736b206c65>5.538 F -.15<7665>-.25 +G 3.037<6c74>.15 G 3.037<6f62>-3.037 G 3.037<6569>-3.037 G .537 +<6e636c7564656420696e20746865207265706f7274>-3.037 F 1.952 +<697320646973706c617965643b20627920646566>108 292.8 R 1.952 +<61756c7420746869732069732031202875736520adad6d696e6c65>-.1 F -.15<7665> +-.25 G 4.453<6c74>.15 G 4.453<6f63>-4.453 G 1.953 +<68616e67652074686973292e>-4.453 F 1.953 +<5468652073756d6d61727920656e6473207769746820696d706f7274616e74>6.953 F +.283<72656d696e646572733a204e6f742065>108 304.8 R -.15<7665>-.25 G .283< +727920686974206973206e65636573736172696c7920612073656375726974792076756c +6e65726162696c697479>.15 F 2.783<2c61>-.65 G .282<6e64207468657265206d61 +79206265206f746865722073656375726974792076756c6e65726162696c692d>-2.783 +F<74696573206e6f74207265706f727465642062792074686520746f6f6c2e>108 316.8 +Q<466c61>108 333.6 Q .29<778c6e64657220696e74656e74696f6e616c6c792077> +-.15 F .29<6f726b732073696d696c61726c7920746f20616e6f746865722070726f67 +72616d2c20495453342c207768696368206973206e6f742066756c6c79206f70656e2073 +6f7572636520736f667477>-.1 F<617265>-.1 E .378<2861732064658c6e65642069 +6e20746865204f70656e20536f757263652044658c6e6974696f6e29206e6f7220667265 +6520736f667477>108 345.6 R .378 +<617265202861732064658c6e656420627920746865204672656520536f667477>-.1 F +.378<6172652046>-.1 F<6f756e646174696f6e292e>-.15 E +<54686520617574686f72206f6620466c61>108 357.6 Q +<778c6e64657220686173206e65>-.15 E -.15<7665>-.25 G 2.5<7273>.15 G +<65656e204954533427>-2.5 E 2.5<7373>-.55 G<6f7572636520636f64652e>-2.5 E +/F1 10.95/Times-Bold@0 SF<425249454620545554>72 374.4 Q<4f5249414c>-.197 +E F0<4865726527>108 386.4 Q 2.748<736162>-.55 G .249<726965662065>-2.748 +F .249<78616d706c65206f6620686f>-.15 F 2.749<778d>-.25 G -.15<6177> +-2.749 G .249<8c6e646572206d6967687420626520757365642e>.15 F .249 +<496d6167696e65207468617420796f75206861>5.249 F .549 -.15<76652074>-.2 H +.249<686520432f432b2b20736f7572636520636f646520666f72>.15 F .861<736f6d +652070726f6772616d206e616d65642078797a7a792028776869636820796f75206d6179 +206f72206d6179206e6f74206861>108 398.4 R 1.161 -.15<76652077>-.2 H .861 +<72697474656e292c20616e6420796f7527>.15 F .861 +<726520736561726368696e6720666f72207365637572697479>-.5 F .938<76756c6e +65726162696c69746965732028736f20796f752063616e208c78207468656d206265666f +726520637573746f6d65727320656e636f756e746572207468652076756c6e6572616269 +6c6974696573292e>108 410.4 R -.15<466f>5.938 G 3.438<7274>.15 G .938 +<686973207475746f7269616c2c204927>-3.438 F<6c6c>-.1 E +<617373756d65207468617420796f7527>108 422.4 Q +<7265207573696e67206120556e69782d6c696b>-.5 E 2.5<6573>-.1 G<797374656d +2c2073756368206173204c696e75782c204f70656e4253442c206f72204d61634f532058 +2e>-2.5 E .874<49662074686520736f7572636520636f646520697320696e20612073 +75626469726563746f7279206e616d65642078797a7a79>108 451.2 R 3.373<2c79> +-.65 G .873<6f752077>-3.373 F .873 +<6f756c642070726f6261626c79207374617274206279206f70656e696e672061207465> +-.1 F .873<78742077696e646f>-.15 F<77>-.25 E .161 +<616e64207573696e67208d61>108 463.2 R<778c6e64657227>-.15 E 2.662<7364> +-.55 G<6566>-2.662 E .162<61756c742073657474696e67732c20746f20616e616c79 +7a65207468652070726f6772616d20616e64207265706f72742061207072696f72697469 +7a6564206c697374206f6620706f74656e7469616c20736563752d>-.1 F +<726974792076756c6e65726162696c697469657320287468652060>108 475.2 Q +<606c65737327>-.74 E 2.5<276a>-.74 G<757374206d616b>-2.5 E<657320737572 +652074686520726573756c74732073746179206f6e207468652073637265656e293a>-.1 +E<8d61>144 487.2 Q<778c6e6465722078797a7a79207c206c657373>-.15 E .306 +<4174207468697320706f696e742c20796f752077696c6c2061206c6172>108 516 R +.306 +<6765206e756d626572206f6620656e74726965733b206561636820656e747279206265> +-.18 F .306<67696e7320776974682061208c6c656e616d652c206120636f6c6f6e2c20 +61206c696e65206e756d626572>-.15 F<2c>-.4 E 2.536<6172>108 528 S .036 +<69736b206c65>-2.536 F -.15<7665>-.25 G 2.536<6c69>.15 G 2.536<6e62> +-2.536 G<7261636b>-2.536 E .036 +<65747320287768657265203520697320746865206d6f7374207269736b>-.1 F .036 +<79292c20612063617465>-.15 F<676f7279>-.15 E 2.536<2c74>-.65 G .036<6865 +206e616d65206f66207468652066756e6374696f6e2c20616e6420612064657363726970 +74696f6e206f66>-2.536 F<7768>108 540 Q 2.782<798d>-.05 G -.15<6177> +-2.782 G .282<8c6e646572207468696e6b7320746865206c696e652069732061207675 +6c6e65726162696c697479>.15 F 5.281<2e46>-.65 G<6c61>-5.281 E .281 +<778c6e646572206e6f726d616c6c7920736f727473206279207269736b206c65>-.15 F +-.15<7665>-.25 G .281<6c2c2073686f>.15 F .281 +<77696e6720746865207269736b692d>-.25 F .07 +<657374206974656d73208c7273743b20696620796f75206861>108 552 R .37 -.15 +<7665206c>-.2 H .07<696d697465642074696d652c20697427>.15 F 2.57<7370> +-.55 G .071<726f6261626c79206265737420746f2073746172742077>-2.57 F .071< +6f726b696e67206f6e20746865207269736b69657374206974656d7320616e6420636f6e +74696e7565>-.1 F .625 +<756e74696c20796f752072756e206f7574206f662074696d652e>108 564 R .625 +<496620796f752077>5.625 F .625<616e7420746f206c696d69742074686520646973 +706c617920746f207269736b732077697468206f6e6c792061206365727461696e207269 +736b206c65>-.1 F -.15<7665>-.25 G 3.125<6c6f>.15 G 3.125<7268>-3.125 G +<6967686572>-3.125 E<2c>-.4 E 1.098<7573652074686520adad6d696e6c65>108 +576 R -.15<7665>-.25 G 3.598<6c6f>.15 G 3.598<7074696f6e2e204966>-3.598 +F<796f7527>3.598 E 1.099<72652067657474696e6720616e2065>-.5 F 1.099 +<787472616f7264696e617279206e756d626572206f662066>-.15 F 1.099 +<616c736520706f73697469>-.1 F -.15<7665>-.25 G 3.599<7362>.15 G 1.099 +<6563617573652076>-3.599 F<61726961626c65>-.25 E .673 +<6e616d6573206c6f6f6b206c696b>108 588 R 3.173<6564>-.1 G .672<616e676572 +6f75732066756e6374696f6e206e616d65732c207573652074686520ad46206f7074696f +6e20746f2072656d6f>-3.173 F .972 -.15<76652072>-.15 H .672 +<65706f7274732061626f7574207468656d2e>.15 F .672<496620796f7520646f6e27> +5.672 F<74>-.18 E 1.112<756e6465727374616e6420746865206572726f72206d6573 +736167652c20706c656173652073656520646f63756d656e747320737563682061732074 +6865>108 600 R/F2 10/Times-Italic@0 SF 1.112<57726974696e67205365637572> +3.402 F 3.612<6550>-.37 G -1.7 -.45<726f2067>-3.612 H -.15<7261>.45 G +1.112<6d7320666f72204c696e757820616e64>.15 F 1.074<556e697820484f>108 +612 R<5754>-.5 E<4f>-.18 E F0 1.074<617420687474703a2f2f777777>3.844 F +<2e64776865656c6572>-.65 E 1.073 +<2e636f6d2f7365637572652d70726f6772616d732077686963682070726f>-.55 F +1.073 +<7669646573206d6f726520696e666f726d6174696f6e206f6e2077726974696e67>-.15 +F<7365637572652070726f6772616d732e>108 624 Q .721<4f6e636520796f75206964 +656e74696679207468652070726f626c656d20616e6420756e6465727374616e64206974 +2c20796f752063616e208c782069742e>108 652.8 R .722 +<4f63636173696f6e616c6c7920796f75206d61792077>5.722 F .722 +<616e7420746f2072652d646f20746865>-.1 F .546<616e616c797369732c20626f74 +68206265636175736520746865206c696e65206e756d626572732077696c6c206368616e +6765>108 664.8 R F2<616e64>3.045 E F0 .545<746f206d616b>3.045 F 3.045 +<6573>-.1 G .545<757265207468617420746865206e65>-3.045 F 3.045<7763>-.25 +G .545<6f646520646f65736e27>-3.045 F 3.045<7469>-.18 G<6e74726f64756365> +-3.045 E<796574206120646966>108 676.8 Q +<666572656e742076756c6e65726162696c697479>-.25 E<2e>-.65 E .515 +<496620796f7527>108 705.6 R .815 -.15<76652064>-.5 H .515 +<657465726d696e6564207468617420736f6d65206c696e652069736e27>.15 F 3.016 +<7472>-.18 G .516<65616c6c7920612070726f626c656d2c20616e6420796f7527> +-3.016 F .516<72652073757265206f662069742c20796f752063616e20696e73657274 +206a757374206265666f7265>-.5 F<6f72206f6e20746865206f66>108 717.6 Q +<66656e64696e67206c696e65206120636f6d6d656e74206c696b>-.25 E<65>-.1 E +<2f2a20466c61>146.5 729.6 Q<778c6e6465723a2069676e6f7265202a2f>-.15 E +<466c61>72 768 Q 161.655<778c6e646572203330>-.15 F<4d61792032303034>2.5 +E<32>202.335 E 0 Cg EP +%%Page: 3 3 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF<464c41>72 48 Q 134.71 +<5746494e44455228312920466c61>-.9 F 134.71<778c6e64657220464c41>-.15 F +<5746494e444552283129>-.9 E<746f206b>108 84 Q +<656570207468656d2066726f6d2073686f>-.1 E +<77696e6720757020696e20746865206f75747075742e>-.25 E .398 +<4f6e636520796f7527>108 112.8 R .698 -.15<76652064>-.5 H .398<6f6e652074 +6861742c20796f752073686f756c6420676f206261636b20616e64207365617263682066 +6f72207468652070726f6772616d27>.15 F 2.897<7369>-.55 G .397 +<6e707574732c20746f206d616b>-2.897 F 2.897<6573>-.1 G .397 +<7572652074686174207468652070726f2d>-2.897 F .293 +<6772616d207374726f6e676c79208c6c7465727320616e>108 124.8 R 2.793<796f> +-.15 G 2.793<6669>-2.793 G .293 +<747320756e7472757374656420696e707574732e>-2.793 F<466c61>5.293 E .293 +<778c6e6465722063616e206964656e74696679206d616e>-.15 F 2.793<7970>-.15 G +.293<726f6772616d20696e70757473206279207573696e6720746865>-2.793 F +108 136.8 Q 2.5<6574>-.1 G +<6869733a>-2.5 E<8d61>144 148.8 Q +<778c6e64657220adad696e707574732078797a7a79>-.15 E<466c61>108 177.6 Q +.428<778c6e6465722063616e20696e7465>-.15 F .428 +<67726174652077656c6c2077697468207465>-.15 F .428 +<787420656469746f727320616e6420696e7465>-.15 F .428<677261746564206465> +-.15 F -.15<7665>-.25 G .427<6c6f706d656e7420656e>.15 F .427 +<7669726f6e6d656e74733b20736565207468652065>-.4 F<78616d706c6573>-.15 E +<666f72206d6f726520696e666f726d6174696f6e2e>108 189.6 Q<466c61>108 218.4 +Q .574<778c6e64657220696e636c75646573206d616e>-.15 F 3.074<796f>-.15 G +.574<74686572206f7074696f6e732c20696e636c7564696e67206f6e657320746f2063 +72656174652048544d4c2076>-3.074 F .574 +<657273696f6e73206f6620746865206f7574707574202875736566756c20666f72>-.15 +F<707265747469657220646973706c617973292e>108 230.4 Q<546865206e65>5 E<78 +742073656374696f6e206465736372696265732074686f7365206f7074696f6e7320696e +206d6f72652064657461696c2e>-.15 E/F1 10.95/Times-Bold@0 SF +<4f5054494f4e53>72 259.2 Q F0<466c61>108 271.2 Q .187<778c6e646572206861 +732061206e756d626572206f66206f7074696f6e732c2077686963682063616e20626520 +67726f7570656420696e746f206f7074696f6e73207468617420636f6e74726f6c206974 +73206f>-.15 F .186<776e20646f63756d656e746174696f6e2c>-.25 F +<73656c656374207768696368206869747320746f20646973706c6179>108 283.2 Q +2.5<2c73>-.65 G<656c65637420746865206f757470757420666f726d61742c20616e64 +20706572666f726d206869746c697374206d616e6167656d656e742e>-2.5 E/F2 10 +/Times-Bold@0 SF<446f63756d656e746174696f6e>87 312 Q108 +324 Q F0<53686f>30.26 E 2.5<7775>-.25 G +<73616765202868656c702920696e666f726d6174696f6e2e>-2.5 E F2108 +352.8 Q<657273696f6e>-.1 E F0<53686f>17.59 E +<777320286a75737429207468652076>-.25 E +<657273696f6e206e756d62657220616e642065>-.15 E<786974732e>-.15 E F2 +<53656c656374696e67204869747320746f20446973706c6179>87 381.6 Q +108 393.6 Q<776c696e6b>-.1 E F0<416c6c6f>9.24 E 2.673 +<7774>-.25 G .173<686520757365206f662073796d626f6c6963206c696e6b733b206e +6f726d616c6c792073796d626f6c6963206c696e6b732061726520736b69707065642e> +-2.673 F<446f6e27>5.174 E 2.674<7475>-.18 G .174 +<73652074686973206f7074696f6e>-2.674 F .355<696620796f7527>168 405.6 R +.355 +<726520616e616c797a696e6720636f6465206279206f74686572733b2061747461636b> +-.5 F .355<65727320636f756c6420646f206d616e>-.1 F 2.855<7974>-.15 G .354 +<68696e677320746f2063617573652070726f626c656d7320666f7220616e>-2.855 F +1.083 +<616e616c7973697320776974682074686973206f7074696f6e20656e61626c65642e> +168 417.6 R -.15<466f>6.084 G 3.584<7265>.15 G 1.084 +<78616d706c652c20616e2061747461636b>-3.734 F 1.084 +<657220636f756c6420696e736572742073796d626f6c6963206c696e6b7320746f>-.1 +F .326<8c6c65732073756368206173202f6574632f70617373776420286c65616b696e +6720696e666f726d6174696f6e2061626f757420746865208c6c6529206f722063726561 +746520612063697263756c6172206c6f6f702c207768696368>168 429.6 R -.1<776f> +168 441.6 S .428<756c64206361757365208d61>.1 F .428 +<778c6e64657220746f2072756e2060>-.15 F<60666f7265>-.74 E -.15<7665>-.25 +G<7227>.15 E 2.928<272e20416e6f74686572>-.74 F .429<70726f626c656d207769 +746820656e61626c696e672074686973206f7074696f6e2069732074686174>2.928 F +.542<6966207468652073616d65208c6c65206973207265666572656e636564206d756c +7469706c652074696d6573207573696e672073796d626f6c6963206c696e6b732c206974 +2077696c6c20626520616e616c797a6564206d756c74692d>168 453.6 R 1.525<706c +652074696d65732028616e642074687573207265706f72746564206d756c7469706c6520 +74696d6573292e>168 465.6 R 1.525<4e6f74652074686174208d61>6.525 F 1.525 +<778c6e64657220616c726561647920696e636c7564657320736f6d65>-.15 F 2.957 +<70726f74656374696f6e206167>168 477.6 R 2.957<61696e73742073796d626f6c69 +63206c696e6b7320746f207370656369616c208c6c652074797065732073756368206173 +206465>-.05 F 2.957<76696365208c6c652074797065732028652e672e2c>-.25 F +<2f6465>168 489.6 Q 1.218<762f7a65726f206f7220433a5c6d7973747566>-.25 F +3.718<665c636f6d31292e204e6f7465>-.25 F 1.218<7468617420666f72208d61> +3.718 F 1.218<778c6e6465722076>-.15 F 1.219 +<657273696f6e20312e303120616e64206265666f72652c20746869732077>-.15 F +<6173>-.1 E<74686520646566>168 501.6 Q<61756c742e>-.1 E F2 +108 530.4 Q108 547.2 Q F0<53686f>50.41 E 2.5 +<776f>-.25 G<6e6c792066756e6374696f6e732074686174206f627461696e20646174 +612066726f6d206f757473696465207468652070726f6772616d3b207468697320616c73 +6f2073657473206d696e6c65>-2.5 E -.15<7665>-.25 G 2.5<6c74>.15 G 2.5 +<6f30>-2.5 G<2e>-2.5 E F2108 576 Q -.1<7665>-.15 G<6c3d> +.1 E/F3 10/Times-Italic@0 SF<58>A F2<2d6d>108 592.8 Q F3<58>2.5 E F0 +1.143<536574206d696e696d756d207269736b206c65>39.73 F -.15<7665>-.25 G +3.643<6c74>.15 G 3.642<6f5866>-3.643 G 1.142 +<6f7220696e636c7573696f6e20696e206869746c6973742e>-3.642 F 1.142 +<546869732063616e2062652066726f6d2030202860>6.142 F 1.142 +<606e6f207269736b27>-.74 F 1.142<272920746f2035>-.74 F<2860>168 604.8 Q +<606d6178696d756d207269736b27>-.74 E<27293b2074686520646566>-.74 E +<61756c7420697320312e>-.1 E F2108 633.6 Q +-.1<7665>-.1 G108 650.4 Q F0 .736 +<446f206e6f7420696e636c7564652068697473207468617420617265206c696b>48.19 +F .737<656c7920746f2062652066>-.1 F .737<616c736520706f73697469>-.1 F +-.15<7665>-.25 G 3.237<732e2043757272656e746c79>.15 F 3.237<2c74>-.65 G +.737<686973206d65616e7320746861742066756e6374696f6e>-3.237 F 1.12 +<6e616d6573206172652069676e6f72656420696620746865>168 662.4 R<7927>-.15 +E 1.12<7265206e6f7420666f6c6c6f>-.5 F 1.12<776564206279202228222c20616e +642074686174206465636c61726174696f6e73206f662063686172616374657220617272 +617973>-.25 F<6172656e27>168 674.4 Q 3.34<746e>-.18 G 3.34 +<6f7465642e20546875732c>-3.34 F .84<696620796f75206861>3.34 F 1.141 -.15 +<76652075>-.2 H .841<736520612076>.15 F .841 +<61726961626c65206e616d65642022616363657373222065>-.25 F -.15<7665>-.25 +G .841<727977686572652c20746869732077696c6c20656c696d692d>.15 F .928 +<6e617465207265666572656e63657320746f2074686973206f7264696e6172792076> +168 686.4 R 3.428<61726961626c652e2054686973>-.25 F<69736e27>3.428 E +3.428<7474>-.18 G .928<686520646566>-3.428 F .927 +<61756c742c2062656361757365207468697320616c736f20696e63726561736573>-.1 +F .279<746865206c696b>168 698.4 R .279<656c69686f6f64206f66206d69737369 +6e6720696d706f7274616e7420686974733b20696e20706172746963756c6172>-.1 F +2.779<2c66>-.4 G .28 +<756e6374696f6e206e616d657320696e202364658c6e6520636c617573657320616e64> +-2.779 F<63616c6c73207468726f7567682066756e6374696f6e20706f696e74657273 +2077696c6c206265206d69737365642e>168 710.4 Q<466c61>72 768 Q 161.655 +<778c6e646572203330>-.15 F<4d61792032303034>2.5 E<33>202.335 E 0 Cg EP +%%Page: 4 4 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF<464c41>72 48 Q 134.71 +<5746494e44455228312920466c61>-.9 F 134.71<778c6e64657220464c41>-.15 F +<5746494e444552283129>-.9 E/F1 10/Times-Bold@0 SF108 84 Q -.1 +<7665>-.15 G<7269676e6f72>.1 E<65>-.18 E<2d6e>108 100.8 Q F0<4e65>51.11 +E -.15<7665>-.25 G 2.5<7269>.15 G +<676e6f7265207365637572697479206973737565732c2065>-2.5 E -.15<7665>-.25 +G 2.5<6e69>.15 G 2.5<6674>-2.5 G<6865>-2.5 E 2.5<7968>-.15 G -2.25 -.2 +<61762065>-2.5 H<616e2060>2.7 E<6069676e6f726527>-.74 E 2.5<2764>-.74 G +<697265637469>-2.5 E .3 -.15<76652069>-.25 H 2.5<6e6163>.15 G +<6f6d6d656e742e>-2.5 E F1<53656c656374696e67204f75747075742046>87 141.6 +Q<6f726d6174>-.25 E108 153.6 Q108 170.4 Q F0 +<53686f>47.08 E 4.024<7774>-.25 G 1.524<686520636f6c756d6e206e756d626572 +202861732077656c6c20617320746865208c6c65206e616d6520616e64206c696e65206e +756d62657229206f662065616368206869743b2074686973206973>-4.024 F<73686f> +168 182.4 Q .609<776e20616674657220746865206c696e65206e756d626572206279 +20616464696e67206120636f6c6f6e20616e642074686520636f6c756d6e206e756d6265 +7220696e20746865206c696e652028746865208c727374>-.25 F .562<636861726163 +74657220696e2061206c696e6520697320636f6c756d6e206e756d6265722031292e>168 +194.4 R .562<546869732069732075736566756c20666f7220656469746f7273207468 +61742063616e206a756d7020746f2073706563698c63>5.562 F 1.374 +<636f6c756d6e732c206f7220666f7220696e7465>168 206.4 R 1.375<67726174696e +672077697468206f7468657220746f6f6c732028737563682061732074686f736520746f +2066757274686572208c6c746572206f75742066>-.15 F 1.375 +<616c736520706f73692d>-.1 F<7469>168 218.4 Q -.15<7665>-.25 G<73292e>.15 +E F1108 247.2 Q108 264 Q F0<53686f>49.86 E +4.25<7763>-.25 G<6f6e7465>-4.25 E 1.75 +<78742c20692e652e2c20746865206c696e65206861>-.15 F 1.749 +<76696e67207468652022686974222f706f74656e7469616c208d61>-.2 F 5.549 -.65 +<772e2042>-.15 H 4.249<7964>.65 G<6566>-4.249 E 1.749 +<61756c7420746865206c696e652069732073686f>-.1 F<776e>-.25 E +<696d6d6564696174656c79206166746572207468652077>168 276 Q +<61726e696e672e>-.1 E F1108 304.8 Q108 321.6 +Q F0<446f6e27>47.08 E 2.5<7464>-.18 G +<6973706c6179207468652068656164657220616e6420666f6f746572>-2.5 E 5<2e55> +-.55 G<7365207468697320616c6f6e67207769746820adad717569657420746f207365 +65206a75737420746865206461746120697473656c662e>-5 E F1108 +350.4 Q F0 -.15<466f>28.6 G<726d617420746865206f75747075742061732048544d +4c20696e7374656164206f662061732073696d706c65207465>.15 E<78742e>-.15 E +F1108 379.2 Q<2d69>108 396 Q F0 +<496d6d6564696174656c7920646973706c617920686974732028646f6e27>53.89 E +2.5<746a>-.18 G<7573742077>-2.5 E +<61697420756e74696c2074686520656e64292e>-.1 E F1 +108 424.8 Q<2d53>108 441.6 Q F0 1.267 +<446973706c61792061732073696e676c65206c696e65206f66207465>51.11 F 1.267 +<7874206f757470757420666f722065616368206869742e>-.15 F 1.267<5573656675 +6c20666f7220696e746572616374696e67207769746820636f6d70696c6174696f6e> +6.267 F<746f6f6c732e>168 453.6 Q F1108 482.4 Q F0 +.82<4f6d69742074696d696e6720696e666f726d6174696f6e2e>10.28 F .82 +<546869732069732075736566756c20666f72207265>5.82 F .82 +<6772657373696f6e207465737473206f66208d61>-.15 F .82 +<778c6e64657220697473656c662c20736f207468617420746865>-.15 F +<6f757470757420646f65736e27>168 494.4 Q 2.5<7476>-.18 G +<61727920646570656e64696e67206f6e20686f>-2.75 E 2.5<776c>-.25 G +<6f6e672074686520616e616c797369732074616b>-2.5 E<65732e>-.1 E F1 +108 523.2 Q108 540 Q F0<446f6e27>46.52 E 3.152 +<7464>-.18 G .652<6973706c61792073746174757320696e666f726d6174696f6e2028 +692e652e2c207768696368208c6c657320617265206265696e672065>-3.152 F .653 +<78616d696e656429207768696c652074686520616e616c79736973206973>-.15 F +<676f696e67206f6e2e>168 552 Q F1<4869746c697374204d616e6167656d656e74>87 +592.8 Q108 604.8 Q -.1<7665>-.25 G<6869746c6973743d>.1 E/F2 10 +/Times-Italic@0 SF<46>A F0<5361>168 616.8 Q .3 -.15<76652061>-.2 H<6c6c +20726573756c74696e672068697473202874686520226869746c697374222920746f2046> +.15 E<2e>-.8 E F1108 645.6 Q F2<46>A F0<4c +6f616420746865206869746c6973742066726f6d204620696e7374656164206f6620616e +616c797a696e6720736f757263652070726f6772616d732e>168 657.6 Q F1 +108 686.4 Q F2<46>A F0<53686f>168 698.4 Q +3.54<776f>-.25 G 1.039<6e6c79206869747320286c6f61646564206f7220616e616c +797a656429206e6f7420696e2046>-3.54 F 6.039<2e46>-.8 G -.1<7761>-2.5 G +3.539<7370>.1 G 1.039<726573756d61626c79206372656174656420707265>-3.539 +F 1.039<76696f75736c79207573696e67>-.25 F168 710.4 Q -.15 +<7665>-.2 G 3.178<6869746c6973742e204966>.15 F .678 +<74686520adad6c6f61646869746c697374206f7074696f6e206973206e6f742070726f> +3.178 F .679<76696465642c20746869732077696c6c2073686f>-.15 F 3.179<7774> +-.25 G .679<6865206869747320696e2074686520616e612d>-3.179 F .084<6c797a +656420736f7572636520636f6465208c6c657320746861742077657265206e6f74207072 +65>168 722.4 R .083<76696f75736c792073746f72656420696e2046>-.25 F 5.083 +<2e49>-.8 G 2.583<6675>-5.083 G .083 +<73656420616c6f6e67207769746820adad6c6f61646869746c6973742c>-2.583 F +<466c61>72 768 Q 161.655<778c6e646572203330>-.15 F<4d61792032303034>2.5 +E<34>202.335 E 0 Cg EP +%%Page: 5 5 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF<464c41>72 48 Q 134.71 +<5746494e44455228312920466c61>-.9 F 134.71<778c6e64657220464c41>-.15 F +<5746494e444552283129>-.9 E .039<746869732077696c6c2073686f>168 84 R +2.539<7774>-.25 G .039<6865206869747320696e20746865206c6f61646564206869 +746c697374206e6f7420696e2046>-2.539 F 5.04<2e54>-.8 G .04<686520646966> +-5.04 F .04<666572656e636520616c676f726974686d20697320636f6e73657276> +-.25 F<617469>-.25 E -.15<7665>-.25 G<3b>.15 E 1.112 +<6869747320617265206f6e6c7920636f6e73696465726564207468652060>168 96 R +<6073616d6527>-.74 E 3.612<2769>-.74 G 3.611<6674>-3.612 G<6865>-3.611 E +3.611<7968>-.15 G -2.25 -.2<61762065>-3.611 H 1.111 +<7468652073616d65208c6c656e616d652c206c696e65206e756d626572>3.811 F +3.611<2c63>-.4 G<6f6c756d6e>-3.611 E<706f736974696f6e2c2066756e6374696f +6e206e616d652c20616e64207269736b206c65>168 108 Q -.15<7665>-.25 G<6c2e> +.15 E/F1 10.95/Times-Bold@0 SF<4558414d504c4553>72 148.8 Q F0 .225 +<48657265206172652076>108 160.8 R .225<6172696f75732065>-.25 F .225 +<78616d706c6573206f6620686f>-.15 F 2.725<7774>-.25 G 2.725<6f69>-2.725 G +-1.9 -.4<6e76206f>-2.725 H .425 -.1<6b65208d>.4 H -.15<6177>.1 G +<8c6e646572>.15 E 5.225<2e54>-.55 G .225<6865208c7273742065>-5.225 F +.226<78616d706c65732073686f>-.15 F 2.726<7776>-.25 G .226 +<6172696f75732073696d706c6520636f6d6d616e642d>-2.976 F 1.274 +<6c696e65206f7074696f6e732e>108 172.8 R<466c61>6.274 E 1.274 +<778c6e6465722069732064657369676e656420746f2077>-.15 F 1.274 +<6f726b2077656c6c2077697468207465>-.1 F 1.273 +<787420656469746f727320616e6420696e7465>-.15 F 1.273<677261746564206465> +-.15 F -.15<7665>-.25 G 1.273<6c6f706d656e7420656e>.15 F<7669726f6e2d> +-.4 E<6d656e74732c20736f20746865206e65>108 184.8 Q +<78742073656374696f6e732073686f>-.15 E 2.5<7768>-.25 G .5 -.25<6f772074> +-2.5 H 2.5<6f69>.25 G<6e7465>-2.5 E<6772617465208d61>-.15 E +<778c6e64657220696e746f2076696d20616e6420656d6163732e>-.15 E/F2 10 +/Times-Bold@0 SF<53696d706c6520636f6d6d616e642d6c696e65206f7074696f6e73> +87 213.6 Q<8d61778c6e646572202f7573722f7372>108 225.6 Q +<632f6c696e75782d322e342e3132>-.18 E F0 1.08<4578616d696e6520616c6c2074 +686520432f432b2b208c6c657320696e20746865206469726563746f7279202f7573722f +7372632f6c696e75782d322e342e313220616e6420616c6c206974732073756264697265 +63746f72696573>168 237.6 R<2872656375727369>168 249.6 Q -.15<7665>-.25 G +<6c79292c207265706f7274696e67206f6e20616c6c206869747320666f756e642e>.15 +E F2<8d61778c6e64657220adad6d696e6c65>108 278.4 Q -.1<7665>-.15 G +<6c3d34202e>.1 E F0 .154<4578616d696e6520616c6c2074686520432f432b2b208c +6c657320696e207468652063757272656e74206469726563746f727920616e6420697473 +207375626469726563746f72696573202872656375727369>168 290.4 R -.15<7665> +-.25 G .153<6c79293b206f6e6c79>.15 F +<7265706f72742076756c6e65726162696c6974696573206c65>168 302.4 Q -.15 +<7665>-.25 G 2.5<6c3461>.15 G<6e642075702028746865207477>-2.5 E 2.5 +<6f68>-.1 G<696768657374207269736b206c65>-2.5 E -.15<7665>-.25 G +<6c73292e>.15 E F2<8d61778c6e64657220adad696e70757473206d79646972>108 +331.2 Q F0 1.03<4578616d696e6520616c6c2074686520432f432b2b208c6c65732069 +6e206d7964697220616e6420697473207375626469726563746f72696573202872656375 +727369>168 343.2 R -.15<7665>-.25 G 1.03 +<6c79292c20616e64207265706f72742066756e632d>.15 F +<74696f6e7320746861742074616b>168 355.2 Q 2.5<6569>-.1 G<6e707574732028 +736f207468617420796f752063616e20656e73757265207468617420746865>-2.5 E +2.5<798c>-.15 G +<6c7465722074686520696e7075747320617070726f7072696174656c79292e>-2.5 E +F2<8d61778c6e64657220adad6e65>108 384 Q -.1<7665>-.15 G<7269676e6f72>.1 +E 2.5<656d>-.18 G<79646972>-2.5 E F0 .3<4578616d696e6520616c6c2074686520 +432f432b2b208c6c657320696e20746865206469726563746f7279206d7964697220616e +6420697473207375626469726563746f726965732c20696e636c7564696e672065>168 +396 R -.15<7665>-.25 G 2.8<6e74>.15 G<6865>-2.8 E<68697473206d61726b>168 +408 Q<656420666f722069676e6f72696e6720696e2074686520636f646520636f6d6d65 +6e74732e>-.1 E F2<8d61778c6e646572202d5144206d79646972>108 436.8 Q F0 +.092<4578616d696e65206d7964697220616e64207265706f7274206f6e6c7920746865 +2061637475616c20726573756c7473202872656d6f>168 448.8 R .093<76696e672074 +68652068656164657220616e6420666f6f746572206f6620746865206f75742d>-.15 F +2.603<707574292e2054686973>168 460.8 R .103<666f726d2069732075736566756c +20696620746865206f75747075742077696c6c20626520706970656420696e746f206f74 +68657220746f6f6c7320666f72206675727468657220616e616c797369732e>2.603 F +<546865>5.102 E .78168 472.8 R .78<726520706970696e67207468652064617461> +-.5 F<696e746f206f7468657220746f6f6c732e>168 484.8 Q F2<8d61778c6e646572 +20adad717569657420adad68746d6c20adad636f6e74657874206d79646972203e2072> +108 513.6 Q<6573756c74732e68746d6c>-.18 E F0 1.185<4578616d696e6520616c +6c2074686520432f432b2b208c6c657320696e20746865206469726563746f7279206d79 +64697220616e6420697473207375626469726563746f726965732c20616e642070726f64 +75636520616e>168 525.6 R .277<48544d4c20666f726d61747465642076>168 537.6 +R .277<657273696f6e206f662074686520726573756c74732e>-.15 F .278<536f7572 +636520636f6465206d616e6167656d656e742073797374656d7320287375636820617320 +536f757263652d>5.277 F -.15<466f>168 549.6 S -.18<7267>.15 G 2.5<6561> +.18 G<6e64205361>-2.5 E -.25<7661>-.2 G +<6e6e616829206d6967687420757365206120636f6d6d616e64206c696b>.25 E 2.5 +<6574>-.1 G<6869732e>-2.5 E F2 +<8d61778c6e64657220adad717569657420adad7361>108 578.4 Q -.1<7665>-.25 G +<6869746c697374207361>.1 E -.1<7665>-.25 G<642e68697473202a2e5b63685d>.1 +E F0 .406<4578616d696e6520616c6c202e6320616e64202e68208c6c657320696e2074 +68652063757272656e74206469726563746f7279>168 590.4 R 5.406<2e44>-.65 G +<6f6e27>-5.406 E 2.906<7472>-.18 G .406 +<65706f7274206f6e2074686520737461747573206f662070726f63657373696e672c> +-2.906 F<616e64207361>168 602.4 Q .3 -.15<76652074>-.2 H<68652072657375 +6c74696e67206869746c697374202874686520736574206f6620616c6c20686974732920 +696e20746865208c6c65207361>.15 E -.15<7665>-.2 G<642e686974732e>.15 E F2 +<8d61778c6e64657220adad646966666869746c697374207361>108 631.2 Q -.1 +<7665>-.25 G<642e68697473202a2e5b63685d>.1 E F0 .324<4578616d696e652061 +6c6c202e6320616e64202e68208c6c657320696e207468652063757272656e7420646972 +6563746f7279>168 643.2 R 2.825<2c61>-.65 G .325<6e642073686f>-2.825 F +2.825<7761>-.25 G .625 -.15<6e792068>-2.825 H .325 +<697473207468617420776572656e27>.15 F 2.825<7461>-.18 G .325 +<6c726561647920696e>-2.825 F .921<746865208c6c65207361>168 655.2 R -.15 +<7665>-.2 G 3.421<642e686974732e2054686973>.15 F .921 +<63616e206265207573656420746f2073686f>3.421 F 3.421<776f>-.25 G .921 +<6e6c79207468652060>-3.421 F<606e65>-.74 E<7727>-.25 E 3.42<2776>-.74 G +.92<756c6e65726162696c697469657320696e2061206d6f64698c6564>-3.42 F +<70726f6772616d2c206966207361>168 667.2 Q -.15<7665>-.2 G +<642e686974732077>.15 E +<617320637265617465642066726f6d20746865206f6c6465722076>-.1 E<657273696f +6e206f66207468652070726f6772616d206265696e6720616e616c797a65642e>-.15 E +F2<496e>87 696 Q -.1<766f>-.4 G<6b696e67206672>.1 E<6f6d2076696d>-.18 E +F0 .177<546865207465>108 708 R .177<787420656469746f722076696d20696e636c +7564657320612022717569636b8c7822206d656368616e69736d20746861742077>-.15 +F .177<6f726b732077656c6c2077697468208d61>-.1 F<778c6e646572>-.15 E +2.677<2c73>-.4 G 2.677<6f74>-2.677 G .177 +<68617420796f752063616e20656173696c79>-2.677 F<766965>108 720 Q 2.5 +<7774>-.25 G<68652077>-2.5 E<61726e696e67206d6573736167657320616e64206a +756d7020746f207468652072656c65>-.1 E -.25<7661>-.25 G +<6e7420736f7572636520636f64652e>.25 E<466c61>72 768 Q 161.655 +<778c6e646572203330>-.15 F<4d61792032303034>2.5 E<35>202.335 E 0 Cg EP +%%Page: 6 6 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF<464c41>72 48 Q 134.71 +<5746494e44455228312920466c61>-.9 F 134.71<778c6e64657220464c41>-.15 F +<5746494e444552283129>-.9 E .323 +<46697273742c20796f75206e65656420746f20696e>108 84 R -.2<766f>-.4 G .523 +-.1<6b65208d>.2 H -.15<6177>.1 G .322<8c6e64657220746f206372656174652061 +206c697374206f6620686974732c20616e6420746865726520617265207477>.15 F +2.822<6f77>-.1 G .322<61797320746f20646f20746869732e>-2.922 F .322 +<546865208c7273742077>5.322 F<6179>-.1 E .218 +<697320746f207374617274208d61>108 96 R .218<778c6e646572208c7273742c2061 +6e64207468656e20287573696e6720697473206f75747075742920696e>-.15 F -.2 +<766f>-.4 G .418 -.1<6b652076>.2 H 2.718<696d2e20546865>.1 F .218 +<7365636f6e642077>2.718 F .218 +<617920697320746f20737461727420286f7220636f6e74696e756520746f>-.1 F +<72756e292076696d2c20616e64207468656e20696e>108 108 Q -.2<766f>-.4 G .2 +-.1<6b65208d>.2 H -.15<6177>.1 G +<8c6e64657220287479706963616c6c792066726f6d20696e736964652076696d292e> +.15 E -.15<466f>108 124.8 S 3.072<7274>.15 G .572<6865208c7273742077> +-3.072 F<6179>-.1 E 3.072<2c72>-.65 G .572<756e208d61>-3.072 F .572<778c +6e64657220616e642073746f726520697473206f757470757420696e20736f6d6520464c +41>-.15 F .572<5746494c45202873617920228d61>-.9 F .571 +<778c6c6522292c207468656e20696e>-.15 F -.2<766f>-.4 G .771 -.1<6b652076> +.2 H<696d>.1 E .485<7573696e6720697473202d71206f7074696f6e2c206c696b>108 +136.8 R 2.986<6574>-.1 G .486<6869733a202276696d202d71208d61>-2.986 F +2.986<778c6c65222e20546865>-.15 F .486<7365636f6e642077>2.986 F .486 +<617920287374617274696e67208d61>-.1 F .486 +<778c6e646572206166746572207374617274696e672076696d292063616e>-.15 F +1.018<626520646f6e652061206c65>108 148.8 R 1.018<67696f6e206f662077>-.15 +F 3.518<6179732e204f6e65>-.1 F 1.018<697320746f20696e>3.518 F -.2<766f> +-.4 G 1.217 -.1<6b65208d>.2 H -.15<6177>.1 G 1.017 +<8c6e646572207573696e672061207368656c6c20636f6d6d616e642c20223a218d61> +.15 F<778c6e646572>-.15 E 1.017<2d636f6d6d616e64203e>-.2 F<464c41>108 +160.8 Q .251<5746494c45222c207468656e20666f6c6c6f>-.9 F 2.751<7774>-.25 +G .251<68617420776974682074686520636f6d6d616e6420223a636620464c41>-2.751 +F 2.751<5746494c45222e20416e6f74686572>-.9 F -.1<7761>2.751 G 2.752 +<7969>.1 G 2.752<7374>-2.752 G 2.752<6f73>-2.752 G .252 +<746f726520746865208d61>-2.752 F<778c6e646572>-.15 E +<636f6d6d616e6420696e20796f7572206d616b>108 172.8 Q +<658c6c65202861732c20736179>-.1 E 2.5<2c6170>-.65 G +<736575646f636f6d6d616e64206c696b>-2.5 E 2.5<6522>-.1 G<8d61>-2.5 E +<7722292c20616e64207468656e2072756e20223a6d616b>-.15 E 2.5<658d>-.1 G +-.15<6177>-2.5 G<222e>.15 E .417<496e20616c6c20746865736520636173657320 +796f75206e656564206120636f6d6d616e6420666f72208d61>108 189.6 R .417 +<778c6e64657220746f2072756e2e>-.15 F 2.917<4170>5.417 G .417<6c61757369 +626c6520636f6d6d616e642c20776869636820706c61636573206561636820686974> +-2.917 F<696e20697473206f>108 201.6 Q +<776e206c696e6520282d532920616e642072656d6f>-.25 E -.15<7665>-.15 G 2.5 +<7368>.15 G<65616465727320616e6420666f6f7465727320746861742077>-2.5 E +<6f756c6420636f6e667573652069742c2069733a>-.1 E/F1 10/Times-Bold@0 SF +<8d61778c6e64657220ad535144202e>108 218.4 Q F0 -1.1<596f>108 247.2 S +2.96<7563>1.1 G .46<616e206e6f>-2.96 F 2.96<7775>-.25 G .46<73652076> +-2.96 F .46 +<6172696f75732065646974696e6720636f6d6d616e647320746f20766965>-.25 F +2.96<7774>-.25 G .46<686520726573756c74732e>-2.96 F .46 +<54686520636f6d6d616e6420223a636e2220646973706c61797320746865206e65>5.46 +F .46<7874206869743b>-.15 F .012 +<223a634e2220646973706c6179732074686520707265>108 259.2 R .012 +<76696f7573206869742c20616e6420223a637222207265>-.25 F .012 +<77696e6473206261636b20746f20746865208c727374206869742e>-.25 F .011 +<223a636f70656e222077696c6c206f70656e20612077696e646f>5.011 F 2.511 +<7774>-.25 G 2.511<6f73>-2.511 G<686f>-2.511 E<77>-.25 E .202<7468652063 +757272656e74206c697374206f6620686974732c2063616c6c6564207468652022717569 +636b8c782077696e646f>108 271.2 R .202<77223b20223a63636c6f7365222077696c +6c20636c6f73652074686520717569636b8c782077696e646f>-.25 F 4.003 -.65 +<772e2049>-.25 H 2.703<6674>.65 G .203<68652062>-2.703 F<7566>-.2 E +<666572>-.25 E .25<696e2074686520757365642077696e646f>108 283.2 R 2.75 +<7768>-.25 G .25<6173206368616e6765642c20616e6420746865206572726f722069 +7320696e20616e6f74686572208c6c652c206a756d70696e6720746f2074686520657272 +6f722077696c6c2066>-2.75 F 2.75<61696c2e2059>-.1 F .25<6f75206861>-1.1 F +.55 -.15<76652074>-.2 H<6f>.15 E<6d616b>108 295.2 Q 2.587<6573>-.1 G +.087<757265207468652077696e646f>-2.587 F 2.587<7763>-.25 G .087 +<6f6e7461696e7320612062>-2.587 F<7566>-.2 E .088<6665722077686963682063 +616e206265206162616e646f6e6564206265666f726520747279696e6720746f206a756d +7020746f2061206e65>-.25 F 2.588<778c>-.25 G .088<6c652c20736179206279> +-2.588 F<7361>108 307.2 Q<76696e6720746865208c6c653b207468697320707265> +-.2 E -.15<7665>-.25 G +<6e7473206163636964656e74616c2064617461206c6f73732e>.15 E F1<496e>87 336 +Q -.1<766f>-.4 G<6b696e67206672>.1 E<6f6d20656d616373>-.18 E F0 .27 +<546865207465>108 348 R .269<787420656469746f72202f206f7065726174696e67 +2073797374656d20656d61637320696e636c75646573202267726570206d6f6465222061 +6e642022636f6d70696c65206d6f646522206d656368616e69736d7320746861742077> +-.15 F<6f726b>-.1 E .824<77656c6c2077697468208d61>108 360 R +<778c6e646572>-.15 E 3.324<2c6d>-.4 G .824 +<616b696e67206974206561737920746f20766965>-3.324 F 3.324<7777>-.25 G +.824<61726e696e67206d657373616765732c206a756d7020746f207468652072656c65> +-3.424 F -.25<7661>-.25 G .824 +<6e7420736f7572636520636f64652c20616e64208c78>.25 F<616e>108 372 Q 2.5 +<7970>-.15 G<726f626c656d7320796f75208c6e642e>-2.5 E 1.427 +<46697273742c20796f75206e65656420746f20696e>108 388.8 R -.2<766f>-.4 G +1.627 -.1<6b65208d>.2 H -.15<6177>.1 G 1.427 +<8c6e64657220746f206372656174652061206c697374206f662077>.15 F 1.427 +<61726e696e67206d657373616765732e>-.1 F -1.1<596f>6.426 G 3.926<7563>1.1 +G 1.426<616e20757365202267726570206d6f646522206f72>-3.926 F 2.645 +<22636f6d70696c65206d6f64652220746f206372656174652074686973206c6973742e> +108 400.8 R 2.645 +<4f6674656e202267726570206d6f646522206973206d6f726520636f6e>7.645 F -.15 +<7665>-.4 G 2.646<6e69656e743b206974206c6561>.15 F -.15<7665>-.2 G 5.146 +<7363>.15 G 2.646<6f6d70696c65206d6f6465>-5.146 F .537<756e746f75636865 +6420736f20796f752063616e20656173696c79207265636f6d70696c65206f6e63652079 +6f7527>108 412.8 R .837 -.15<76652063>-.5 H .537 +<68616e67656420736f6d657468696e672e>.15 F<486f>5.537 E<7765>-.25 E -.15 +<7665>-.25 G 1.337 -.4<722c2069>.15 H 3.037<6679>.4 G .537<6f752077> +-3.037 F .536<616e7420746f206a756d7020746f>-.1 F .509<7468652065>108 +424.8 R .509<7861637420636f6c756d6e20706f736974696f6e206f66206120686974 +2c20636f6d70696c65206d6f6465206d6179206265206d6f726520636f6e>-.15 F -.15 +<7665>-.4 G .51<6e69656e74206265636175736520656d6163732063616e2075736520 +74686520636f6c2d>.15 F<756d6e206f7574707574206f66208d61>108 436.8 Q<778c +6e64657220746f206469726563746c79206a756d7020746f20746865207269676874206c +6f636174696f6e20776974686f757420616e>-.15 E 2.5<7973>-.15 G +<70656369616c20636f6e8c6775726174696f6e2e>-2.5 E 2.065 -.8<546f2075>108 +453.6 T .465<73652067726570206d6f64652c20656e7465722074686520636f6d6d61 +6e6420224d2d7820677265702220616e64207468656e20656e74657220746865206e6565 +646564208d61>.8 F .464<778c6e64657220636f6d6d616e642e>-.15 F 2.064 -.8 +<546f2075>5.464 H<7365>.8 E 1.307<636f6d70696c65206d6f64652c20656e746572 +2074686520636f6d6d616e6420224d2d7820636f6d70696c652220616e6420656e746572 +20746865206e6565646564208d61>108 465.6 R 1.308 +<778c6e64657220636f6d6d616e642e>-.15 F 1.308<546869732069732061>6.308 F +<6d6574612d6b>108 477.6 Q .437 -.15<65792063>-.1 H .137 +<6f6d6d616e642c20736f20796f7527>.15 F .137 +<6c6c206e65656420746f2075736520746865206d657461206b>-.1 F .437 -.15 +<65792066>-.1 H .137<6f7220796f7572206b>.15 F -.15<6579>-.1 G .137 +<626f61726420287468697320697320757375616c6c792074686520455343206b>.15 F +-.15<6579>-.1 G 2.636<292e204173>.15 F 1.015 +<7769746820616c6c20656d61637320636f6d6d616e64732c20796f7527>108 489.6 R +1.016<6c6c206e65656420746f2070726573732052455455524e20616674657220747970 +696e6720226772657022206f722022636f6d70696c65222e>-.1 F 1.016 +<536f206f6e206d616e>6.016 F<79>-.15 E +<73797374656d732c207468652067726570206d6f646520697320696e>108 501.6 Q +-.2<766f>-.4 G -.1<6b65>.2 G 2.5<6462>.1 G 2.5<7974>-2.5 G +<7970696e6720455343207820672072206520702052455455524e2e>-2.5 E -1.1 +<596f>108 518.4 S 3.564<7574>1.1 G 1.063 +<68656e206e65656420746f20656e746572206120636f6d6d616e642c2072656d6f> +-3.564 F 1.063<76696e67207768617465>-.15 F -.15<7665>-.25 G 3.563<7277> +.15 G 1.063<6173207468657265206265666f7265206966206e6563657373617279> +-3.663 F 6.063<2e41>-.65 G 1.063<706c61757369626c6520636f6d2d>-2.5 F +<6d616e642069733a>108 530.4 Q F1<8d61778c6e64657220ad53514443202e>108 +547.2 Q F0 .134<5468697320636f6d6d616e64206d616b>108 564 R .134 +<65732065>-.1 F -.15<7665>-.25 G .135<727920686974207265706f727420612073 +696e676c65206c696e652c207768696368206973206d7563682065617369657220666f72 +20746f6f6c7320746f2068616e646c652e>.15 F .135 +<54686520717569657420616e64>5.135 F .546 +<646174616f6e6c79206f7074696f6e732072656d6f>108 576 R .846 -.15 +<76652074>-.15 H .546<6865206f746865722073746174757320696e666f726d617469 +6f6e206e6f74206e656564656420666f722075736520696e7369646520656d6163732e> +.15 F .546<54686520747261696c696e6720706572696f64>5.546 F<6d65616e732074 +686174207468652063757272656e74206469726563746f727920616e6420616c6c206465 +7363656e64656e74732061726520736561726368656420666f7220432f432b2b20636f64 +652c20616e6420616e616c797a656420666f72208d61>108 588 Q<77732e>-.15 E +1.311<4f6e636520796f7527>108 604.8 R 1.611 -.15<76652069>-.5 H -1.9 -.4 +<6e76206f>.15 H -.1<6b65>.4 G 3.811<648d>.1 G -.15<6177>-3.811 G +<8c6e646572>.15 E 3.811<2c79>-.4 G 1.311<6f752063616e2075736520656d6163 +7320746f206a756d702061726f756e6420696e2069747320726573756c74732e>-3.811 +F 1.312<54686520636f6d6d616e6420432d782092>6.311 F 1.248<28436f6e74726f +6c2d78206261636b7469636b29207669736974732074686520736f7572636520636f6465 +206c6f636174696f6e20666f7220746865206e65>108 616.8 R 1.247<78742077>-.15 +F 1.247<61726e696e67206d6573736167652e>-.1 F 1.247 +<432d7520432d7820922028636f6e74726f6c2d75>6.247 F .807<636f6e74726f6c2d +78206261636b7469636b292072657374617274732066726f6d20746865206265>108 +628.8 R 3.307<67696e6e696e672e2059>-.15 F .807 +<6f752063616e2076697369742074686520736f7572636520666f7220616e>-1.1 F +3.308<7970>-.15 G .808<6172746963756c6172206572726f72206d657373616765> +-3.308 F 1.641<6279206d6f>108 640.8 R 1.641<76696e6720746f20746861742068 +6974206d65737361676520696e20746865202a636f6d70696c6174696f6e2a2062>-.15 +F<7566>-.2 E 1.64<666572206f72202a677265702a2062>-.25 F<7566>-.2 E 1.64 +<66657220616e6420747970696e67207468652072657475726e206b>-.25 F -.15 +<6579>-.1 G<2e>-.5 E<2854>108 652.8 Q 2.81 +<6563686e6963616c206e6f74653a20696e2074686520636f6d70696c6174696f6e2062> +-.7 F<7566>-.2 E<666572>-.25 E 5.31<2c74>-.4 G 2.81<68697320696e>-5.31 F +-.2<766f>-.4 G -.1<6b65>.2 G 5.31<7363>.1 G 5.31 +<6f6d70696c652d676f746f2d6572726f72292e2059>-5.31 F 2.81 +<6f752063616e20616c736f20636c69636b20746865>-1.1 F .094 +<4d6f7573652d322062>108 664.8 R .094<7574746f6e206f6e20746865206572726f +72206d65737361676520287768656e207573696e6720746865206d6f75736520796f7520 +646f6e27>-.2 F 2.593<746e>-.18 G .093 +<65656420746f2073776974636820746f20746865202a636f6d70696c6174696f6e2a> +-2.593 F -.2<6275>108 676.8 S -.25<6666>.2 G<6572208c727374292e>.25 E +.237<496620796f752077>108 693.6 R .237<616e7420746f20757365206772657020 +6d6f646520746f206a756d7020746f2073706563698c6320636f6c756d6e73206f662061 +206869742c20796f7527>-.1 F .238 +<6c6c206e65656420746f207370656369616c6c7920636f6e8c6775726520656d616373> +-.1 F 1.279<746f20646f20746869732e>108 705.6 R 2.879 -.8<546f2064>6.279 +H 3.779<6f74>.8 G 1.279<6869732c206d6f646966792074686520656d6163732076> +-3.779 F 1.279<61726961626c652022677265702d7265>-.25 F<6765>-.15 E 3.779 +<78702d616c697374222e2054686973>-.15 F -.25<7661>3.779 G 1.278 +<726961626c652074656c6c7320456d61637320686f>.25 F 3.778<7774>-.25 G<6f> +-3.778 E .348<7061727365206f7574707574206f6620612022677265702220636f6d6d +616e642c2073696d696c617220746f207468652076>108 717.6 R .349 +<61726961626c652022636f6d70696c6174696f6e2d6572726f72>-.25 F<2d7265>-.2 +E<6765>-.15 E .349<78702d616c69737422207768696368206c697374732076>-.15 F +<6172692d>-.25 E<6f757320666f726d617473206f6620636f6d70696c6174696f6e20 +6572726f72206d657373616765732e>108 729.6 Q<466c61>72 768 Q 161.655 +<778c6e646572203330>-.15 F<4d61792032303034>2.5 E<36>202.335 E 0 Cg EP +%%Page: 7 7 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF<464c41>72 48 Q 134.71 +<5746494e44455228312920466c61>-.9 F 134.71<778c6e64657220464c41>-.15 F +<5746494e444552283129>-.9 E/F1 10.95/Times-Bold@0 SF<5345435552495459>72 +84 Q F0 -1.1<596f>108 96 S 2.859<7573>1.1 G .359<686f756c6420616c>-2.859 +F -.1<7761>-.1 G .359<797320616e616c797a652061>.1 F/F2 10/Times-Italic@0 +SF<636f7079>2.859 E F0 .359<6f662074686520736f757263652070726f6772616d20 +6265696e6720616e616c797a65642c206e6f742061206469726563746f72792074686174 +2063616e206265206d6f64692d>2.859 F .344<8c65642062792061206465>108 108 R +-.15<7665>-.25 G .344<6c6f706572207768696c65208d61>.15 F .344 +<778c6e64657220697320706572666f726d696e672074686520616e616c797369732e> +-.15 F .344<54686973206973>5.344 F F2<657370656369616c6c79>2.844 E F0 +.344<7472756520696620796f7520646f6e27>2.844 F 2.845<746e>-.18 G +<65636573732d>-2.845 E .807<696c792074727573742061206465>108 120 R -.15 +<7665>-.25 G .806<6c6f706572206f66207468652070726f6772616d206265696e6720 +616e616c797a65642e>.15 F .806<496620616e2061747461636b>5.806 F .806 +<65722068617320636f6e74726f6c206f>-.1 F -.15<7665>-.15 G 3.306<7274>.15 +G .806<6865208c6c6573207768696c6520796f7527>-3.306 F<7265>-.5 E .538 +<616e616c797a696e67207468656d2c207468652061747461636b>108 132 R .538 +<657220636f756c64206d6f>-.1 F .838 -.15<7665208c>-.15 H .538<6c65732061 +726f756e64206f72206368616e676520746865697220636f6e74656e747320746f207072 +65>.15 F -.15<7665>-.25 G .539<6e74207468652065>.15 F .539 +<78706f73757265206f662061>-.15 F .078<73656375726974792070726f626c656d20 +286f72206372656174652074686520696d7072657373696f6e206f6620612070726f626c +656d207768657265207468657265206973206e6f6e65292e>108 144 R .077 +<496620796f7527>5.077 F .077<72652077>-.5 F .077 +<6f72726965642061626f7574206d616c692d>-.1 F 1.017<63696f75732070726f6772 +616d6d65727320796f752073686f756c6420646f207468697320616e>108 156 R<7977> +-.15 E<6179>-.1 E 3.517<2c62>-.65 G 1.018 +<65636175736520616674657220616e616c7973697320796f7527>-3.517 F 1.018 +<6c6c206e65656420746f2076>-.1 F 1.018 +<657269667920746861742074686520636f6465>-.15 F -2.15 -.25<65762065>108 +168 T .711<6e7475616c6c792072756e2069732074686520636f646520796f7520616e +616c797a65642e>.25 F .711 +<416c736f2c20646f206e6f74207573652074686520adad616c6c6f>5.711 F .71 +<776c696e6b206f7074696f6e20696e20737563682063617365733b2061747461636b> +-.25 F<657273>-.1 E<636f756c6420637265617465206d616c6963696f75732073796d +626f6c6963206c696e6b7320746f208c6c6573206f757473696465206f66207468656972 +20736f7572636520636f64652061726561202873756368206173202f6574632f70617373 +7764292e>108 180 Q 1.591 +<536f7572636520636f6465206d616e6167656d656e742073797374656d7320286c696b> +108 196.8 R 4.091<6553>-.1 G<6f7572636546>-4.091 E<6f72>-.15 E 1.591 +<676520616e64205361>-.18 F -.25<7661>-.2 G 1.592 +<6e6e6168292064658c6e6974656c792066>.25 F 1.592 +<616c6c20696e746f20746869732063617465>-.1 F 1.592<676f72793b206966>-.15 +F<796f7527>108 208.8 Q .7<7265206d61696e7461696e696e67206f6e65206f662074 +686f73652073797374656d732c208c72737420636f70>-.5 F 3.199<796f>-.1 G +3.199<7265>-3.199 G .699<78747261637420746865208c6c657320696e746f206120 +7365706172617465206469726563746f72792028746861742063616e27>-3.349 F<74> +-.18 E<626520636f6e74726f6c6c65642062792061747461636b>108 220.8 Q +<65727329206265666f72652072756e6e696e67208d61>-.1 E +<778c6e646572206f7220616e>-.15 E 2.5<796f>-.15 G +<7468657220636f646520616e616c7973697320746f6f6c2e>-2.5 E 1.276 +<4e6f74652074686174208d61>108 237.6 R 1.276 +<778c6e646572206f6e6c79206f70656e73207265>-.15 F 1.276<67756c6172208c6c +65732c206469726563746f726965732c20616e6420286966207265717565737465642920 +73796d626f6c6963206c696e6b733b2069742077696c6c206e65>-.15 F -.15<7665> +-.25 G<72>.15 E 1.608 +<6f70656e206f74686572206b696e6473206f66208c6c65732c2065>108 249.6 R -.15 +<7665>-.25 G 4.107<6e69>.15 G 4.107<666173>-4.107 G 1.607 +<796d626f6c6963206c696e6b206973206d61646520746f207468656d2e>-4.107 F +1.607<5468697320636f756e746572732061747461636b>6.607 F 1.607 +<6572732077686f20696e73657274>-.1 F .363<756e757375616c208c6c6520747970 +657320696e746f2074686520736f7572636520636f64652e>108 261.6 R<486f>5.363 +E<7765>-.25 E -.15<7665>-.25 G 1.163 -.4<722c2074>.15 H .363 +<686973206f6e6c792077>.4 F .363<6f726b7320696620746865208c6c657379737465 +6d206265696e6720616e616c797a65642063616e27>-.1 F 2.863<7462>-.18 G<65> +-2.863 E .48<6d6f64698c656420627920616e2061747461636b>108 273.6 R .479< +657220647572696e672074686520616e616c797369732c206173207265636f6d6d656e64 +65642061626f>-.1 F -.15<7665>-.15 G 5.479<2e54>.15 G .479 +<6869732070726f74656374696f6e20616c736f20646f65736e27>-5.479 F 2.979 +<7477>-.18 G .479<6f726b206f6e>-3.079 F +<43796777696e20706c6174666f726d732c20756e666f7274756e6174656c79>108 +285.6 Q<2e>-.65 E .788<43796777696e2073797374656d732028556e697820656d75 +6c6174696f6e206f6e20746f70206f662057>108 302.4 R<696e646f>-.4 E .789 +<777329206861>-.25 F 1.089 -.15<76652061>-.2 H 3.289<6e61>.15 G .789 +<64646974696f6e616c2070726f626c656d206966208d61>-3.289 F .789 +<778c6e646572206973207573656420746f>-.15 F 1.427<616e616c797a652070726f +6772616d732074686520616e616c797a65722063616e6e6f742074727573742064756520 +746f20612064657369676e208d61>108 314.4 R 3.926<7769>-.15 G 3.926<6e57> +-3.926 G<696e646f>-4.326 E 1.426 +<777320287468617420697420696e6865726974732066726f6d204d532d>-.25 F 2.776 +<444f53292e204f6e>108 326.4 R -.4<5769>2.776 G<6e646f>.4 E .276<77732061 +6e64204d532d444f532c206365727461696e208c6c656e616d65732028652e672e2c2060> +-.25 F<60636f6d3127>-.74 E .277<272920617265206175746f6d61746963616c6c79 +207472656174656420627920746865206f706572>-.74 F<2d>-.2 E .853<6174696e67 +2073797374656d20617320746865206e616d6573206f66207065726970686572616c732c +20616e64207468697320697320747275652065>108 338.4 R -.15<7665>-.25 G +3.353<6e77>.15 G .853 +<68656e20612066756c6c20706174686e616d65206973206769>-3.353 F -.15<7665> +-.25 G 3.353<6e2e2059>.15 F .853<65732c2057>-1 F<696e2d>-.4 E<646f>108 +350.4 Q .054<777320616e64204d532d444f53207265616c6c79206172652064657369 +676e65642074686973206261646c79>-.25 F 5.054<2e46>-.65 G<6c61>-5.054 E +.055<778c6e646572206465616c732077697468207468697320627920636865636b696e +6720776861742061208c6c6573797374656d>-.15 F .394<6f626a6563742069732c20 +616e64207468656e206f6e6c79206f70656e696e67206469726563746f7269657320616e +64207265>108 362.4 R .394<67756c6172208c6c65732028616e642073796d6c696e6b +7320696620656e61626c6564292e>-.15 F<556e666f7274756e6174656c79>5.394 E +2.894<2c74>-.65 G<686973>-2.894 E<646f65736e27>108 374.4 Q 2.561<7477> +-.18 G .061 +<6f726b206f6e2043796777696e3b206f6e206174206c6561737420736f6d652076> +-2.661 F .061<657273696f6e73206f662043796777696e206f6e20736f6d652076> +-.15 F .061<657273696f6e73206f662057>-.15 F<696e646f>-.4 E .062 +<77732c206d6572656c7920747279696e67>-.25 F .395 +<746f2064657465726d696e652069662061208c6c652069732061206465>108 386.4 R +.394<7669636520747970652063616e206361757365207468652070726f6772616d2074 +6f2068616e672e>-.25 F 2.894<4177>5.394 G .394 +<6f726b61726f756e6420697320746f2064656c657465206f722072656e616d65>-2.994 +F<616e>108 398.4 Q 5.32<798c>-.15 G 2.821 +<6c656e616d657320746861742061726520696e746572707265746564206173206465> +-5.32 F 2.821<76696365206e616d6573206265666f726520706572666f726d696e6720 +74686520616e616c797369732e>-.25 F 2.821<546865736520736f2d63616c6c6564> +7.821 F -.74<6060>108 410.4 S<726573657276>.74 E .238 +<6564206e616d657327>-.15 F 2.738<2761>-.74 G .238 +<726520434f4e2c2050524e2c2041>-2.738 F .237<55582c20434c4f434b242c204e55 +4c2c20434f4d312d434f4d392c20616e64204c5054312d4c5054392c206f7074696f6e61 +6c6c7920666f6c2d>-.55 F<6c6f>108 422.4 Q<77656420627920616e2065>-.25 E +<7874656e73696f6e2028652e672e2c2060>-.15 E<60636f6d312e74787427>-.74 E +<27292c20696e20616e>-.74 E 2.5<7964>-.15 G<69726563746f7279>-2.5 E 2.5 +<2c61>-.65 G<6e6420696e20616e>-2.5 E 2.5<7963>-.15 G<617365202857>-2.5 E +<696e646f>-.4 E<777320697320636173652d696e73656e73697469>-.25 E -.15 +<7665>-.25 G<292e>.15 E F1 -.11<4255>72 463.2 S<4753>.11 E F0<466c61>108 +475.2 Q .781<778c6e6465722069732063757272656e746c79206c696d697465642074 +6f20432f432b2b2e>-.15 F<497427>5.781 E 3.281<7364>-.55 G .782<657369676e +656420736f207468617420616464696e6720737570706f727420666f72206f7468657220 +6c616e6775616765732073686f756c64>-3.281 F<62652065617379>108 487.2 Q<2e> +-.65 E<466c61>108 504 Q .813 +<778c6e6465722063616e20626520666f6f6c65642062792075736572>-.15 F .812<2d +64658c6e65642066756e6374696f6e73206f72206d6574686f64206e616d657320746861 +742068617070656e20746f206265207468652073616d652061732074686f7365>-.2 F +.185<64658c6e65642061732060>108 516 R<606869747327>-.74 E 2.685<2769> +-.74 G 2.685<6e69>-2.685 G .186<74732064617461626173652c20616e642077696c +6c206f6674656e2074726967676572206f6e2064658c6e6974696f6e7320286173207765 +6c6c206173207573657329206f662066756e6374696f6e73207769746820746865> +-2.685 F .564<73616d65206e616d652e>108 528 R .564 +<546869732069732062656361757365208d61>5.564 F .564 +<778c6e646572206973206261736564206f6e207465>-.15 F .563<7874207061747465 +726e206d61746368696e672c2077686963682069732070617274206f6620697473206675 +6e64616d656e74616c>-.15 F .098 +<64657369676e20616e64206e6f7420656173696c79206368616e6765642e>108 540 R +.098<546869732069736e27>5.098 F 2.598<7461>-.18 G 2.598<736d>-2.598 G +.099<756368206f6620612070726f626c656d20666f72204320636f64652c2062>-2.598 +F .099<75742069742063616e206265206d6f7265206f6620612070726f626c656d>-.2 +F .021<666f7220736f6d6520432b2b20636f646520776869636820686561>108 552 R +.021<76696c79207573657320636c617373657320616e64206e616d657370616365732e> +-.2 F .02<4f6e2074686520706f73697469>5.021 F .32 -.15<76652073>-.25 H +.02<6964652c208d61>.15 F .02<778c6e64657220646f65736e27>-.15 F 2.52 +<7467>-.18 G<6574>-2.52 E .45<636f6e6675736564206279206d616e>108 564 R +2.95<7963>-.15 G .45<6f6d706c6963617465642070726570726f636573736f722073 +657175656e6365732074686174206f7468657220746f6f6c7320736f6d6574696d657320 +63686f6b>-2.95 F 2.95<656f>-.1 G 2.95<6e2e20416c736f2c>-2.95 F<6861>2.95 +E<76696e67>-.2 E .059<7468652073616d65206e616d65206173206120636f6d6d6f6e +206c69627261727920726f7574696e65206e616d652063616e20696e6469636174652074 +68617420746865206465>108 576 R -.15<7665>-.25 G .059 +<6c6f7065722069732073696d706c79207265>.15 F .058 +<77726974696e67206120636f6d2d>-.25 F .217<6d6f6e206c69627261727920726f75 +74696e652c2073617920666f7220706f72746162696c69747927>108 588 R 2.717 +<7373>-.55 G<616b>-2.717 E 2.717<652e20546875732c>-.1 F .218<7468657265 +2061726520726561736f6e61626c65206f6464732074686174207468657365207265> +2.717 F .218<7772697474656e20726f7574696e6573>-.25 F .3<77696c6c20626520 +76756c6e657261626c6520746f207468652073616d65206b696e6473206f66206d697375 +73652e>108 600 R .3<54686520adad66>5.3 F<616c7365706f73697469>-.1 E .6 +-.15<7665206f>-.25 H .3<7074696f6e2063616e2068656c7020736f6d65>.15 F 2.8 +<776861742e204966>-.25 F .3<746869732069732061>2.8 F 1.04<736572696f7573 +2070726f626c656d2c206665656c206672656520746f206d6f6469667920746865207072 +6f6772616d2c206f722070726f6365737320746865208d61>108 612 R 1.041<778c6e +646572206f7574707574207468726f756768206f7468657220746f6f6c7320746f>-.15 +F<72656d6f>108 624 Q .3 -.15<76652074>-.15 H<68652066>.15 E +<616c736520706f73697469>-.1 E -.15<7665>-.25 G<732e>.15 E .025<50726570 +726f636573736f7220636f6d6d616e647320656d62656464656420696e20746865206d69 +64646c65206f66206120706172616d65746572206c697374206f6620612063616c6c2063 +616e2063617573652070726f626c656d7320696e2070617273696e672c>108 640.8 R +2.382<696e20706172746963756c6172>108 652.8 R 4.882<2c69>-.4 G 4.882 +<666173>-4.882 G 2.382<7472696e67206973206f70656e656420616e64207468656e +20636c6f736564206d756c7469706c652074696d6573207573696e6720616e2023696664 +6566202e2e2023656c736520636f6e7374727563742c>-4.882 F<8d61>108 664.8 Q +.073<778c6e646572206765747320636f6e66757365642e>-.15 F .073<537563682063 +6f6e737472756374732061726520626164207374796c652c20616e642077696c6c20636f +6e66757365206d616e>5.073 F 2.573<796f>-.15 G .073 +<7468657220746f6f6c7320746f6f2e>-2.573 F .073<496620796f75206d757374> +5.073 F<616e616c797a652073756368208c6c65732c207265>108 676.8 Q +<77726974652074686f7365206c696e65732e>-.25 E<5468616e6b66756c6c79>5 E +2.5<2c74>-.65 G<686573652061726520717569746520726172652e>-2.5 E .051<54 +686520726f7574696e6520746f2064657465637420737461746963616c6c792064658c6e +6564206368617261637465722061727261797320757365732073696d706c65207465>108 +693.6 R .052 +<7874206d61746368696e673b20736f6d6520636f6d706c6963617465642065>-.15 F +<787072652d>-.15 E<73696f6e732063616e20636175736520697420746f2074726967 +676572206f72206e6f74207472696767657220756e65>108 705.6 Q +<787065637465646c79>-.15 E<2e>-.65 E<466c61>108 722.4 Q .222<778c6e6465 +72206c6f6f6b7320666f722073706563698c63207061747465726e73206b6e6f>-.15 F +.221<776e20746f20626520636f6d6d6f6e206d697374616b>-.25 F 2.721 +<65732e20466c61>-.1 F .221<778c6e64657220286f7220616e>-.15 F 2.721<7974> +-.15 G .221<6f6f6c206c696b>-2.721 F 2.721<6569>-.1 G .221 +<7429206973206e6f74>-2.721 F<466c61>72 768 Q 161.655<778c6e646572203330> +-.15 F<4d61792032303034>2.5 E<37>202.335 E 0 Cg EP +%%Page: 8 8 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF<464c41>72 48 Q 134.71 +<5746494e44455228312920466c61>-.9 F 134.71<778c6e64657220464c41>-.15 F +<5746494e444552283129>-.9 E 2.572<6167>108 84 S .072<6f6f6420746f6f6c20 +666f72208c6e64696e6720696e74656e74696f6e616c6c79206d616c6963696f75732063 +6f64652028652e672e2c2054>-2.572 F .072<726f6a616e20686f72736573293b206d +616c6963696f75732070726f6772616d6d6572732063616e20656173696c79>-.35 F +<696e7365727420636f646520746861742077>108 96 Q<6f756c64206e6f7420626520 +64657465637465642062792074686973206b696e64206f6620746f6f6c2e>-.1 E +<466c61>108 112.8 Q .355<778c6e646572206c6f6f6b7320666f722073706563698c +63207061747465726e73206b6e6f>-.15 F .355 +<776e20746f20626520636f6d6d6f6e206d697374616b>-.25 F .355 +<657320696e206170706c69636174696f6e20636f64652e>-.1 F .355 +<546875732c206974206973206c696b>5.355 F<656c79>-.1 E .673 +<746f206265206c657373206566>108 124.8 R<6665637469>-.25 E .973 -.15 +<76652061>-.25 H .673 +<6e616c797a696e672070726f6772616d732074686174206172656e27>.15 F 3.174 +<7461>-.18 G .674 +<70706c69636174696f6e2d6c6179657220636f64652028652e672e2c206b>-3.174 F +.674<65726e656c20636f6465206f722073656c662d686f7374696e67>-.1 F 2.868 +<636f6465292e20546865>108 136.8 R .367<746563686e6971756573206d61792073 +74696c6c2062652075736566756c3b206665656c206672656520746f207265706c616365 +2074686520646174616261736520696620796f757220736974756174696f6e2069732073 +69676e698c63616e746c79>2.867 F<646966>108 148.8 Q +<666572656e742066726f6d206e6f726d616c2e>-.25 E<466c61>108 165.6 Q +<778c6e64657227>-.15 E 3.06<736f>-.55 G .561 +<757470757420666f726d617420288c6c656e616d653a6c696e656e756d626572>-3.06 +F 3.061<2c66>-.4 G<6f6c6c6f>-3.061 E .561<776564206f7074696f6e616c6c7920 +62792061203a636f6c756d6e6e756d626572292063616e206265206d6973756e2d>-.25 +F .509<64657273746f6f6420696620616e>108 177.6 R 3.009<7973>-.15 G .509 +<6f75726365208c6c6573206861>-3.009 F .809 -.15<7665207665>-.2 H .508 +<7279207765697264208c6c656e616d65732e>.15 F .508 +<46696c656e616d657320656d62656464696e672061206e65>5.508 F .508 +<776c696e652f6c696e656665656420636861726163746572>-.25 F .499<77696c6c20 +6361757365206f646420627265616b732c20616e64208c6c656e616d657320696e636c75 +64696e6720636f6c6f6e20283a2920617265206c696b>108 189.6 R .499 +<656c7920746f206265206d6973756e64657273746f6f642e>-.1 F .499 +<5468697320697320657370656369616c6c79>5.499 F .111 +<696d706f7274616e74206966208d61>108 201.6 R<778c6e64657227>-.15 E 2.611 +<736f>-.55 G .111<7574707574206973206265696e672075736564206279206f746865 +7220746f6f6c732c2073756368206173208c6c74657273206f72207465>-2.611 F .11 +<787420656469746f72732e>-.15 F .11<496620796f7527>5.11 F .11 +<7265206c6f6f6b696e67>-.5 F .661<6174206e65>108 213.6 R 3.161<7763>-.25 +G .662<6f64652c2065>-3.161 F .662<78616d696e6520746865208c6c657320666f72 +207375636820636861726163746572732e>-.15 F<497427>5.662 E 3.162<7369>-.55 +G .662<6e6372656469626c7920756e7769736520746f206861>-3.162 F .962 -.15 +<76652073>-.2 H .662<756368208c6c656e616d657320616e>.15 F<7977>-.15 E +<61793b>-.1 E<6d616e>108 225.6 Q 2.805<7974>-.15 G .305 +<6f6f6c732063616e27>-2.805 F 2.804<7468>-.18 G .304 +<616e646c652073756368208c6c656e616d657320617420616c6c2e>-2.804 F<4e65> +5.304 E .304<776c696e6520616e64206c696e656665656420617265206f6674656e20 +7573656420617320696e7465726e616c20646174612064656c696d652d>-.25 F 3.332 +<746572732e20546865>108 237.6 R .832<636f6c6f6e206973206f6674656e207573 +6564206173207370656369616c206368617261637465727320696e208c6c657379737465 +6d733a204d61634f5320757365732069742061732061206469726563746f727920736570 +617261746f72>3.332 F<2c>-.4 E -.4<5769>108 249.6 S<6e646f>.4 E .029 +<77732f4d532d444f53207573657320697420746f206964656e7469667920647269>-.25 +F .329 -.15<7665206c>-.25 H .028<6574746572732c2057>.15 F<696e646f>-.4 E +.028<77732f4d532d444f5320696e636f6e73697374656e746c79207573657320697420 +746f206964656e74696679207370652d>-.25 F 1.168<6369616c206465>108 261.6 R +1.168<7669636573206c696b>-.25 F 3.668<6543>-.1 G 1.168 +<4f4e3a2c20616e64206170706c69636174696f6e73206f6e206d616e>-3.668 F 3.669 +<7970>-.15 G 1.169<6c6174666f726d73207573652074686520636f6c6f6e20746f20 +6964656e7469667920555249732f55524c732e>-3.669 F<46696c652d>6.169 E .37< +6e616d657320696e636c7564696e672073706163657320616e642f6f7220746162732064 +6f6e27>108 273.6 R 2.87<7463>-.18 G .37 +<617573652070726f626c656d7320666f72208d61>-2.87 F<778c6e646572>-.15 E +2.87<2c74>-.4 G .37 +<686f756768206e6f74652074686174206f7468657220746f6f6c73206d69676874> +-2.87 F<6861>108 285.6 Q .3 -.15<76652070>-.2 H +<726f626c656d732077697468207468656d2e>.15 E .132 +<496e2067656e6572616c2c208d61>108 302.4 R .133<778c6e64657220617474656d +70747320746f20657272206f6e207468652073696465206f662063617574696f6e3b2069 +742074656e647320746f207265706f727420686974732c20736f207468617420746865> +-.15 F 2.633<7963>-.15 G .133<616e2062652065>-2.633 F<78616d2d>-.15 E +.398<696e65642066757274686572>108 314.4 R 2.898<2c69>-.4 G .398 +<6e7374656164206f662073696c656e746c792069676e6f72696e67207468656d2e> +-2.898 F .397<546875732c208d61>5.397 F .397 +<778c6e646572207072656665727320746f206861>-.15 F .697 -.15<76652066>-.2 +H .397<616c736520706f73697469>.05 F -.15<7665>-.25 G 2.897<7328>.15 G +.397<7265706f7274732074686174>-2.897 F .74<7475726e206f757420746f206e6f +742062652070726f626c656d732920726174686572207468616e2066>108 326.4 R +.741<616c7365206e65>-.1 F -.05<6761>-.15 G<7469>.05 E -.15<7665>-.25 G +3.241<7328>.15 G -.1<6661>-3.241 G .741<696c75726520746f207265706f727420 +6f6e20612073656375726974792076756c6e65726162696c697479292e>.1 F<427574> +5.741 E<7468697320697320612067656e6572616c6974793b208d61>108 338.4 Q<77 +8c6e64657220757365732073696d706c6973746963206865757269737469637320616e64 +2073696d706c792063616e27>-.15 E 2.5<7467>-.18 G<65742065>-2.5 E -.15 +<7665>-.25 G<72797468696e6720227269676874222e>.15 E .062<53656375726974 +792076756c6e65726162696c6974696573206d69676874206e6f74206265206964656e74 +698c65642061732073756368206279208d61>108 355.2 R<778c6e646572>-.15 E +2.561<2c61>-.4 G .061<6e6420636f6e>-2.561 F -.15<7665>-.4 G<7273656c79> +.15 E 2.561<2c73>-.65 G .061<6f6d652068697473206172656e27>-2.561 F 2.561 +<7472>-.18 G<65616c6c79>-2.561 E .302 +<73656375726974792076756c6e65726162696c69746965732e>108 367.2 R .302<54 +686973206973207472756520666f7220616c6c2073746174696320736563757269747920 +7363616e6e6572732c20657370656369616c6c792074686f7365206c696b>5.302 F +2.802<658d>-.1 G -.15<6177>-2.802 G .302<8c6e646572207468617420757365> +.15 F 3.889<6173>108 379.2 S 1.388<696d706c65207061747465726e2d62617365 +6420617070726f61636820746f206964656e74696679696e672070726f626c656d732e> +-3.889 F 1.388<5374696c6c2c2069742063616e2073657276>6.388 F 3.888<6561> +-.15 G 3.888<736175>-3.888 G 1.388 +<736566756c2061696420666f722068756d616e732c>-3.888 F<68656c70696e672074 +6f206964656e746966792075736566756c20706c6163657320746f2065>108 391.2 Q +<78616d696e652066757274686572>-.15 E 2.5<2c61>-.4 G<6e64207468617427> +-2.5 E 2.5<7374>-.55 G<686520706f696e74206f66207468697320746f6f6c2e>-2.5 +E/F1 10.95/Times-Bold@0 SF<53454520414c534f>72 420 Q F0 1.447 +<53656520746865208d61>108 432 R 1.447 +<778c6e646572207765627369746520617420687474703a2f2f777777>-.15 F +<2e64776865656c6572>-.65 E<2e636f6d2f8d61>-.55 E<778c6e646572>-.15 E +6.447<2e59>-.55 G 1.448<6f752073686f756c6420616c736f2073656520746865> +-7.547 F/F2 10/Times-Italic@0 SF<5365637572>4.278 E 3.948<6550>-.37 G +-.45<726f>-3.948 G<2d>.45 E<6772>108 444 Q +<616d6d696e6720666f7220556e697820616e64204c696e757820484f>-.15 E<5754> +-.5 E<4f>-.18 E F0<617420687474703a2f2f777777>2.77 E<2e64776865656c6572> +-.65 E<2e636f6d2f7365637572652d70726f6772616d732e>-.55 E F1 -.548<4155> +72 472.8 S<54484f52>.548 E F0<4461>108 484.8 Q +<76696420412e20576865656c6572202864776865656c65724064776865656c6572>-.2 +E<2e636f6d292e>-.55 E<466c61>72 768 Q 161.655<778c6e646572203330>-.15 F +<4d61792032303034>2.5 E<38>202.335 E 0 Cg EP +%%Trailer +end +%%EOF diff --git a/flawfinder.spec b/flawfinder.spec new file mode 100644 index 0000000..b632a41 --- /dev/null +++ b/flawfinder.spec @@ -0,0 +1,46 @@ +Name: flawfinder +Summary: Examines C/C++ source code for security flaws +Version: 1.26 +Release: 1 +License: GPL +Group: Development/Tools +URL: http://www.dwheeler.com/flawfinder/ +Source: http://www.dwheeler.com/flawfinder/%{name}-%{version}.tar.gz +Packager: David A. Wheeler +Requires: python +BuildArch: noarch +BuildRoot: %{_tmppath}/%{name}-%{version}-root + +%description +Flawfinder scans through C/C++ source code, +identifying lines ("hits") with potential security flaws. +By default it reports hits sorted by severity, with the riskiest lines first. +Flawfinder is released under the GNU Public License (GPL). + +%prep +%setup -q + +%build +make + +%install +[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT" +install -m755 -D flawfinder ${RPM_BUILD_ROOT}%{_bindir}/flawfinder +install -m644 -D flawfinder.1 ${RPM_BUILD_ROOT}%{_mandir}/man1/flawfinder.1 + +%clean +[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT" + +%files +%defattr(-,root,root) +%doc README ChangeLog COPYING flawfinder.ps +%{_bindir}/* +%{_mandir}/man1/* + +%changelog +* Sat Feb 1 2003 Jose Pedro Oliveira +- changed build architecture to noarch +- replaced hardcoded directories by rpm macros +- removed several rpmlint warnings/errors + +# vim:set ai ts=4 sw=4: diff --git a/flawtest.c b/flawtest.c new file mode 100644 index 0000000..6c44640 --- /dev/null +++ b/flawtest.c @@ -0,0 +1,26 @@ + +/* Test flawfinder. This program won't compile or run; that's not necessary + for this to be a useful test. */ + +main() { + char d[20]; + char s[20]; + int n; + + _mbscpy(d,s); /* like strcpy, this doesn't check for buffer overflow */ + memcpy(d,s); + CopyMemory(d,s); + lstrcat(d,s); + strncpy(d,s); + _tcsncpy(d,s); + strncat(d,s,10); + strncat(d,s,sizeof(d)); /* Misuse - this should be flagged as riskier. */ + _tcsncat(d,s,sizeof(d)); /* Misuse - flag as riskier */ + n = strlen(d); + /* This is wrong, and should be flagged as risky: */ + MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName)); + /* This is much better: */ + MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName)/sizeof(wszUserName[0])); +} + + diff --git a/junk.c b/junk.c new file mode 100644 index 0000000..03d668d --- /dev/null +++ b/junk.c @@ -0,0 +1,9 @@ + +#include + +main() { + char abuf[1000]; + FILE *FR = stdin; + fscanf(FR, "%2000s", abuf); + printf("Result = %s\n", abuf); +} diff --git a/makefile b/makefile new file mode 100644 index 0000000..4388b3a --- /dev/null +++ b/makefile @@ -0,0 +1,150 @@ +# Flawfinder. Released under the General Public License (GPL). +# (C) 2001 David A. Wheeler. + +# To change version number, edit this here, the beginning of the +# "flawfinder" script, flawfinder.spec, setup.py, and index.html. +# Then "make test-is-correct" to get the updated version number. +# To distribute, "make distribute && su && make rpm". +# Then use make my_install to install to website image. +# Eventually switch to using DistUtils to autogenerate. + +NAME=flawfinder +VERSION=1.26 +RPM_VERSION=1 +VERSIONEDNAME=$(NAME)-$(VERSION) +ARCH=noarch + +SAMPLE_DIR=/usr/src/linux-2.2.16 + +INSTALL_DIR=/usr/local +INSTALL_DIR_BIN=$(INSTALL_DIR)/bin +INSTALL_DIR_MAN=$(INSTALL_DIR)/man/man1 + +# For Cygwin on Windows, set PYTHONEXT=.py +# (EXE=.exe would be needed on some systems, but not for flawfinder) +EXE= +PYTHONEXT= +# EXE=.exe +# PYTHONEXT=.py + +# The rpm build command. "rpmbuild" for rpm version 4.1+ +# (e.g., in Red Hat Linux 8), "rpm" for older versions. + +RPMBUILD=rpmbuild + +all: flawfinder.pdf flawfinder.1.gz + chmod -R a+rX * + + +# This installer doesn't install the compiled Python bytecode. +# It doesn't take long to compile the short Python code, so +# it doesn't save much time, and having the source code available +# makes it easier to see what it does. It also avoids the +# (admittedly rare) problem of bad date/timestamps causing the +# compiled code to override later uncompiled Python code. +# Note that this uses the "-p" option of mkdir; some very old Unixes +# might not support this option, but it's a really common option +# and required by SUSv3 (and probably earlier, I haven't checked). +install: + -mkdir -p $(INSTALL_DIR_BIN) + cp flawfinder$(PYTHONEXT) $(INSTALL_DIR_BIN)/flawfinder$(PYTHONEXT) + -mkdir -p $(INSTALL_DIR_MAN) + cp flawfinder.1 $(INSTALL_DIR_MAN)/flawfinder.1 + +uninstall: + rm $(INSTALL_DIR_BIN)/flawfinder$(PYTHONEXT) + rm $(INSTALL_DIR_MAN)/flawfinder.1 + +flawfinder.1.gz: flawfinder.1 + gzip -c9 < flawfinder.1 > flawfinder.1.gz + +flawfinder.ps: flawfinder.1 + man -t ./flawfinder.1 > flawfinder.ps + +flawfinder.pdf: flawfinder.ps + ps2pdf flawfinder.ps flawfinder.pdf + + +clean: + rm -f *.pyc + rm -f flawfinder-$(VERSION).tar.gz + rm -f *.tar + +distribute: clean flawfinder.pdf flawfinder.ps + chmod -R a+rX * + mkdir ,1 + cp -p [a-zA-Z]* ,1 + rm -f ,1/*.tar.gz + rm -f ,1/*.rpm + # We don't need both "flawfinder" and "flawfinder.py": + rm -f ,1/flawfinder.py + mv ,1 flawfinder-$(VERSION) + # Nobody else needs "update" either. + rm -f ,1/update + # Don't include (out of date) index.html + rm -f ,1/index.html + tar cvfz flawfinder-$(VERSION).tar.gz flawfinder-$(VERSION) + chown --reference=. flawfinder-$(VERSION).tar.gz + rm -fr flawfinder-$(VERSION) + + +time: + echo "Timing the program. First, time taken:" + time ./flawfinder $(SAMPLE_DIR)/*/*.[ch] > /dev/null + echo "Lines examined:" + wc -l $(SAMPLE_DIR)/*/*.[ch] | tail -2 + +test: flawfinder test.c test2.c + # Omit time report so that results are always the same textually. + ./flawfinder --omittime test.c test2.c > test-results.txt + ./flawfinder --omittime --html --context test.c test2.c > test-results.html + less test-results.txt + +check: + diff -u correct-results.txt test-results.txt + +test-is-correct: test-results.txt + mv test-results.txt correct-results.txt + mv test-results.html correct-results.html + +profile: + /usr/lib/python1.5/profile.py ./flawfinder > profile-results $(SAMPLE_DIR)/*/*.[ch] > profile-results + + +rpm: distribute + chmod -R a+rX * + cp $(VERSIONEDNAME).tar.gz /usr/src/redhat/SOURCES + cp flawfinder.spec /usr/src/redhat/SPECS + cd /usr/src/redhat/SPECS + $(RPMBUILD) -ba flawfinder.spec + chmod a+r /usr/src/redhat/RPMS/$(ARCH)/$(VERSIONEDNAME)-$(RPM_VERSION)*.rpm + chmod a+r /usr/src/redhat/SRPMS/$(VERSIONEDNAME)-$(RPM_VERSION)*.src.rpm + # cp -p /usr/src/redhat/RPMS/$(ARCH)/$(VERSIONEDNAME)-$(RPM_VERSION)*.rpm . + # cp -p /usr/src/redhat/RPMS/$(ARCH)/$(VERSIONEDNAME)-$(RPM_VERSION)*.rpm $(VERSIONEDNAME)-$(RPM_VERSION).noarch.rpm + cp -p /usr/src/redhat/RPMS/$(ARCH)/$(VERSIONEDNAME)-$(RPM_VERSION)*.rpm . + cp -p /usr/src/redhat/SRPMS/$(VERSIONEDNAME)-$(RPM_VERSION)*.src.rpm . + chown --reference=README *.rpm + # Install, for testing. Ignore the "not installed" message here, + # unless you already installed it; we're just removing any old copies: + -rpm -e flawfinder + rpm -ivh /usr/src/redhat/RPMS/$(ARCH)/$(VERSIONEDNAME)-$(RPM_VERSION)*.rpm + echo "Use rpm -e $(NAME) to remove the package" + chown --reference=. *.rpm + +my_install: flawfinder.pdf flawfinder.ps + cp -p $(VERSIONEDNAME)-$(RPM_VERSION).$(ARCH).rpm \ + $(VERSIONEDNAME)-$(RPM_VERSION).src.rpm \ + $(VERSIONEDNAME).tar.gz \ + flawfinder makefile \ + flawfinder.pdf flawfinder.ps ChangeLog \ + test.c test2.c test-results.txt test-results.html \ + /home/dwheeler/dwheeler.com/flawfinder + +.PHONY: install clean test check profile test-is-correct rpm uninstall distribute + + +# When I switch to using "DistUtils", I may need to move the MANIFEST.in +# file into a subdirectory (named flawfinder-versionnumber). +# I can then create all the distribution files by just typing: +# python setup.py bdist_rpm + diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..46fa967 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,7 @@ +[bdist_rpm] +release = 1 +doc_files = ChangeLog + README + COPYING + flawfinder.ps + flawfinder.pdf diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..e56c42d --- /dev/null +++ b/setup.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# This is the setup.py script for "flawfinder" by David A. Wheeler. +# My thanks to Jon Nelson, who created the initial setup.py script. + +# Template for creating your own setup.py. See the USAGE file in +# the Distutils source distribution for descriptions of all the +# options shown below. Brief instructions on what to do: +# - set the other metadata: version, description, author, author_email +# and url. All of these except 'description' are required, although +# you may supply 'maintainer' and 'maintainer_email' in place of (or in +# addition to) 'author' and 'author_email' as appropriate. +# - fill in or delete the 'packages', 'package_dir', 'py_modules', +# and 'ext_modules' options as appropriate -- see USAGE for details +# - delete this comment and change '__revision__' to whatever is +# appropriate for your revision control system of choice (just make +# sure it stores the revision number for your distribution's setup.py +# script, *not* the examples/template_setup.py file from Distutils!) + + +"""Setup script for the flawfinder tool.""" + +from distutils.core import setup +import commands + +setup (# Distribution meta-data + name = "flawfinder", + version = "1.26", + description = "a program that examines source code looking for security weaknesses", + author = "David A. Wheeler", + author_email = "dwheeler@dwheeler.com", + license = 'GPL', + long_description = """Flawfinder is a program that can scan +C/C++ source code and identify out potential security flaws, +ranking them by likely severity. +It is released under the GNU GPL license.""", + url = "http://www.dwheeler.com/flawfinder/", + scripts = [ 'flawfinder' ], + data_files = [ ('share/man/man1', [ 'flawfinder.1.gz' ]) ], + py_modules = [ ], + ) diff --git a/sloctest.c b/sloctest.c new file mode 100644 index 0000000..c3b2e64 --- /dev/null +++ b/sloctest.c @@ -0,0 +1,9 @@ +/* This is a test. Should produce 6 SLOC. + */ +#include +#define HI 10 + +main() { + a = 1; /* hi */ + "hi" +} diff --git a/test-results.html b/test-results.html new file mode 100644 index 0000000..988df36 --- /dev/null +++ b/test-results.html @@ -0,0 +1,270 @@ + + + + +Flawfinder Results + + + + +

        Flawfinder Results

        +Here are the security scan results from +Flawfinder version 1.25, +(C) 2001-2004 David A. Wheeler. +Number of dangerous functions in C/C++ ruleset: 158 +

        +Examining test.c
        +Examining test2.c
        +

          +
        • test.c:32: [5] (buffer) gets: + Does not check for buffer overflows. Use fgets() instead. +
          + gets(f);
          +
          +
        • test.c:56: [5] (buffer) strncat: + Easily used incorrectly (e.g., incorrectly computing the correct + maximum size to add). Consider strlcat or automatically resizing strings. + Risk is high; the length parameter appears to be a constant, instead of + computing the number of characters left. +
          +  strncat(d,s,sizeof(d)); /* Misuse - this should be flagged as riskier. */
          +
          +
        • test.c:57: [5] (buffer) _tcsncat: + Easily used incorrectly (e.g., incorrectly computing the correct + maximum size to add). Consider strlcat or automatically resizing strings. + Risk is high; the length parameter appears to be a constant, instead of + computing the number of characters left. +
          +  _tcsncat(d,s,sizeof(d)); /* Misuse - flag as riskier */
          +
          +
        • test.c:60: [5] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes. Risk is high, it + appears that the size is given as bytes, but the function requires size as + characters. +
          +  MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName));
          +
          +
        • test.c:62: [5] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes. Risk is high, it + appears that the size is given as bytes, but the function requires size as + characters. +
          +  MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName);
          +
          +
        • test.c:73: [5] (misc) SetSecurityDescriptorDacl: + Never create NULL ACLs; an attacker can set it to Everyone (Deny All + Access), which would even forbid administrator access. +
          +  SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE);
          +
          +
        • test.c:73: [5] (misc) SetSecurityDescriptorDacl: + Never create NULL ACLs; an attacker can set it to Everyone (Deny All + Access), which would even forbid administrator access. +
          +  SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE);
          +
          +
        • test.c:17: [4] (buffer) strcpy: + Does not check for buffer overflows when copying to destination. + Consider using strncpy or strlcpy (warning, strncpy is easily misused). +
          + strcpy(b, a);
          +
          +
        • test.c:20: [4] (buffer) sprintf: + Does not check for buffer overflows. Use snprintf or vsnprintf. +
          + sprintf(s, "hello %s", bug);
          +
          +
        • test.c:21: [4] (buffer) sprintf: + Does not check for buffer overflows. Use snprintf or vsnprintf. +
          + sprintf(s, gettext("hello %s"), bug);
          +
          +
        • test.c:22: [4] (format) sprintf: + Potential format string problem. Make format string constant. +
          + sprintf(s, unknown, bug);
          +
          +
        • test.c:23: [4] (format) printf: + If format strings can be influenced by an attacker, they can be + exploited. Use a constant for the format specification. +
          + printf(bf, x);
          +
          +
        • test.c:25: [4] (buffer) scanf: + The scanf() family's %s operation, without a limit specification, + permits buffer overflows. Specify a limit to %s, or use a different input + function. +
          + scanf("%s", s);
          +
          +
        • test.c:27: [4] (buffer) scanf: + The scanf() family's %s operation, without a limit specification, + permits buffer overflows. Specify a limit to %s, or use a different input + function. +
          + scanf("%s", s);
          +
          +
        • test.c:38: [4] (format) syslog: + If syslog's format strings can be influenced by an attacker, they can + be exploited. Use a constant format string for syslog. +
          + syslog(LOG_ERR, attacker_string);
          +
          +
        • test.c:49: [4] (buffer) _mbscpy: + Does not check for buffer overflows when copying to destination. + Consider using a function version that stops copying at the end of the + buffer. +
          +  _mbscpy(d,s); /* like strcpy, this doesn't check for buffer overflow */
          +
          +
        • test.c:52: [4] (buffer) lstrcat: + Does not check for buffer overflows when concatenating to destination. +
          +  lstrcat(d,s);
          +
          +
        • test.c:75: [3] (shell) CreateProcess: + This causes a new process to execute and is difficult to use safely. + Specify the application path in the first argument, NOT as part of the + second, or embedded spaces could allow an attacker to force a different + program to run. +
          +  CreateProcess(NULL, "C:\\Program Files\\GoodGuy\\GoodGuy.exe -x", "");
          +
          +
        • test.c:75: [3] (shell) CreateProcess: + This causes a new process to execute and is difficult to use safely. + Specify the application path in the first argument, NOT as part of the + second, or embedded spaces could allow an attacker to force a different + program to run. +
          +  CreateProcess(NULL, "C:\\Program Files\\GoodGuy\\GoodGuy.exe -x", "");
          +
          +
        • test.c:91: [3] (buffer) getopt_long: + Some older implementations do not protect against internal buffer + overflows . Check implementation on installation, or limit the size of all + string inputs. +
          +    while ((optc = getopt_long (argc, argv, "a",longopts, NULL )) != EOF) {
          +
          +
        • test.c:16: [2] (buffer) strcpy: + Does not check for buffer overflows when copying to destination. + Consider using strncpy or strlcpy (warning, strncpy is easily misused). Risk + is low because the source is a constant string. +
          + strcpy(a, gettext("Hello there")); // Did this work?
          +
          +
        • test.c:19: [2] (buffer) sprintf: + Does not check for buffer overflows. Use snprintf or vsnprintf. Risk + is low because the source has a constant maximum length. +
          + sprintf(s, "hello");
          +
          +
        • test.c:45: [2] (buffer) char: + Statically-sized arrays can be overflowed. Perform bounds checking, + use functions that limit length, or ensure that the size is larger than + the maximum possible length. +
          +  char d[20];
          +
          +
        • test.c:46: [2] (buffer) char: + Statically-sized arrays can be overflowed. Perform bounds checking, + use functions that limit length, or ensure that the size is larger than + the maximum possible length. +
          +  char s[20];
          +
          +
        • test.c:50: [2] (buffer) memcpy: + Does not check for buffer overflows when copying to destination. Make + sure destination can always hold the source data. +
          +  memcpy(d,s);
          +
          +
        • test.c:51: [2] (buffer) CopyMemory: + Does not check for buffer overflows when copying to destination. Make + sure destination can always hold the source data. +
          +  CopyMemory(d,s);
          +
          +
        • test.c:97: [2] (misc) fopen: + Check when opening files - can an attacker redirect it (via symlinks), + force the opening of special file type (e.g., device files), move + things around to create a race condition, control its ancestors, or change + its contents?. +
          +  f = fopen("/etc/passwd", "r"); 
          +
          +
        • test.c:15: [1] (buffer) strcpy: + Does not check for buffer overflows when copying to destination. + Consider using strncpy or strlcpy (warning, strncpy is easily misused). Risk + is low because the source is a constant character. +
          + strcpy(a, "\n"); // Did this work?
          +
          +
        • test.c:18: [1] (buffer) sprintf: + Does not check for buffer overflows. Use snprintf or vsnprintf. Risk + is low because the source is a constant character. +
          + sprintf(s, "\n");
          +
          +
        • test.c:26: [1] (buffer) scanf: + it's unclear if the %s limit in the format string is small enough. + Check that the limit is sufficiently small, or use a different input + function. +
          + scanf("%10s", s);
          +
          +
        • test.c:53: [1] (buffer) strncpy: + Easily used incorrectly; doesn't always \0-terminate or check for + invalid pointers. +
          +  strncpy(d,s);
          +
          +
        • test.c:54: [1] (buffer) _tcsncpy: + Easily used incorrectly; doesn't always \0-terminate or check for + invalid pointers. +
          +  _tcsncpy(d,s);
          +
          +
        • test.c:55: [1] (buffer) strncat: + Easily used incorrectly (e.g., incorrectly computing the correct + maximum size to add). Consider strlcat or automatically resizing strings. +
          +  strncat(d,s,10);
          +
          +
        • test.c:58: [1] (buffer) strlen: + Does not handle strings that are not \0-terminated (it could cause a + crash if unprotected). +
          +  n = strlen(d);
          +
          +
        • test.c:64: [1] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes. Risk is very low, + the length appears to be in characters not bytes. +
          +  MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName)/sizeof(wszUserName[0]));
          +
          +
        • test.c:66: [1] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes. Risk is very low, + the length appears to be in characters not bytes. +
          +  MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName /sizeof(wszUserName[0]));
          +
          +
        +

        +Hits = 36 +
        +Lines analyzed = 118 +
        +Physical Source Lines of Code (SLOC) = 80 +
        +Hits@level = [0] 0 [1] 9 [2] 7 [3] 3 [4] 10 [5] 7
        +Hits@level+ = [0+] 36 [1+] 36 [2+] 27 [3+] 20 [4+] 17 [5+] 7
        +Hits/KSLOC@level+ = [0+] 450 [1+] 450 [2+] 337.5 [3+] 250 [4+] 212.5 [5+] 87.5
        +Suppressed hits = 2 (use --neverignore to show them) +
        +Minimum risk level = 1 +
        +Not every hit is necessarily a security vulnerability. +
        +There may be other security vulnerabilities; review your code! + + diff --git a/test-results.txt b/test-results.txt new file mode 100644 index 0000000..9d2752a --- /dev/null +++ b/test-results.txt @@ -0,0 +1,139 @@ +Flawfinder version 1.25, (C) 2001-2004 David A. Wheeler. +Number of dangerous functions in C/C++ ruleset: 158 +Examining test.c +Examining test2.c +test.c:32: [5] (buffer) gets: + Does not check for buffer overflows. Use fgets() instead. +test.c:56: [5] (buffer) strncat: + Easily used incorrectly (e.g., incorrectly computing the correct + maximum size to add). Consider strlcat or automatically resizing strings. + Risk is high; the length parameter appears to be a constant, instead of + computing the number of characters left. +test.c:57: [5] (buffer) _tcsncat: + Easily used incorrectly (e.g., incorrectly computing the correct + maximum size to add). Consider strlcat or automatically resizing strings. + Risk is high; the length parameter appears to be a constant, instead of + computing the number of characters left. +test.c:60: [5] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes. Risk is high, it + appears that the size is given as bytes, but the function requires size as + characters. +test.c:62: [5] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes. Risk is high, it + appears that the size is given as bytes, but the function requires size as + characters. +test.c:73: [5] (misc) SetSecurityDescriptorDacl: + Never create NULL ACLs; an attacker can set it to Everyone (Deny All + Access), which would even forbid administrator access. +test.c:73: [5] (misc) SetSecurityDescriptorDacl: + Never create NULL ACLs; an attacker can set it to Everyone (Deny All + Access), which would even forbid administrator access. +test.c:17: [4] (buffer) strcpy: + Does not check for buffer overflows when copying to destination. + Consider using strncpy or strlcpy (warning, strncpy is easily misused). +test.c:20: [4] (buffer) sprintf: + Does not check for buffer overflows. Use snprintf or vsnprintf. +test.c:21: [4] (buffer) sprintf: + Does not check for buffer overflows. Use snprintf or vsnprintf. +test.c:22: [4] (format) sprintf: + Potential format string problem. Make format string constant. +test.c:23: [4] (format) printf: + If format strings can be influenced by an attacker, they can be + exploited. Use a constant for the format specification. +test.c:25: [4] (buffer) scanf: + The scanf() family's %s operation, without a limit specification, + permits buffer overflows. Specify a limit to %s, or use a different input + function. +test.c:27: [4] (buffer) scanf: + The scanf() family's %s operation, without a limit specification, + permits buffer overflows. Specify a limit to %s, or use a different input + function. +test.c:38: [4] (format) syslog: + If syslog's format strings can be influenced by an attacker, they can + be exploited. Use a constant format string for syslog. +test.c:49: [4] (buffer) _mbscpy: + Does not check for buffer overflows when copying to destination. + Consider using a function version that stops copying at the end of the + buffer. +test.c:52: [4] (buffer) lstrcat: + Does not check for buffer overflows when concatenating to destination. +test.c:75: [3] (shell) CreateProcess: + This causes a new process to execute and is difficult to use safely. + Specify the application path in the first argument, NOT as part of the + second, or embedded spaces could allow an attacker to force a different + program to run. +test.c:75: [3] (shell) CreateProcess: + This causes a new process to execute and is difficult to use safely. + Specify the application path in the first argument, NOT as part of the + second, or embedded spaces could allow an attacker to force a different + program to run. +test.c:91: [3] (buffer) getopt_long: + Some older implementations do not protect against internal buffer + overflows . Check implementation on installation, or limit the size of all + string inputs. +test.c:16: [2] (buffer) strcpy: + Does not check for buffer overflows when copying to destination. + Consider using strncpy or strlcpy (warning, strncpy is easily misused). Risk + is low because the source is a constant string. +test.c:19: [2] (buffer) sprintf: + Does not check for buffer overflows. Use snprintf or vsnprintf. Risk + is low because the source has a constant maximum length. +test.c:45: [2] (buffer) char: + Statically-sized arrays can be overflowed. Perform bounds checking, + use functions that limit length, or ensure that the size is larger than + the maximum possible length. +test.c:46: [2] (buffer) char: + Statically-sized arrays can be overflowed. Perform bounds checking, + use functions that limit length, or ensure that the size is larger than + the maximum possible length. +test.c:50: [2] (buffer) memcpy: + Does not check for buffer overflows when copying to destination. Make + sure destination can always hold the source data. +test.c:51: [2] (buffer) CopyMemory: + Does not check for buffer overflows when copying to destination. Make + sure destination can always hold the source data. +test.c:97: [2] (misc) fopen: + Check when opening files - can an attacker redirect it (via symlinks), + force the opening of special file type (e.g., device files), move + things around to create a race condition, control its ancestors, or change + its contents?. +test.c:15: [1] (buffer) strcpy: + Does not check for buffer overflows when copying to destination. + Consider using strncpy or strlcpy (warning, strncpy is easily misused). Risk + is low because the source is a constant character. +test.c:18: [1] (buffer) sprintf: + Does not check for buffer overflows. Use snprintf or vsnprintf. Risk + is low because the source is a constant character. +test.c:26: [1] (buffer) scanf: + it's unclear if the %s limit in the format string is small enough. + Check that the limit is sufficiently small, or use a different input + function. +test.c:53: [1] (buffer) strncpy: + Easily used incorrectly; doesn't always \0-terminate or check for + invalid pointers. +test.c:54: [1] (buffer) _tcsncpy: + Easily used incorrectly; doesn't always \0-terminate or check for + invalid pointers. +test.c:55: [1] (buffer) strncat: + Easily used incorrectly (e.g., incorrectly computing the correct + maximum size to add). Consider strlcat or automatically resizing strings. +test.c:58: [1] (buffer) strlen: + Does not handle strings that are not \0-terminated (it could cause a + crash if unprotected). +test.c:64: [1] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes. Risk is very low, + the length appears to be in characters not bytes. +test.c:66: [1] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes. Risk is very low, + the length appears to be in characters not bytes. + +Hits = 36 +Lines analyzed = 118 +Physical Source Lines of Code (SLOC) = 80 +Hits@level = [0] 0 [1] 9 [2] 7 [3] 3 [4] 10 [5] 7 +Hits@level+ = [0+] 36 [1+] 36 [2+] 27 [3+] 20 [4+] 17 [5+] 7 +Hits/KSLOC@level+ = [0+] 450 [1+] 450 [2+] 337.5 [3+] 250 [4+] 212.5 [5+] 87.5 +Suppressed hits = 2 (use --neverignore to show them) +Minimum risk level = 1 +Not every hit is necessarily a security vulnerability. +There may be other security vulnerabilities; review your code! diff --git a/test.c b/test.c new file mode 100644 index 0000000..97579c0 --- /dev/null +++ b/test.c @@ -0,0 +1,117 @@ +/* Test flawfinder. This program won't compile or run; that's not necessary + for this to be a useful test. */ + +#include +#define hello(x) goodbye(x) +#define WOKKA "stuff" + +main() { + printf("hello\n"); +} + +/* This is a strcpy test. */ + +int demo(char *a, char *b) { + strcpy(a, "\n"); // Did this work? + strcpy(a, gettext("Hello there")); // Did this work? + strcpy(b, a); + sprintf(s, "\n"); + sprintf(s, "hello"); + sprintf(s, "hello %s", bug); + sprintf(s, gettext("hello %s"), bug); + sprintf(s, unknown, bug); + printf(bf, x); + scanf("%d", &x); + scanf("%s", s); + scanf("%10s", s); + scanf("%s", s); + gets(f); // Flawfinder: ignore + printf("\\"); + /* Flawfinder: ignore */ + gets(f); + gets(f); + /* These are okay, but flawfinder version < 0.20 incorrectly used + the first parameter as the parameter for the format string */ + syslog(LOG_ERR,"cannot open config file (%s): %s",filename,strerror(errno)) + syslog(LOG_CRIT,"malloc() failed"); + /* But this one SHOULD trigger a warning. */ + syslog(LOG_ERR, attacker_string); + +} + + + +demo2() { + char d[20]; + char s[20]; + int n; + + _mbscpy(d,s); /* like strcpy, this doesn't check for buffer overflow */ + memcpy(d,s); + CopyMemory(d,s); + lstrcat(d,s); + strncpy(d,s); + _tcsncpy(d,s); + strncat(d,s,10); + strncat(d,s,sizeof(d)); /* Misuse - this should be flagged as riskier. */ + _tcsncat(d,s,sizeof(d)); /* Misuse - flag as riskier */ + n = strlen(d); + /* This is wrong, and should be flagged as risky: */ + MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName)); + /* This is also wrong, and should be flagged as risky: */ + MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName); + /* This is much better: */ + MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName)/sizeof(wszUserName[0])); + /* This is much better: */ + MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName /sizeof(wszUserName[0])); + /* This is an example of bad code - the third paramer is NULL, so it creates + a NULL ACL. Note that Flawfinder can't detect when a + SECURITY_DESCRIPTOR structure is manually created with a NULL value + as the ACL; doing so would require a tool that handles C/C++ + and knows about types more that flawfinder currently does. + Anyway, this needs to be detected: */ + SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE); + /* This one is a bad idea - first param shouldn't be NULL */ + CreateProcess(NULL, "C:\\Program Files\\GoodGuy\\GoodGuy.exe -x", ""); + /* Test interaction of quote characters */ + printf("%c\n", 'x'); + printf("%c\n", '"'); + printf("%c\n", '\"'); + printf("%c\n", '\''); + printf("%c\n", '\177'); + printf("%c\n", '\xfe'); + printf("%c\n", '\xd'); + printf("%c\n", '\n'); + printf("%c\n", '\\'); + printf("%c\n", "'"); +} + + +int getopt_example(int argc,char *argv[]) { + while ((optc = getopt_long (argc, argv, "a",longopts, NULL )) != EOF) { + } +} + +int testfile() { + FILE *f; + f = fopen("/etc/passwd", "r"); + fclose(f); +} + +/* Regression test: handle \\\n after end of string */ + +#define assert(x) {\ + if (!(x)) {\ + fprintf(stderr,"Assertion failed.\n"\ + "File: %s\nLine: %d\n"\ + "Assertion: %s\n\n"\ + ,__FILE__,__LINE__,#x);\ + exit(1);\ + };\ + } + +int accesstest() { + int access = 0; /* Not a function call. Should be caught by the + false positive test, and NOT labelled as a problem. */ +} + diff --git a/test2.c b/test2.c new file mode 100644 index 0000000..ad6f96f --- /dev/null +++ b/test2.c @@ -0,0 +1 @@ +/* Here's a file with no contents to try */