diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..797d0dc --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,144 @@ +# How to contribute to Flawfinder + +We love contributions! Here's how to do them in a way that will +make everyone's lives easy. + +Flawfinder has long been maintained on SourceForge. +We now support reporting and changes using either SourceForge or GitHub. + +## Reporting + +For normal problems, bugs, and feature requests, *except* for +vulnerabilities, please file a +[GitHub issue](https://github.com/david-a-wheeler/flawfinder/issues) or +[SourceForge ticket](https://sourceforge.net/p/flawfinder/_list/tickets). + +If you find a vulnerability, please separately send a private email to +[David A. Wheeler](https://dwheeler.com/contactme.html). +To maintain confidentiality, +please use an email system that implements STARTTLS hop-by-hop email +encryption on outgoing email (many do, including +Gmail, hotmail.com, live.com, outlook.com, and runbox.com). +For more about STARTTLS, see the +EFF's [STARTTLS Everywhere](https://www.starttls-everywhere.org/) project. +We plan to handle vulnerabilities separately, fixing them and *then* +telling the world. We will gladly provide credit to vulnerability reporters +(unless you don't want the credit). We've never had a vulnerability +report, so this is theoretical at this time. + +## Change process + +We use "git" to track changes. To propose a change, create a fork +(copy) of the repository, make your changes, and create a +GitHub pull request or SourceForge merge request (they are the same thing). + +If you're not familiar with the process, here's some +documentation for +[GitHub](https://help.github.com/articles/about-pull-requests/) +and +[SourceForge](https://sourceforge.net/p/forge/documentation/Git/). + +## License and DCO + +All proposed changes must be released under at least the project license, +in this case the GNU GPL version 2 or later (GPL-2.0+). + +Proposers must agree to the +[Developer's Certificate of Origin](https://developercertificate.org/), +aka DCO. +The DCO basically says that you assert that you're legally allowed to +provide the commit. Please include in your commit a statement of the +form to confirm this ("git commit -s" will do this): + +> Signed-off-by: Your-name \ + +You must include the DCO in your first commit proposal. +If you forget occasionally, we'll assume that you just forgot, but +please try to not forget. + +## Development environment setup + +As always, if you're modifying the software, you'll need to have +your development environment set up. You need: + +* make +* python2 (invokable as "python2") +* python3 (invokable as "python3") +* pylint (see below) + +An easy way to install pylint is to use pip. +Most python installs have pip, but if yours does not +(e.g., Cygwin), install pip with: + +~~~~ +python -m ensurepip +~~~~ + +You may want to upgrade pip with: + +~~~~ +pip install --upgrade pip +~~~~ + +Finally, you can actually install pylint using: + +~~~~ +pip install pylint +~~~~ + +## Code Conventions + +To make the program easy to install everywhere, the main executable +is exactly one self-contained file. That involves some compromises, +but for now, please keep it that way. + +We generally use the code conventions of +[PEP 8](https://www.python.org/dev/peps/pep-0008/). +The Python code uses 4-space indents (we used to use 2-space indents). +Do not use tabs. In some cases the code doesn't yet comply; +patches to improve that are often welcome. + +The code must run on both Python 2.7 and Python 3. +To check that it works on both, run: + +~~~~ +make check +~~~~ + +We use "pylint" to check for style and other generic quality problems. +To check that the code passes these quality tests, run: + +~~~~ +make pylint +~~~~ + +We require that the pylint results for contributions be at least 9.5/10 as +configured with the provided "pylintrc" file, without any errors ("E"). +Better is better. The current version *does* cause some pylint reports +(patches to fix those are welcome!). Note that we configure pylint +with the included "pylintrc" file. +We intentionally disable some checks as being "less important", +for example, the current code has many lines longer than 80 characters. +That said, patches to make lines fit in 80 characters are welcome. + +## Tests + +Make *sure* that your code passes the automated tests. +As noted above, invoke tests with +"make check", which tests the code using both Python2 and Python3. + +It's our policy that as major new functionality is added to the software +produced by the project, tests of that functionality should be added to +the automated test suite. + +## Other + +Project documentation tends to be in markdown (.md) format. +We use "~~~~" so that it's easy to cut-and-paste commands if desired. +The main document is a man page, which is then converted to PDF. + +Avoid trailing space or tab on a line in source files - those can create +hard-to-understand "differences" on lines. + +We have earned a +[CII Best Practices Badge](https://bestpractices.coreinfrastructure.org/projects/323)... make sure we keep it! 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..2237f58 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,707 @@ +2019-06-22 David A. Wheeler + * Use binary mode when reading a diffhitlist. + My thanks to Michał Górny, who both reported the problem + and provided the patch! + +2019-05-19 David A. Wheeler + * Version 2.0.9 + * Fixes a serious defect in --diffhitlist + +2019-05-17 Labidurie Jerome + * Fixed a serious defect in --diffhitlist option and added a unit test + +2019-01-21 David A. Wheeler + * Version 2.0.8 + * Don't warn if memcpy call includes sizeof(first arg). + Thanks to Michael Clark for this improvement! + * Bugfix (banned function _ftcsat should be _ftcscat). + Thanks to Lucas Ramage for reporting this! + * Documentation tweaks. Make it clear that GitHub issues and + pull requests are supported, and use ~~~~ in markdown + to ease copy-and-paste from documentation. + +2018-09-30 David A. Wheeler + * Incorporate many small improvements from nickthetait + * Fix a number of bugs reported by philipp + * Update URLs for www.dwheeler.com -> dwheeler.com + +2018-04-04 David A. Wheeler + * Version 2.0.6 + +2018-01-26 David A. Wheeler + * Small fixes + * Update cwe.mitre.org URLs to use https + +2017-11-16 David A. Wheeler + * add detection of crypt_r function + * add detection of errant equal, mismatch, and is_permutation + * update CWE, risk, and discussion for C++14 STL functions + * Always report hit counts correctly, even if ignored using -m + * Update www.dwheeler.com URLs to use https + +2017-09-02 David A. Wheeler + * Version 2.0.4 + * Switch from distutils to setuptools + * Directly support "pip" installs + +2017-08-26 David A. Wheeler + * Version 2.0.2 + * Flawfinder can now run on either Python 2.7 or 3 + * Added more tests + * Implemented additional code cleanups recommended by Pylint + * Modified documentation in various ways to clarify things + +2017-08-13 David A. Wheeler + * Version 2.0.1 + * Tranform many internal constructs to work on Python 2 or 3, + with the eventual goal of making it run on either. + +2017-07-29 David A. Wheeler + * Version 2.0.0 + * Change version numbers to use Semantic Versioning (x.y.z) + * Add support for generating CSV (comma-separated value) format, + to make this tool easier to integrate into larger toolsuites. + * Fixed a number of issues - and even a few bugs - found by the + Python static analysis tool pylint. + * Document in CONTRIBUTING.md how to contribute to the project. + * Change version number to 2.0.0, because we have a subtle + interface change that won't affect most people but it + *may* affect those who use postprocess + flawfinder data on CWEs. The fundamental issue is that + in some cases a hit corresponds to multiple CWEs. As a result, + in some cases flawfinder will list a sequence of CWEs + in the format "more-general/more-specific", where the CWE actually + being mapped is followed by a "!". + This is always done whenever a flaw is not mapped directly to + a top 25 CWE, but the mapping is related to such a CWE. + So "CWE-119!/CWE-120" means that the vulnerability is mapped + to CWE-119 and that CWE-120 is a subset of CWE-119. + In contrast, "CWE-362/CWE-367!" means that the hit is mapped to + CWE-367, a subset of CWE-362. + Note that this is a subtle syntax change from flawfinder + version 1.31; in flawfinder version 1.31, + the form "more-general:more-specific" meant what is now listed as + "more-general!/more-specific", while + "more-general/more-specific" meant "more-general/more-specific!". + Tools can handle both the version 1.31 and the current format, + if they wish, by noting that the older format did not use "!" at all. + These mapping mechanisms simplify searching for certain CWEs. + +2014-08-03 David A. Wheeler + * Release version 1.31, a set of small improvements mostly CWE-related. + * Note that flawfinder is officially CWE-compatible. + * Support GNU make install conventions (prefix, bindir, DESTDIR, etc.). + The older program-specific conventions are still supported, but + the documentation emphasizes using the standard conventions instead. + * Simplified installation text. + * Added more wide character function rules. + * Add reference to info at "http://www.dwheeler.com/secure-programs". + * Document that hitlists should be trusted to be loaded or diffed. + These are implented using Python's pickle module, and that module + presumes the data is from a trustworthy source. In the expected + use case this is fine... but it needed to be documented. + * Tweak/improve mappings to CWE. E.G., strlen() + better maps to CWE-126 (buffer over-read). In a few cases the + CWE mappings weren't reported as such; that is now fixed. + CWEs are actually a hierarchy; expose a little of this so + people can more easily search on them. + * Improved error detection and reporting. In particular, error + messages are sent to standard errors, filenames listed but + non-existent trigger a separate warning, and there's a warning + about non-existent filenames listed on the command line that + begin with the UTF-8 long dash sequence (users might not notice + the difference between long dash and dash, and this can happen + in some cases when copying and pasting). + * Add "-H" option as synonym for "--html". + +2014-07-19 David A. Wheeler + * Release 1.29, primarily for CWE improvements. + * Multi-line formatting is faster and formats better. + * Documentation about CWEs has been improved. + * HTML format includes links from CWE identifiers to their definitions. + * Tweak CWE mappings, e.g., strlen maps to CWE-126 (buffer over-read). + * Option "--listrules" now gives default warning and is tab-delimited. + * Regression test suite now also tests the generated HTML. + +2014-07-13 David A. Wheeler + * Release 1.28 + * Common Weakness Enumeration (CWE) references are + now included in most hits + * Handle files not ending in newline (thanks to Alexis Wilke) + * Documentation clarifications + * Added support for "git diff" in patchfile processing + * Handles unbalanced double-quotes in sprintf + * Fix incorrect time executed report + * Fix bug to allow "flawfinder ." (fix bug#3) + * Fix ignore directive when filenames differ (fix bug#6) + +2007-01-16 David A. Wheeler + * Release version 1.27 + +2007-01-16 Sebastien Tandel + * Fix Debian bug #268236. + http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=268236 + This complains that flawfinder crashes when presented with a + file it cannot read. The patch obviously can't prevent + the problem, since the tool can't review what it can't read, + but at least it halts with a cleaner error message. + +2007-01-15 cmorgan + * Fixed Debian bug #271287 (flawfinder). See: + http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=271287 + Fixed skipping newlines when line ended with \, + which caused incorrect line number reporting. + Skip multiple whitespace at one time. + +2007-01-15 David A. Wheeler + * Modified Sebastien Tandel's code so that it also supports GNU diff + (his code worked only for svn diff) + * When using a patchfile, skip analysis of any file not + listed in the patchfile. + +2007-01-15 Sebastien Tandel + * By default, now skips directories beginning with "." + (this makes it work nicely with many SCM systems). + Added "--followdotdir" option if you WANT it to enter + such directories. + * Fixed divide-by-zero when no code found (not exactly common + in normal use, but anyway!) + +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.md b/INSTALL.md new file mode 100644 index 0000000..5033898 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,131 @@ +# Installing flawfinder + +You can install flawfinder a number of different ways. +Choose the approach that's most convenient for you! +The options (described below) are (1) pip, (2) package for Unix-like system, (3) source install, and (4) run directly. + + +## 1. PIP + +For many, the simple approach is to first install Python +(2.7 or something reasonable in the 3.X series). +Then use `pip` to install flawfinder +(this will normally download the package): + +~~~~ +pip install flawfinder +~~~~ + +One advantage for using pip is that you'll generally get the +*current* released version. + + +## 2. PACKAGE FOR UNIX-LIKE SYSTEM (including Cygwin): + +If you use an RPM-based system (e.g., Red Hat) or deb-based system +(e.g., Debian), you can 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. + +This will work out-of-the-box; it may not be the most recent version. + +One way to accomplish this is: + +~~~~ +sudo apt install flawfinder +~~~~ + + +## 3. TARBALL (SOURCE INSTALL) + +QUICK START: +The quick way to install flawfinder from the tarball is to +unpack the tarball and type in something like this on the command line: + +~~~~ +sudo make prefix=/usr install +~~~~ + +Omit prefix=/usr to install in /usr/local instead. +Omit "sudo" if you are already root. +Note that this installation approach follows the usual install conventions +as described below, including prefix= and DESTDIR. + +Not enough? Here are more detailed step-by-step instructions and options. + +* Download the "tarball" and uncompress it. + GNU-based systems can run `tar xvzf flawfinder-.tar.gz` to do so, + then move into the newly created directory with `cd flawfinder-` + 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 everything + in /usr/local, with the program in /usr/local/bin and the man page in + /usr/local/share/man/man1, per GNU conventions. You can override this + when installing (with "make install") by setting some environment + variables. You can do this by setting traditional GNU variables, e.g., + "prefix" = prefix of all files, default /usr/local + "bindir" = directory for binaries, default $(prefix)/bin + (the program "flawfinder" is put here) + "datarootdir" = data for shared data, by default $(prefix)/share + "mandir" = directory for all man pages, default $(datarootdir)/man + "man1dir" = directory for all man1 pages, default $(mandir)/man1 + (the man page "flawfinder.1" is put here). Given the + previous definitions, its default is $(prefix)/share/man/man1 + It is common to override "prefix" with "/usr" instead. + + You can also use the older flawfinder makefile variables to control + installation; you can set: + `INSTALL_DIR` = prefix, default $(prefix); + `INSTALL_DIR_BIN` = program location, default `$(bindir)`; + `INSTALL_DIR_MAN` = manual location, default `$(man1dir)`. + Note that the default of `INSTALL_DIR_MAN` has changed; at one time + it was `$(prefix)/man/man1`, but now it is `$(prefix)/share/man/man1` + +* 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. Currently it really + only installs two files, an executable and a man page (documentation). + 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 prefix=/usr install` + or alternatively, using the older flawfinder conventions: + `make INSTALL_DIR=/usr install` + + To install in /usr on Cygwin: + `make prefix=/usr PYTHONEXT=.py install` + + To put the binaries in /usr/bin, and the manuals under /usr/local/share/man + (common for Red Hat Linux), do: + `make prefix=/usr mandir=/usr/local/share/man install` + + The installer and uninstaller honor `DESTDIR`. + +## 4. DIRECT EXECUTION + +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..ad47cc1 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,14 @@ +include COPYING +include README.md +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.md b/README.md new file mode 100644 index 0000000..0a3aea8 --- /dev/null +++ b/README.md @@ -0,0 +1,79 @@ +# About + +This is "flawfinder" by [David A. Wheeler](mailto:dwheeler@dwheeler.com). + +Flawfinder is a simple program that scans C/C++ source code and reports +potential security flaws. It can be a useful tool for examining software +for vulnerabilities, and it can also serve as a simple introduction to +static source code analysis tools more generally. It is designed to +be easy to install and use. Flawfinder supports the Common Weakness +Enumeration (CWE) and is officially CWE-Compatible. + +For more information, see the [project website](http://dwheeler.com/flawfinder) + +# Platforms + +Flawfinder is designed for use on Unix/Linux/POSIX systems +(including Cygwin, Linux-based systems, MacOS, and various BSDs) as a +command line tool. It requires either Python 2.7 or Python 3. + +# Installation + +If you just want to *use* it, you can install flawfinder with +Python's "pip" or with your system's package manager (flawfinder has +packages for many systems). It also supports easy installation +following usual `make install` source installation conventions. +The file [INSTALL.md](INSTALL.md) has more detailed installation instructions. +You don't HAVE to install it to run it, but it's easiest that way. + +# Usage + +To run flawfinder, just give it a list of source files or directories to +example. For example, to examine all files in "src/" and down recursively: + +~~~~ +flawfinder src/ +~~~~ + +To examine all files in the *current* directory and down recursively: + +~~~~ +flawfinder ./ +~~~~ + +Hits (findings) are given a risk level from 0 (very low risk) to 5 (high risk), +By default, findings of risk level 1 or higher are shown. +You can show only the hits of risk level 4 or higher in the current +directory and down this way: + +~~~~ +flawfinder --minlevel 4 ./ +~~~~ + +The manual page (flawfinder.1 or flawfinder.pdf) describes how to use +flawfinder (including its various options) and related information +(such as how it supports CWE). For example, the `--html` option generates +output in HTML format. The `--help` option gives a brief list of options. + +# Under the hood + +More technically, flawfinder uses lexical scanning to find tokens +(such as function names) that suggest likely vulnerabilities, estimates their +level of risk (e.g., by the text of function calls), and reports the results. +Flawfinder does not use or have access to information about control flow, +data flow, or data types. Thus, flawfinder will necessarily +produce many false positives for vulnerabilities and fail to report +many vulnerabilities. On the other hand, flawfinder can find +vulnerabilities in programs that cannot be built or cannot be linked. +Flawfinder also doesn't get as confused by macro definitions +and other oddities that more sophisticated tools have trouble with. + +# Contributions + +We love contributions! For more information on contributing, see +the file [CONTRIBUTING.md](CONTRIBUTING.md). + +# License + +Flawfinder is released under the GNU GPL license version 2 or later (GPL-2.0+). +See the [COPYING](COPYING) file for license information. 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/buggy-latin1.c b/buggy-latin1.c new file mode 100755 index 0000000..3184003 --- /dev/null +++ b/buggy-latin1.c @@ -0,0 +1,8 @@ + +// Buggy é + +main() { + char x[1]; + strcpy(x,"aaaaé"); +} + diff --git a/buggy.c b/buggy.c new file mode 100755 index 0000000..9d4b4f1 --- /dev/null +++ b/buggy.c @@ -0,0 +1,5 @@ + +// Buggy é + +main() {} + diff --git a/correct-results-004.txt b/correct-results-004.txt new file mode 100755 index 0000000..e898119 --- /dev/null +++ b/correct-results-004.txt @@ -0,0 +1,7 @@ +test.c:32:2: [5] (buffer) gets:Does not check for buffer overflows (CWE-120, CWE-20). Use fgets() instead. +test.c:60:3: [5] (buffer) strncat:Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120). Consider strcat_s, strlcat, snprintf, 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:61:3: [5] (buffer) _tcsncat:Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120). Consider strcat_s, 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:64:3: [5] (buffer) MultiByteToWideChar:Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is high, it appears that the size is given as bytes, but the function requires size as characters. +test.c:66:3: [5] (buffer) MultiByteToWideChar:Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is high, it appears that the size is given as bytes, but the function requires size as characters. +test.c:77:3: [5] (misc) SetSecurityDescriptorDacl:Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732). +test.c:77:3: [5] (misc) SetSecurityDescriptorDacl:Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732). diff --git a/correct-results-005.txt b/correct-results-005.txt new file mode 100755 index 0000000..5e83b7c --- /dev/null +++ b/correct-results-005.txt @@ -0,0 +1 @@ +test-patched.c:13:2: [4] (buffer) strcpy:Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120). Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused). diff --git a/correct-results-006.txt b/correct-results-006.txt new file mode 100755 index 0000000..e898119 --- /dev/null +++ b/correct-results-006.txt @@ -0,0 +1,7 @@ +test.c:32:2: [5] (buffer) gets:Does not check for buffer overflows (CWE-120, CWE-20). Use fgets() instead. +test.c:60:3: [5] (buffer) strncat:Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120). Consider strcat_s, strlcat, snprintf, 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:61:3: [5] (buffer) _tcsncat:Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120). Consider strcat_s, 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:64:3: [5] (buffer) MultiByteToWideChar:Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is high, it appears that the size is given as bytes, but the function requires size as characters. +test.c:66:3: [5] (buffer) MultiByteToWideChar:Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is high, it appears that the size is given as bytes, but the function requires size as characters. +test.c:77:3: [5] (misc) SetSecurityDescriptorDacl:Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732). +test.c:77:3: [5] (misc) SetSecurityDescriptorDacl:Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732). diff --git a/correct-results-008.txt b/correct-results-008.txt new file mode 100644 index 0000000..be0c58d --- /dev/null +++ b/correct-results-008.txt @@ -0,0 +1,17 @@ +Flawfinder version 2.0.10, (C) 2001-2019 David A. Wheeler. +Showing hits not in test-saved-hitlist-008.txt +Number of rules (primarily dangerous function names) in C/C++ ruleset: 223 + +ANALYSIS SUMMARY: + +No hits found. +Lines analyzed = 121 +Physical Source Lines of Code (SLOC) = 84 +Hits@level = [0] 0 [1] 0 [2] 0 [3] 0 [4] 0 [5] 0 +Hits@level+ = [0+] 0 [1+] 0 [2+] 0 [3+] 0 [4+] 0 [5+] 0 +Hits/KSLOC@level+ = [0+] 0 [1+] 0 [2+] 0 [3+] 0 [4+] 0 [5+] 0 +Suppressed hits = 2 (use --neverignore to show them) +Minimum risk level = 1 +There may be other security vulnerabilities; review your code! +See 'Secure Programming HOWTO' +(https://dwheeler.com/secure-programs) for more information. diff --git a/correct-results.csv b/correct-results.csv new file mode 100755 index 0000000..a4599b5 --- /dev/null +++ b/correct-results.csv @@ -0,0 +1,39 @@ +File,Line,Column,Level,Category,Name,Warning,Suggestion,Note,CWEs,Context,Fingerprint +test.c,32,2,5,buffer,gets,"Does not check for buffer overflows (CWE-120, CWE-20)",Use fgets() instead,,"CWE-120, CWE-20", gets(f);,6a5bb383fb44030b0d9428b17359e94ba3979bc1ce702be450427f85592c649a +test.c,60,3,5,buffer,strncat,"Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120)","Consider strcat_s, strlcat, snprintf, or automatically resizing strings","Risk is high; the length parameter appears to be a constant, instead of computing the number of characters left.",CWE-120," strncat(d,s,sizeof(d)); /* Misuse - this should be flagged as riskier. */",cbd19c308547e79af13436d8f7dbcf6c62e49e4f62ba9aee38fbef29e0772f74 +test.c,61,3,5,buffer,_tcsncat,"Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120)","Consider strcat_s, strlcat, or automatically resizing strings","Risk is high; the length parameter appears to be a constant, instead of computing the number of characters left.",CWE-120," _tcsncat(d,s,sizeof(d)); /* Misuse - flag as riskier */",c3f6ba2c710efc878e66df4578894fd408452cb7cdec7ae6f492a3b1796f8c42 +test.c,64,3,5,buffer,MultiByteToWideChar,"Requires maximum length in CHARACTERS, not bytes (CWE-120)",,"Risk is high, it appears that the size is given as bytes, but the function requires size as characters.",CWE-120," MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName));",4f5b73ff337a54d6e1d9a369659ca0ddb4f80e6b7e38a17e5b112f6d3e266e69 +test.c,66,3,5,buffer,MultiByteToWideChar,"Requires maximum length in CHARACTERS, not bytes (CWE-120)",,"Risk is high, it appears that the size is given as bytes, but the function requires size as characters.",CWE-120," MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName);",9ecdc1e903acc16a646bf7909a630ae22a7593b70952c39ce6bd9c5a23fad0fd +test.c,77,3,5,misc,SetSecurityDescriptorDacl,"Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732)",,,CWE-732," SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE);",5fed1e135b593b4c943e66e89a26ff131eba18b83a32a8af37d1c0bd7b01aadb +test.c,77,3,5,misc,SetSecurityDescriptorDacl,"Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732)",,,CWE-732," SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE);",5fed1e135b593b4c943e66e89a26ff131eba18b83a32a8af37d1c0bd7b01aadb +test.c,17,2,4,buffer,strcpy,Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120),"Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused)",,CWE-120," strcpy(b, a);",c01c8472bb53022e912da4da2faebc67d537855da324020c44bfd5e608a79b77 +test.c,20,2,4,buffer,sprintf,Does not check for buffer overflows (CWE-120),"Use sprintf_s, snprintf, or vsnprintf",,CWE-120," sprintf(s, ""hello %s"", bug);",814237858ab012010f3355a49480dd6fa0a2cb8cf8356a98ac1c17c9febf6521 +test.c,21,2,4,buffer,sprintf,Does not check for buffer overflows (CWE-120),"Use sprintf_s, snprintf, or vsnprintf",,CWE-120," sprintf(s, gettext(""hello %s""), bug);",b793f18f143fb2297c49e0639384ad73db86eb01a44377aa4d5d09b44b03d747 +test.c,22,2,4,format,sprintf,Potential format string problem (CWE-134),Make format string constant,,CWE-134," sprintf(s, unknown, bug);",16ebc2ff96ee4bab2695783709e97b597ca9c8b8cc149e33aed859f0fafd3431 +test.c,23,2,4,format,printf,"If format strings can be influenced by an attacker, they can be exploited (CWE-134)",Use a constant for the format specification,,CWE-134," printf(bf, x);",46f42896019245d2dffc4caf4fe018b073ce2a58203676eaa28b6374558a5b5d +test.c,25,2,4,buffer,scanf,"The scanf() family's %s operation, without a limit specification, permits buffer overflows (CWE-120, CWE-20)","Specify a limit to %s, or use a different input function",,"CWE-120, CWE-20"," scanf(""%s"", s);",3f169dd9fe508f70438f818770a3cb8b0f228e4245ea11a929a5fb0a7839fd5f +test.c,27,2,4,buffer,scanf,"The scanf() family's %s operation, without a limit specification, permits buffer overflows (CWE-120, CWE-20)","Specify a limit to %s, or use a different input function",,"CWE-120, CWE-20"," scanf(""%s"", s);",3f169dd9fe508f70438f818770a3cb8b0f228e4245ea11a929a5fb0a7839fd5f +test.c,38,2,4,format,syslog,"If syslog's format strings can be influenced by an attacker, they can be exploited (CWE-134)",Use a constant format string for syslog,,CWE-134," syslog(LOG_ERR, attacker_string);",22e98963d5af7b197a090bd522d2d39b8d8ee7bdf08453fd2008939c92cd9677 +test.c,49,3,4,buffer,_mbscpy,Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120),Consider using a function version that stops copying at the end of the buffer,,CWE-120," _mbscpy(d,s); /* like strcpy, this doesn't check for buffer overflow */",e00a4a1a0a3603db98a23fcff3c9cdfd9012f5a81826814d9508e0f22089b993 +test.c,56,3,4,buffer,lstrcat,Does not check for buffer overflows when concatenating to destination [MS-banned] (CWE-120),,,CWE-120," lstrcat(d,s);",364b4c512862fdccbca27d2fa7737995b5d24b637a760976c940ae636218d340 +test.c,79,3,3,shell,CreateProcess,This causes a new process to execute and is difficult to use safely (CWE-78),"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",,CWE-78," CreateProcess(NULL, ""C:\\Program Files\\GoodGuy\\GoodGuy.exe -x"", """");",3c712b38d0857bde3832d85ad35ac9859be55c5f5f1c20af659a577dd4d0acbf +test.c,79,3,3,shell,CreateProcess,This causes a new process to execute and is difficult to use safely (CWE-78),"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",,CWE-78," CreateProcess(NULL, ""C:\\Program Files\\GoodGuy\\GoodGuy.exe -x"", """");",3c712b38d0857bde3832d85ad35ac9859be55c5f5f1c20af659a577dd4d0acbf +test.c,95,20,3,buffer,getopt_long,"Some older implementations do not protect against internal buffer overflows (CWE-120, CWE-20)","Check implementation on installation, or limit the size of all string inputs",,"CWE-120, CWE-20"," while ((optc = getopt_long (argc, argv, ""a"",longopts, NULL )) != EOF) {",5bedf6e5bccf596008ef191ec4c5d4cc51a32cff0c05ef62d5f10fab93d0cc24 +test.c,16,2,2,buffer,strcpy,Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120),"Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused)",Risk is low because the source is a constant string.,CWE-120," strcpy(a, gettext(""Hello there"")); // Did this work?",d64070fb93ff0bb797fb926f4dddc7212d42f77e288d5ceb0cd30ed2979fa28d +test.c,19,2,2,buffer,sprintf,Does not check for buffer overflows (CWE-120),"Use sprintf_s, snprintf, or vsnprintf",Risk is low because the source has a constant maximum length.,CWE-120," sprintf(s, ""hello"");",907b46be1c3ea7b38f90a4d1b0f43b7751cd8cbe38fae840930ff006b702157d +test.c,45,3,2,buffer,char,"Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120)","Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length",,CWE-119!/CWE-120, char d[20];,36c87517700337a59cc3ad3218cfdde56cad37d69cdeccee5a55ab232d5c7946 +test.c,46,3,2,buffer,char,"Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120)","Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length",,CWE-119!/CWE-120, char s[20];,213de8e8815fc84c423b55fd845fea541f25744718e486234364bb457863b597 +test.c,50,3,2,buffer,memcpy,Does not check for buffer overflows when copying to destination (CWE-120),Make sure destination can always hold the source data,,CWE-120," memcpy(d,s); // fail - no size",e667b352fb0748c67b607b11577b11bad87545779c39923e61839dd04056055f +test.c,53,3,2,buffer,memcpy,Does not check for buffer overflows when copying to destination (CWE-120),Make sure destination can always hold the source data,,CWE-120," memcpy(&n,s,sizeof(s)); // fail - sizeof not of destination",01bcc2c8ba2d928ac3315b4dcc6593042ea05e62888a10a6d2cf16797a65ed32 +test.c,54,3,2,buffer,memcpy,Does not check for buffer overflows when copying to destination (CWE-120),Make sure destination can always hold the source data,,CWE-120," memcpy(d,s,n); // fail - size unguessable",2517a2fb5981193a6017cca660d16e85aab133706cbec302df97aaa623fc77ef +test.c,55,3,2,buffer,CopyMemory,Does not check for buffer overflows when copying to destination (CWE-120),Make sure destination can always hold the source data,,CWE-120," CopyMemory(d,s);",977f8c805ddd76ff32e0f7aea08701ba97d9ce6955136e98b308ed4f70eb2e11 +test.c,101,7,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? (CWE-362)",,,CWE-362," f = fopen(""/etc/passwd"", ""r""); ",2ec6928c77a8b54caa61d0459f367c4394ee1f5e6f488753f587bfa9c780bad8 +test.c,15,2,1,buffer,strcpy,Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120),"Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused)",Risk is low because the source is a constant character.,CWE-120," strcpy(a, ""\n""); // Did this work?",0badc5f4c500d17b42794feaca54ee0f49e607a32510af3ed749579001017edb +test.c,18,2,1,buffer,sprintf,Does not check for buffer overflows (CWE-120),"Use sprintf_s, snprintf, or vsnprintf",Risk is low because the source is a constant character.,CWE-120," sprintf(s, ""\n"");",c65fbd60851f3c8ace22332805966606488c0d242c1823493c582e267609b1a7 +test.c,26,2,1,buffer,scanf,It's unclear if the %s limit in the format string is small enough (CWE-120),"Check that the limit is sufficiently small, or use a different input function",,CWE-120," scanf(""%10s"", s);",e24c4c801f10acfa93098b2bef58524efe4f88237f2dd8b58be9afa838616afe +test.c,57,3,1,buffer,strncpy,Easily used incorrectly; doesn't always \0-terminate or check for invalid pointers [MS-banned] (CWE-120),,,CWE-120," strncpy(d,s);",8fa14bf72393a00f667ffcc06b7b7e5f0b6d2f16d8d67444db06b0deb35b5f5e +test.c,58,3,1,buffer,_tcsncpy,Easily used incorrectly; doesn't always \0-terminate or check for invalid pointers [MS-banned] (CWE-120),,,CWE-120," _tcsncpy(d,s);",691fabd4ca960a00e4c538eee0187ee0fdf59bd43dd71e792c14175150369b8b +test.c,59,3,1,buffer,strncat,"Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120)","Consider strcat_s, strlcat, snprintf, or automatically resizing strings",,CWE-120," strncat(d,s,10);",dd92f996a554bfbc038bea27640ba25dcf298383140a8330dca7cdacf493a701 +test.c,62,7,1,buffer,strlen,Does not handle strings that are not \0-terminated; if given one it may perform an over-read (it could cause a crash if unprotected) (CWE-126),,,CWE-126, n = strlen(d);,db7201c7df7f543ea76febb060bda167e414e71e3d18095fe1def69f8c47a4f6 +test.c,68,3,1,buffer,MultiByteToWideChar,"Requires maximum length in CHARACTERS, not bytes (CWE-120)",,"Risk is very low, the length appears to be in characters not bytes.",CWE-120," MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName)/sizeof(wszUserName[0]));",1813fc329227b38abae867d8023a9e29c7517d679fe55c86f8300dde681b6470 +test.c,70,3,1,buffer,MultiByteToWideChar,"Requires maximum length in CHARACTERS, not bytes (CWE-120)",,"Risk is very low, the length appears to be in characters not bytes.",CWE-120," MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName /sizeof(wszUserName[0]));",7c6cdcb10ad3a16b8bfd56e3dac84829f9bc3e39d4dde74a2be9bbe000102fc5 diff --git a/correct-results.html b/correct-results.html new file mode 100755 index 0000000..3fe1d99 --- /dev/null +++ b/correct-results.html @@ -0,0 +1,344 @@ + + + + +Flawfinder Results + + + + +

Flawfinder Results

+Here are the security scan results from +Flawfinder version 2.0.10, +(C) 2001-2019 David A. Wheeler. +Number of rules (primarily dangerous function names) in C/C++ ruleset: 223 +

+Examining test.c
+Examining test2.c
+ +

Final Results

+
    +
  • test.c:32: [5] (buffer) gets: + Does not check for buffer overflows (CWE-120, CWE-20). Use + fgets() instead. +
    + gets(f);
    +
    +
  • test.c:60: [5] (buffer) strncat: + Easily used incorrectly (e.g., incorrectly computing the correct maximum + size to add) [MS-banned] (CWE-120). + Consider strcat_s, strlcat, snprintf, 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:61: [5] (buffer) _tcsncat: + Easily used incorrectly (e.g., incorrectly computing the correct maximum + size to add) [MS-banned] (CWE-120). + Consider strcat_s, 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:64: [5] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes (CWE-120). 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:66: [5] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes (CWE-120). 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:77: [5] (misc) SetSecurityDescriptorDacl: + Never create NULL ACLs; an attacker can set it to Everyone (Deny All + Access), which would even forbid administrator access (CWE-732). +
    +  SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE);
    +
    +
  • test.c:77: [5] (misc) SetSecurityDescriptorDacl: + Never create NULL ACLs; an attacker can set it to Everyone (Deny All + Access), which would even forbid administrator access (CWE-732). +
    +  SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE);
    +
    +
  • test.c:17: [4] (buffer) strcpy: + Does not check for buffer overflows when copying to destination [MS-banned] + (CWE-120). + Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily + misused). +
    + strcpy(b, a);
    +
    +
  • test.c:20: [4] (buffer) sprintf: + Does not check for buffer overflows (CWE-120). Use + sprintf_s, snprintf, or vsnprintf. +
    + sprintf(s, "hello %s", bug);
    +
    +
  • test.c:21: [4] (buffer) sprintf: + Does not check for buffer overflows (CWE-120). Use + sprintf_s, snprintf, or vsnprintf. +
    + sprintf(s, gettext("hello %s"), bug);
    +
    +
  • test.c:22: [4] (format) sprintf: + Potential format string problem (CWE-134). 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 + (CWE-134). + 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 (CWE-120, CWE-20). 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 (CWE-120, CWE-20). 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 (CWE-134). 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 [MS-banned] + (CWE-120). + 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:56: [4] (buffer) lstrcat: + Does not check for buffer overflows when concatenating to destination + [MS-banned] (CWE-120). +
    +  lstrcat(d,s);
    +
    +
  • test.c:79: [3] (shell) CreateProcess: + This causes a new process to execute and is difficult to use safely (CWE-78). 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:79: [3] (shell) CreateProcess: + This causes a new process to execute and is difficult to use safely (CWE-78). 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:95: [3] (buffer) getopt_long: + Some older implementations do not protect against internal buffer overflows + (CWE-120, CWE-20). 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 [MS-banned] + (CWE-120). + Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy 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 (CWE-120). Use + sprintf_s, 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 improperly restricted, leading to potential + overflows or other issues (CWE-119!/CWE-120). + 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 improperly restricted, leading to potential + overflows or other issues (CWE-119!/CWE-120). + 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 (CWE-120). Make + sure destination can always hold the source data. +
    +  memcpy(d,s); // fail - no size
    +
    +
  • test.c:53: [2] (buffer) memcpy: + Does not check for buffer overflows when copying to destination (CWE-120). Make + sure destination can always hold the source data. +
    +  memcpy(&n,s,sizeof(s)); // fail - sizeof not of destination
    +
    +
  • test.c:54: [2] (buffer) memcpy: + Does not check for buffer overflows when copying to destination (CWE-120). Make + sure destination can always hold the source data. +
    +  memcpy(d,s,n); // fail - size unguessable
    +
    +
  • test.c:55: [2] (buffer) CopyMemory: + Does not check for buffer overflows when copying to destination (CWE-120). Make + sure destination can always hold the source data. +
    +  CopyMemory(d,s);
    +
    +
  • test.c:101: [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? (CWE-362). +
    +  f = fopen("/etc/passwd", "r"); 
    +
    +
  • test.c:15: [1] (buffer) strcpy: + Does not check for buffer overflows when copying to destination [MS-banned] + (CWE-120). + Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy 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 (CWE-120). Use + sprintf_s, 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 (CWE-120). Check + that the limit is sufficiently small, or use a different input function. +
    + scanf("%10s", s);
    +
    +
  • test.c:57: [1] (buffer) strncpy: + Easily used incorrectly; doesn't always \0-terminate or check for invalid + pointers [MS-banned] (CWE-120). +
    +  strncpy(d,s);
    +
    +
  • test.c:58: [1] (buffer) _tcsncpy: + Easily used incorrectly; doesn't always \0-terminate or check for invalid + pointers [MS-banned] (CWE-120). +
    +  _tcsncpy(d,s);
    +
    +
  • test.c:59: [1] (buffer) strncat: + Easily used incorrectly (e.g., incorrectly computing the correct maximum + size to add) [MS-banned] (CWE-120). + Consider strcat_s, strlcat, snprintf, or automatically resizing strings. +
    +  strncat(d,s,10);
    +
    +
  • test.c:62: [1] (buffer) strlen: + Does not handle strings that are not \0-terminated; if given one it may + perform an over-read (it could cause a crash if unprotected) (CWE-126). +
    +  n = strlen(d);
    +
    +
  • test.c:68: [1] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes (CWE-120). 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:70: [1] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes (CWE-120). 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]));
    +
    +
+

Analysis Summary

+

+Hits = 38 +
+Lines analyzed = 122 +
+Physical Source Lines of Code (SLOC) = 84 +
+Hits@level = [0] 16 [1] 9 [2] 9 [3] 3 [4] 10 [5] 7
+Hits@level+ = [0+] 54 [1+] 38 [2+] 29 [3+] 20 [4+] 17 [5+] 7
+Hits/KSLOC@level+ = [0+] 642.857 [1+] 452.381 [2+] 345.238 [3+] 238.095 [4+] 202.381 [5+] 83.3333
+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! +
+See 'Secure Programming HOWTO' +(https://dwheeler.com/secure-programs) for more information. + + diff --git a/correct-results.txt b/correct-results.txt new file mode 100755 index 0000000..fd1d4b3 --- /dev/null +++ b/correct-results.txt @@ -0,0 +1,163 @@ +Flawfinder version 2.0.10, (C) 2001-2019 David A. Wheeler. +Number of rules (primarily dangerous function names) in C/C++ ruleset: 223 +Examining test.c +Examining test2.c + +FINAL RESULTS: + +test.c:32: [5] (buffer) gets: + Does not check for buffer overflows (CWE-120, CWE-20). Use fgets() instead. +test.c:60: [5] (buffer) strncat: + Easily used incorrectly (e.g., incorrectly computing the correct maximum + size to add) [MS-banned] (CWE-120). Consider strcat_s, strlcat, snprintf, + 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:61: [5] (buffer) _tcsncat: + Easily used incorrectly (e.g., incorrectly computing the correct maximum + size to add) [MS-banned] (CWE-120). Consider strcat_s, 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:64: [5] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is high, + it appears that the size is given as bytes, but the function requires size + as characters. +test.c:66: [5] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is high, + it appears that the size is given as bytes, but the function requires size + as characters. +test.c:77: [5] (misc) SetSecurityDescriptorDacl: + Never create NULL ACLs; an attacker can set it to Everyone (Deny All + Access), which would even forbid administrator access (CWE-732). +test.c:77: [5] (misc) SetSecurityDescriptorDacl: + Never create NULL ACLs; an attacker can set it to Everyone (Deny All + Access), which would even forbid administrator access (CWE-732). +test.c:17: [4] (buffer) strcpy: + Does not check for buffer overflows when copying to destination [MS-banned] + (CWE-120). Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy + easily misused). +test.c:20: [4] (buffer) sprintf: + Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or + vsnprintf. +test.c:21: [4] (buffer) sprintf: + Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or + vsnprintf. +test.c:22: [4] (format) sprintf: + Potential format string problem (CWE-134). Make format string constant. +test.c:23: [4] (format) printf: + If format strings can be influenced by an attacker, they can be exploited + (CWE-134). 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 (CWE-120, CWE-20). 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 (CWE-120, CWE-20). 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 (CWE-134). Use a constant format string for syslog. +test.c:49: [4] (buffer) _mbscpy: + Does not check for buffer overflows when copying to destination [MS-banned] + (CWE-120). Consider using a function version that stops copying at the end + of the buffer. +test.c:56: [4] (buffer) lstrcat: + Does not check for buffer overflows when concatenating to destination + [MS-banned] (CWE-120). +test.c:79: [3] (shell) CreateProcess: + This causes a new process to execute and is difficult to use safely + (CWE-78). 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:79: [3] (shell) CreateProcess: + This causes a new process to execute and is difficult to use safely + (CWE-78). 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:95: [3] (buffer) getopt_long: + Some older implementations do not protect against internal buffer overflows + (CWE-120, CWE-20). 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 [MS-banned] + (CWE-120). Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy + easily misused). Risk is low because the source is a constant string. +test.c:19: [2] (buffer) sprintf: + Does not check for buffer overflows (CWE-120). Use sprintf_s, 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 improperly restricted, leading to potential + overflows or other issues (CWE-119!/CWE-120). 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 improperly restricted, leading to potential + overflows or other issues (CWE-119!/CWE-120). 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 (CWE-120). + Make sure destination can always hold the source data. +test.c:53: [2] (buffer) memcpy: + Does not check for buffer overflows when copying to destination (CWE-120). + Make sure destination can always hold the source data. +test.c:54: [2] (buffer) memcpy: + Does not check for buffer overflows when copying to destination (CWE-120). + Make sure destination can always hold the source data. +test.c:55: [2] (buffer) CopyMemory: + Does not check for buffer overflows when copying to destination (CWE-120). + Make sure destination can always hold the source data. +test.c:101: [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? (CWE-362). +test.c:15: [1] (buffer) strcpy: + Does not check for buffer overflows when copying to destination [MS-banned] + (CWE-120). Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy + easily misused). Risk is low because the source is a constant character. +test.c:18: [1] (buffer) sprintf: + Does not check for buffer overflows (CWE-120). Use sprintf_s, 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 + (CWE-120). Check that the limit is sufficiently small, or use a different + input function. +test.c:57: [1] (buffer) strncpy: + Easily used incorrectly; doesn't always \0-terminate or check for invalid + pointers [MS-banned] (CWE-120). +test.c:58: [1] (buffer) _tcsncpy: + Easily used incorrectly; doesn't always \0-terminate or check for invalid + pointers [MS-banned] (CWE-120). +test.c:59: [1] (buffer) strncat: + Easily used incorrectly (e.g., incorrectly computing the correct maximum + size to add) [MS-banned] (CWE-120). Consider strcat_s, strlcat, snprintf, + or automatically resizing strings. +test.c:62: [1] (buffer) strlen: + Does not handle strings that are not \0-terminated; if given one it may + perform an over-read (it could cause a crash if unprotected) (CWE-126). +test.c:68: [1] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is very + low, the length appears to be in characters not bytes. +test.c:70: [1] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is very + low, the length appears to be in characters not bytes. + +ANALYSIS SUMMARY: + +Hits = 38 +Lines analyzed = 122 +Physical Source Lines of Code (SLOC) = 84 +Hits@level = [0] 16 [1] 9 [2] 9 [3] 3 [4] 10 [5] 7 +Hits@level+ = [0+] 54 [1+] 38 [2+] 29 [3+] 20 [4+] 17 [5+] 7 +Hits/KSLOC@level+ = [0+] 642.857 [1+] 452.381 [2+] 345.238 [3+] 238.095 [4+] 202.381 [5+] 83.3333 +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! +See 'Secure Programming HOWTO' +(https://dwheeler.com/secure-programs) for more information. + +Testing for no ending newline: +Lines analyzed = 32 diff --git a/cwe.l b/cwe.l new file mode 100644 index 0000000..8383dfd --- /dev/null +++ b/cwe.l @@ -0,0 +1,29 @@ +%{ + +/* cwe by David A. Wheeler (http://www.dwheeler.com). + This prints anything of the form CWE-# +*/ + +#include +#include +#include + +void out(char *text) { + fputs(text,stdout); +} + +void outchar(char c) { + fputc(c, stdout); +} + + +%} + + +%% +CWE-[1-9][0-9]* { out(yytext); outchar('\n'); } +. { } +\n { } + +%% + diff --git a/flawfinder b/flawfinder new file mode 100755 index 0000000..7adafde --- /dev/null +++ b/flawfinder @@ -0,0 +1,2236 @@ +#!/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.""" + +# 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. +# +# Copyright (C) 2001-2019 David A. Wheeler. +# This is released under the +# GNU General Public License (GPL) version 2 or later (GPL-2.0+): +# +# 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 + +# This code is written to run on both Python 2.7 and Python 3. +# The Python developers did a *terrible* job when they transitioned +# to Python version 3, as I have documented elsewhere. +# Thankfully, more recent versions of Python 3, and the most recent version of +# Python 2, make it possible (though ugly) to write code that runs on both. +# That *finally* makes it possible to semi-gracefully transition. + +from __future__ import division +from __future__ import print_function +import functools +import sys +import re +import string +import getopt +import pickle # To support load/save/diff of hitlist +import os +import glob +import operator # To support filename expansion on Windows +import time +import csv # To support generating CSV format +import hashlib +# import formatter + +version = "2.0.10" + +# Program Options - these are the default values. +# TODO: Switch to boolean types where appropriate. +# We didn't use boolean types originally because this program +# predates Python's PEP 285, which added boolean types to Python 2.3. +# Even after Python 2.3 was released, we wanted to run on older versions. +# That's irrelevant today, but since "it works" there hasn't been a big +# rush to change it. +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? +skipdotdir = 1 # If 1, don't recurse into dirs beginning with "." +# Note: This doesn't affect the command line. +num_links_skipped = 0 # Number of links skipped. +num_dotdirs_skipped = 0 # Number of dotdirs 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) +patch_file = "" # File containing (unified) diff output. +loadhitlist = None +savehitlist = None +diffhitlist_filename = 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) +csv_output = 0 # 1 = Generate CSV +csv_writer = None +omit_time = 0 # 1 = omit time-to-run (needed for testing) +required_regex = None # If non-None, regex that must be met to report +required_regex_compiled = None + +ERROR_ON_DISABLED_VALUE = 999 +error_level = ERROR_ON_DISABLED_VALUE # Level where we're return error code +error_level_exceeded = False + +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. + + +# Send warning message. This is written this way to work on +# Python version 2.5 through Python 3. +def print_warning(message): + sys.stderr.write("Warning: ") + sys.stderr.write(message) + sys.stderr.write("\n") + sys.stderr.flush() + + +# The following code accepts unified diff format from both subversion (svn) +# and GNU diff, which aren't well-documented. It gets filenames from +# "Index:" if exists, else from the "+++ FILENAME ..." entry. +# Note that this is different than some tools (which will use "+++" in +# preference to "Index:"), but subversion's nonstandard format is easier +# to handle this way. +# Since they aren't well-documented, here's some info on the diff formats: +# GNU diff format: +# --- OLDFILENAME OLDTIMESTAMP +# +++ NEWFILENAME NEWTIMESTAMP +# @@ -OLDSTART,OLDLENGTH +NEWSTART,NEWLENGTH @@ +# ... Changes where preceeding "+" is add, "-" is remove, " " is unchanged. +# +# ",OLDLENGTH" and ",NEWLENGTH" are optional (they default to 1). +# GNU unified diff format doesn't normally output "Index:"; you use +# the "+++/---" to find them (presuming the diff user hasn't used --label +# to mess it up). +# +# Subversion format: +# Index: FILENAME +# --- OLDFILENAME (comment) +# +++ NEWFILENAME (comment) +# @@ -OLDSTART,OLDLENGTH +NEWSTART,NEWLENGTH @@ +# +# In subversion, the "Index:" always occurs, and note that paren'ed +# comments are in the oldfilename/newfilename, NOT timestamps like +# everyone else. +# +# Git format: +# diff --git a/junk.c b/junk.c +# index 03d668d..5b005a1 100644 +# --- a/junk.c +# +++ b/junk.c +# @@ -6,4 +6,5 @@ main() { +# +# Single Unix Spec version 3 (http://www.unix.org/single_unix_specification/) +# does not specify unified format at all; it only defines the older +# (obsolete) context diff format. That format DOES use "Index:", but +# only when the filename isn't specified otherwise. +# We're only supporting unified format directly; if you have an older diff +# format, use "patch" to apply it, and then use "diff -u" to create a +# unified format. +# + +diff_index_filename = re.compile(r'^Index:\s+(?P.*)') +diff_git_filename = re.compile(r'^diff --git a/.* b/(?P.*)$') +diff_newfile = re.compile(r'^\+\+\+\s(?P.*)$') +diff_hunk = re.compile(r'^@@ -\d+(,\d+)?\s+\+(?P\d+)[, ].*@@$') +diff_line_added = re.compile(r'^\+[^+].*') +diff_line_del = re.compile(r'^-[^-].*') +# The "+++" newfile entries have the filename, followed by a timestamp +# or " (comment)" postpended. +# Timestamps can be of these forms: +# 2005-04-24 14:21:39.000000000 -0400 +# Mon Mar 10 15:13:12 1997 +# Also, "newfile" can have " (comment)" postpended. Find and eliminate this. +# Note that the expression below is Y10K (and Y100K) ready. :-). +diff_findjunk = re.compile( + r'^(?P.*)(' + r'(\s\d\d\d\d+-\d\d-\d\d\s+\d\d:\d[0-9:.]+Z?(\s+[\-\+0-9A-Z]+)?)|' + r'(\s[A-Za-z][a-z]+\s[A-za-z][a-z]+\s\d+\s\d+:\d[0-9:.]+Z?' + r'(\s[\-\+0-9]*)?\s\d\d\d\d+)|' + r'(\s\(.*\)))\s*$' +) + + +def is_svn_diff(sLine): + if sLine.find('Index:') != -1: + return True + return False + + +def is_gnu_diff(sLine): + if sLine.startswith('--- '): + return True + return False + + +def is_git_diff(sLine): + if sLine.startswith('diff --git a'): + return True + return False + + +def svn_diff_get_filename(sLine): + return diff_index_filename.match(sLine) + + +def gnu_diff_get_filename(sLine): + newfile_match = diff_newfile.match(sLine) + if newfile_match: + patched_filename = newfile_match.group('filename').strip() + # Clean up filename - remove trailing timestamp and/or (comment). + return diff_findjunk.match(patched_filename) + return None + + +def git_diff_get_filename(sLine): + return diff_git_filename.match(sLine) + + +# For each file found in the file input_patch_file, keep the +# line numbers of the new file (after patch is applied) which are added. +# We keep this information in a hash table for a quick access later. +# +def load_patch_info(input_patch_file): + patch = {} + line_counter = 0 + initial_number = 0 + try: + hPatch = open(input_patch_file, 'r') + except BaseException: + print("Error: failed to open", h(input_patch_file)) + sys.exit(10) + + patched_filename = "" # Name of new file patched by current hunk. + + sLine = hPatch.readline() + # Heuristic to determine if it's a svn diff, git diff, or a GNU diff. + if is_svn_diff(sLine): + fn_get_filename = svn_diff_get_filename + elif is_git_diff(sLine): + fn_get_filename = git_diff_get_filename + elif is_gnu_diff(sLine): + fn_get_filename = gnu_diff_get_filename + else: + print("Error: Unrecognized patch format") + sys.exit(11) + + while True: # Loop-and-half construct. Read a line, end loop when no more + + # This is really a sequence of if ... elsif ... elsif..., but + # because Python forbids '=' in conditions, we do it this way. + filename_match = fn_get_filename(sLine) + if filename_match: + patched_filename = filename_match.group('filename').strip() + if patched_filename in patch: + error("filename occurs more than once in the patch: %s" % + patched_filename) + sys.exit(12) + else: + patch[patched_filename] = {} + else: + hunk_match = diff_hunk.match(sLine) + if hunk_match: + if patched_filename == "": + error( + "wrong type of patch file : " + "we have a line number without having seen a filename" + ) + sys.exit(13) + initial_number = hunk_match.group('linenumber') + line_counter = 0 + else: + line_added_match = diff_line_added.match(sLine) + if line_added_match: + line_added = line_counter + int(initial_number) + patch[patched_filename][line_added] = True + # Let's also warn about the lines above and below this one, + # so that errors that "leak" into adjacent lines are caught. + # Besides, if you're creating a patch, you had to at + # least look at adjacent lines, + # so you're in a position to fix them. + patch[patched_filename][line_added - 1] = True + patch[patched_filename][line_added + 1] = True + line_counter += 1 + else: + line_del_match = diff_line_del.match(sLine) + if line_del_match is None: + line_counter += 1 + + sLine = hPatch.readline() + if sLine == '': + break # Done reading. + + return patch + + +def htmlize(s): + # Take s, and return legal (UTF-8) HTML. + return s.replace("&", "&").replace("<", "<").replace(">", ">") + + +def h(s): + # htmlize s if we're generating html, otherwise just return s. + return htmlize(s) if output_format else s + + +def print_multi_line(text): + # Print text as multiple indented lines. + width = 78 + prefix = " " + starting_position = len(prefix) + 1 + # + print(prefix, end='') + position = starting_position + # + for w in text.split(): + if len(w) + position >= width: + print() + print(prefix, end='') + position = starting_position + print(' ', end='') + print(w, end='') + position += len(w) + 1 + + +# This matches references to CWE identifiers, so we can HTMLize them. +# We don't refer to CWEs with one digit, so we'll only match on 2+ digits. +link_cwe_pattern = re.compile(r'(CWE-([1-9][0-9]+))([,()!/])') + +# This matches the CWE data, including multiple entries. +find_cwe_pattern = re.compile(r'\(CWE-[^)]*\)') + + +class Hit(object): + """ + 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: + setattr(self, key, other[key]) + + def __getitem__(self, X): # Define this so this works: "%(line)" % hit + return getattr(self, X) + + def __eq__(self, other): + return (self.filename == other.filename + and self.line == other.line + and self.column == other.column + and self.level == other.level + and self.name == other.name) + + def __ne__(self, other): + return not self == other + + # return CWEs + def cwes(self): + result = find_cwe_pattern.search(self.warning) + return result.group()[1:-1] if result else '' + + def fingerprint(self): + """Return fingerprint of stripped context.""" + m = hashlib.sha256() + m.update(self.context_text.strip().encode('utf-8')) + return m.hexdigest() + + # Show as CSV format + def show_csv(self): + csv_writer.writerow([ + self.filename, self.line, self.column, self.level, self.category, + self.name, self.warning, self.suggestion, self.note, + self.cwes(), self.context_text, self.fingerprint() + ]) + + def show(self): + if csv_output: + self.show_csv() + return + if output_format: + print("

  • ", end='') + sys.stdout.write(h(self.filename)) + + if show_columns: + print(":%(line)s:%(column)s:" % self, end='') + else: + print(":%(line)s:" % self, end='') + + if output_format: + print(" ", end='') + # Extra space before risk level in text, makes it easier to find: + print(" [%(level)s]" % self, end=' ') + if output_format: + print(" ", end='') + print("(%(category)s)" % self, end=' ') + if output_format: + print(" ", end='') + print(h("%(name)s:" % self), end='') + main_text = h("%(warning)s. " % self) + if output_format: # Create HTML link to CWE definitions + main_text = link_cwe_pattern.sub( + r'\1\3', + main_text) + if single_line: + print(main_text, end='') + if self.suggestion: + print(" " + h(self.suggestion) + ".", end='') + print(' ' + h(self.note), end='') + else: + if self.suggestion: + main_text += h(self.suggestion) + ". " + main_text += h(self.note) + print() + print_multi_line(main_text) + if output_format: + print(" ", end='') + 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 required_regex and (required_regex_compiled.search(hit.warning) is + None): + return + if linenumber == ignoreline: + 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 += 1 + else: + return [] + else: # Never found a reasonable ending. + return [] + 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 += 1 + elif incomment: + if c == '*' and text[i:i + 2] == '*/': + incomment = 0 + i += 1 + else: + if c == '"': + instring = 1 + elif c == "'": + instring = 2 + elif c == '/' and text[i:i + 2] == '/*': + incomment = 1 + i += 1 + elif c == '/' and text[i:i + 2] == '//': + while i < len(text) and text[i] != "\n": + i += 1 + elif c == '\\' and text[i:i + 2] == '\\"': + i += 1 # Handle exposed '\"' + elif c == '(': + parenlevel += 1 + elif c == ',' and (parenlevel == 1): + parameters.append( + p_trailingbackslashes.sub('', text[currentstart:i]).strip()) + currentstart = i + 1 + elif c == ')': + parenlevel -= 1 + if parenlevel <= 0: + parameters.append( + p_trailingbackslashes.sub( + '', text[currentstart:i]).strip()) + # 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 += 1 + internal_warn("Parsing failed to find end of parameter list in %s" % + text[pos:pos + 200]) + return [] # Treat unterminated list as an empty list + + +# 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'. + + In particular, strip away calls to gettext() and _(). + """ + match = gettext_pattern.search(text) + if match: + return match.group(1).strip() + match = undersc_pattern.search(text) + if match: + return match.group(3).strip() + return text + + +p_trailingbackslashes = re.compile(r'(\s|\\(\n|\r))*$') + +p_c_singleton_string = re.compile(r'^\s*L?"([^\\]|\\[^0-6]|\\[0-6]+)?"\s*$') + + +def c_singleton_string(text): + "Returns true if text is a C string with 0 or 1 character." + return 1 if p_c_singleton_string.search(text) else 0 + + +# This string defines a C constant. +p_c_constant_string = re.compile(r'^\s*L?"([^\\]|\\[^0-6]|\\[0-6]+)*"$') + + +def c_constant_string(text): + "Returns true if text is a constant C string." + return 1 if p_c_constant_string.search(text) else 0 + +# Precompile patterns for speed. + +p_memcpy_sizeof = re.compile(r'sizeof\s*\(\s*([^)\s]*)\s*\)') +p_memcpy_param_amp = re.compile(r'&?\s*(.*)') + +def c_memcpy(hit): + if len(hit.parameters) < 4: # 3 parameters + add_warning(hit) + return + + m1 = re.search(p_memcpy_param_amp, hit.parameters[1]) + m3 = re.search(p_memcpy_sizeof, hit.parameters[3]) + if not m1 or not m3 or m1.group(1) != m3.group(1): + add_warning(hit) + + +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. +# We check because 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. + # At one time we warned that very old systems sometimes incorrectly + # allow buffer overflows on snprintf/vsnprintf, but those systems + # are now very old, and snprintf is an important potential tool for + # countering buffer overflows. + # 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 risky." + 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 hit.parameters is None: + # Serious parameter problem, e.g., none, or a string constant that + # never finishes. + hit.warning = "format string parameter problem" + hit.suggestion = "Check if required parameters present and quotes close." + hit.level = 4 + hit.category = "format" + hit.url = "" + elif 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 (CWE-134)" + 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 (CWE-120)") + 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*\[\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 cpp_unsafe_stl(hit): + # Use one of the overloaded classes from the STL in C++14 and higher + # instead of the > 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 = text.rfind("\n", 0, position) + if newline == -1: + return position + 1 + return position - newline + + +def get_context(text, position): + "Get surrounding text line starting from text[position]" + linestart = text.rfind("\n", 0, position + 1) + 1 + lineend = text.find("\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 += 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 + # Note: On Python 2 this is inefficient, because the "range" operator + # creates a list. We used to use "xrange", but that doesn't exist + # in Python3. So we use "range" which at least works everywhere. + # If speed is vital on Python 2 we could replace this with xrange. + for i in range(len(hitlist) - 1, -1, -1): + if hitlist[i].filename == filename and 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 += 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_whitespace = re.compile(r'[ \t\v\f]+') +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, patch_infos): + 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 (patch_infos is not None) and (f not in patch_infos): + # This file isn't in the patch list, so don't bother analyzing it. + if not quiet: + if output_format: + print("Skipping unpatched file ", h(f), "
    ") + else: + print("Skipping unpatched file", f) + sys.stdout.flush() + return + + if f == "-": + my_input = sys.stdin + else: + # Symlinks should never get here, but just in case... + if (not allowlink) and os.path.islink(f): + print("BUG! Somehow got a symlink in process_c_file!") + num_links_skipped += 1 + return + try: + my_input = open(f, "r") + except BaseException: + print("Error: failed to open", h(f)) + sys.exit(14) + + # 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 = "".join(my_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. + + # Skip any whitespace + m = p_whitespace.match(text, i) + if m: + i = m.end(0) + + if i >= len(text): + c = "\n" # Last line with no newline, we're done + else: + 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 += 1 + sumlines += 1 + linebegin = 1 + if codeinline: + sloc += 1 + codeinline = 0 + i += 1 + continue + i += 1 # From here on, text[i] points to next character. + if i < len(text): + nextc = text[i] + else: + nextc = '' + if incomment: + if c == '*' and nextc == '/': + i += 1 + incomment = 0 + elif instring: + if c == '\\' and (nextc != "\n"): + 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 += 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 < len(text) and text[i] != "\n": + i += 1 + elif c == '"': + instring = 1 + codeinline = 1 + elif c == "'": + instring = 2 + codeinline = 1 + else: + codeinline = 1 # It's not whitespace, comment, or string. + m = p_c_word.match(text, i - 1) + if m: # Do we have a word? + startpos = i - 1 + endpos = m.end(0) + i = endpos + word = text[startpos:endpos] + # print "Word is:", text[startpos:endpos] + if (word in c_ruleset) and c_valid_match(text, endpos): + if ((patch_infos is None) + or ((patch_infos is not None) and + (linenumber in patch_infos[f]))): + # FOUND A MATCH, setup & call hook. + # print "HIT: #%s#\n" % word + # Don't use the tuple assignment form, e.g., a,b=c,d + # because Python (least 2.2.2) does that slower + # (presumably because it creates & destroys temporary tuples) + hit = Hit(c_ruleset[word]) + hit.name = word + hit.start = startpos + hit.end = endpos + hit.line = linenumber + hit.column = find_column(text, startpos) + hit.filename = filename + hit.context_text = get_context(text, startpos) + hit.parameters = extract_c_parameters(text, endpos) + if hit.extract_lookahead: + hit.lookahead = text[startpos: + startpos + max_lookahead] + hit.hook(hit) + elif p_digits.match(c): + while i < len(text) and p_digits.match( + text[i]): # Process a number. + i += 1 + # else some other character, which we ignore. + # End of loop through text. Wrap up. + if codeinline: + sloc += 1 + if incomment: + error("File ended while in comment.") + if instring: + error("File ended while in string.") + + +def expand_ruleset(ruleset): + # Rulesets can have compressed sets of rules + # (multiple function names separated by "|". + # Expand the given ruleset. + # Note that this "for" loop modifies the ruleset while it's iterating, + # so we *must* convert the keys into a list before iterating. + for rule in list(ruleset.keys()): + if "|" in rule: # We found a rule to expand. + for newrule in rule.split("|"): + if newrule in ruleset: + print("Error: Rule %s, when expanded, overlaps %s" % ( + rule, newrule)) + sys.exit(15) + ruleset[newrule] = ruleset[rule] + del ruleset[rule] + # To print out the set of keys in the expanded ruleset, run: + # print `ruleset.keys()` + + +def display_ruleset(ruleset): + # First, sort the list by function name: + sortedkeys = sorted(ruleset.keys()) + # Now, print them out: + for key in sortedkeys: + print(key + "\t" + str( + ruleset[key][1] + ) + "\t" + ruleset[key][2]) # function name, default level, default warning + + +def initialize_ruleset(): + expand_ruleset(c_ruleset) + if showheading: + print("Number of rules (primarily dangerous function names) in C/C++ ruleset:", len( + c_ruleset)) + if output_format: + print("

    ") + 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 csv_output: + csv_writer.writerow([ + 'File', 'Line', 'Column', 'Level', 'Category', 'Name', 'Warning', + 'Suggestion', 'Note', 'CWEs', 'Context', 'Fingerprint' + ]) + return + 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-2019 David A. Wheeler.') + else: + print("Flawfinder version %s, (C) 2001-2019 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, # C++ + '.CC': 1, + '.c++': 1, # C++. + '.pcc': 1, # Oracle C++ + '.hpp': 1, + '.H': 1, # .h - usually C++. +} + + +def maybe_process_file(f, patch_infos): + # 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, num_dotdirs_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 += 1 + return + base_filename = os.path.basename(f) + if (skipdotdir and len(base_filename) > 1 + and (base_filename[0] == ".")): + if not quiet: + print_warning("Skipping directory with initial dot " + h(f)) + num_dotdirs_skipped += 1 + return + for dir_entry in os.listdir(f): + maybe_process_file(os.path.join(f, dir_entry), patch_infos) + # 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 = f.rfind(".") + if dotposition > 1: + extension = f[dotposition:] + if extension in c_extensions: + # 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 += 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: + # We want to know the difference only with files found in the + # patch. + if ((patch_infos is None) + or (patch_infos is not None and (f in patch_infos))): + process_c_file(f, patch_infos) + + +def process_file_args(files, patch_infos): + # 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 += 1 + elif os.path.isfile(f) or f == "-": + # If on the command line, FORCE processing of it. + # Currently, we only process C/C++. + # check if we only want to review a patch + if ((patch_infos is not None and f in patch_infos) + or (patch_infos is None)): + process_c_file(f, patch_infos) + 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, patch_infos) + elif not os.path.exists(f): + if not quiet: + # Help humans avoid a long mysterious debugging session. + # Sometimes people copy/paste from HTML that has a leading + # en dash (\u2013 aka 0xE2 0x80 0x93) or + # em dash (\u2014 aka 0xE2 0x80 0x94) instead of the + # correct dash marker (in an attempt to make things "pretty"). + # These symbols *look* like the regular dash + # option marker, but they are not the same characters. + # If there's no such file, give a special warning, + # because otherwise this can be extremely + # difficult for humans to notice. We'll do the check in + # this odd way so it works on both Python 2 and Python 3. + # (Python 3 wants \u...). + # Note that we *only* make this report if the file doesn't + # exist - if someone asks to process a file with this crazy + # name, and it exists, we'll process it without complaint. + if (h(f).startswith("\xe2\x80\x93") or + h(f).startswith("\xe2\x80\x94") or + h(f).startswith("\u2013") or + h(f).startswith("\u2014")): + print_warning( + "Skipping non-existent filename starting with em dash or en dash " + + h(f)) + else: + print_warning("Skipping non-existent file " + h(f)) + else: + if not quiet: + print_warning("Skipping non-regular file " + h(f)) + + +def usage(): + print(""" +flawfinder [--help | -h] [--version] [--listrules] + [--allowlink] [--followdotdir] [--nolink] + [--patch filename | -P filename] + [--inputs | -I] [--minlevel X | -m X] + [--falsepositive | -F] [--neverignore | -n] + [--context | -c] [--columns | -C] [--dataonly | -D] + [--html | -H] [--immediate | -i] [--singleline | -S] + [--omittime] [--quiet | -Q] + [--loadhitlist F] [--savehitlist F] [--diffhitlist F] + [--] [source code file or source root directory]+ + + The options cover various aspects of flawfinder as follows. + + Documentation: + --help | -h Show this usage help. + --version Show version number. + --listrules List the rules in the ruleset (rule database). + + Selecting Input Data: + --allowlink Allow symbolic links. + --followdotdir + Follow directories whose names begin with ".". + Normally they are ignored. + --nolink Skip symbolic links (ignored). + --patch F | -P F + Display information related to the patch F + (patch must be already applied). + + Selecting Hits to Display: + --inputs | -I + Show only functions that obtain data from outside the program; + this also sets minlevel to 0. + -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. + --falsepositive | -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 char- + acter arrays aren't noted. Thus, if you have use a vari- + able named "access" everywhere, this will eliminate refer- + ences 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. + --neverignore | -n + Never ignore security issues, even if they have an ``ignore'' + directive in a comment. + --regex PATTERN | -e PATTERN + Only report hits that match the regular expression PATTERN. + + Selecting Output Format: + --columns | -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). + --context | -c + Show context (the line having the "hit"/potential flaw) + --dataonly | -D + Don't display the headers and footers of the analysis; + use this along with --quiet to get just the results. + --html | -H + Display as HTML output. + --immediate | -i + Immediately display hits (don't just wait until the end). + --singleline | -S + Single-line output. + --omittime Omit time to run. + --quiet | -Q + Don't display status information (i.e., which files are being + examined) while the analysis is going on. + --error-level=LEVEL + Return a nonzero (false) error code if there is at least one + hit of LEVEL or higher. If a diffhitlist is provided, + hits noted in it are ignored. + This option can be useful within a continuous integration script, + especially if you mark known-okay lines as "flawfinder: ignore". + Usually you want level to be fairly high, such as 4 or 5. + By default, flawfinder returns 0 (true) on a successful run. + + Hitlist Management: + --savehitlist=F + Save all hits (the "hitlist") to F. + --loadhitlist=F + Load hits from F instead of analyzing source programs. + --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, skipdotdir, omit_time + global output_format, minimum_level, show_immediately, single_line + global csv_output, csv_writer + global error_level + global required_regex, required_regex_compiled + global falsepositive + global show_columns, never_ignore, quiet, showheading, list_rules + global loadhitlist, savehitlist, diffhitlist_filename + global patch_file + try: + # Note - as a side-effect, this sets sys.argv[]. + optlist, args = getopt.getopt(sys.argv[1:], "ce:m:nih?CSDQHIFP:", [ + "context", "minlevel=", "immediate", "inputs", "input", "nolink", + "falsepositive", "falsepositives", "columns", "listrules", + "omittime", "allowlink", "patch=", "followdotdir", "neverignore", + "regex=", "quiet", "dataonly", "html", "singleline", "csv", + "error-level=", + "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 == "--followdotdir": + skipdotdir = 0 + elif opt == "--listrules": + list_rules = 1 + elif opt == "--html" or opt == "-H": + output_format = 1 + single_line = 0 + elif opt == "--minlevel" or opt == "-m": + minimum_level = int(value) + elif opt == "--singleline" or opt == "-S": + single_line = 1 + elif opt == "--csv": + csv_output = 1 + quiet = 1 + showheading = 0 + csv_writer = csv.writer(sys.stdout) + elif opt == "--error-level": + error_level = int(value) + elif opt == "--immediate" or opt == "-i": + show_immediately = 1 + elif opt == "-n" or opt == "--neverignore": + never_ignore = 1 + elif opt == "-e" or opt == "--regex": + required_regex = value + # This will raise an exception if it can't be compiled as a + # regex: + required_regex_compiled = re.compile(required_regex) + elif opt == "-P" or opt == "--patch": + # Note: This is -P, so that a future -p1 option can strip away + # pathname prefixes (with the same option name as "patch"). + patch_file = value + # If we consider ignore comments we may change a line which was + # previously ignored but which will raise now a valid warning without + # noticing it now. So, set never_ignore. + 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_filename = value + display_header() + if showheading: + print("Showing hits not in", value) + elif opt == "--version": + print(version) + sys.exit(0) + elif opt in ['-h', '-?', '--help']: + # We accept "-?" but do not document it. On Unix-like systems the + # question mark in "-?" should be escaped, and many forget + # that. + 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:] = functools.reduce(operator.add, + list(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 as text: + print("*** getopt error:", text) + usage() + sys.exit(16) + if output_format == 1 and list_rules == 1: + print('You cannot list rules in HTML format') + sys.exit(20) + + +def process_files(): + """Process input (files or hitlist); return True if okay.""" + global hitlist + if loadhitlist: + f = open(loadhitlist, "rb") + hitlist = pickle.load(f) + return True + else: + patch_infos = None + if patch_file != "": + patch_infos = load_patch_info(patch_file) + files = sys.argv[1:] + if not files: + print("*** No input files") + return None + process_file_args(files, patch_infos) + return True + + +def hitlist_sort_key(hit): + """Sort key for hitlist.""" + return (-hit.level, hit.filename, hit.line, hit.column, hit.name) + + +def show_final_results(): + global hitlist + global error_level_exceeded + count = 0 + count_per_level = {} + count_per_level_and_up = {} + # Name levels directly, to avoid Python "range" (a Python 2/3 difference) + possible_levels = (0, 1, 2, 3, 4, 5) + for i in possible_levels: # Initialize count_per_level + count_per_level[i] = 0 + for i in possible_levels: # Initialize count_per_level_and_up + count_per_level_and_up[i] = 0 + if show_immediately or not quiet: # Separate the final results. + print() + if showheading: + if output_format: + print("

    Final Results

    ") + else: + print("FINAL RESULTS:") + print() + hitlist.sort(key=hitlist_sort_key) + # 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_filename: + diff_file = open(diffhitlist_filename, 'rb') + diff_hitlist = pickle.load(diff_file) + if output_format: + print("
          ") + for hit in hitlist: + if not diffhitlist_filename or hit not in diff_hitlist: + count_per_level[hit.level] = count_per_level[hit.level] + 1 + if hit.level >= minimum_level: + hit.show() + count += 1 + if hit.level >= error_level: + error_level_exceeded = True + if output_format: + print("
        ") + if diffhitlist_filename: + diff_file.close() + # Done with list, show the post-hitlist summary. + if showheading: + if output_format: + print("

        Analysis Summary

        ") + else: + print() + print("ANALYSIS SUMMARY:") + if output_format: + print("

        ") + else: + print() + if count > 0: + print("Hits =", count) + else: + print("No hits found.") + if output_format: + print("
        ") + # 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 + if required_regex: + print("Hits limited to regular expression " + required_regex) + print("Lines analyzed = %d" % sumlines, end='') + if time_analyzing > 0 and not omit_time: # Avoid divide-by-zero. + print(" in approximately %.2f seconds (%.0f lines/second)" % ( + time_analyzing, (sumlines / time_analyzing))) + 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 =", end='') + for i in possible_levels: + print(" [%d] %3d" % (i, count_per_level[i]), end='') + if output_format: + print("
        ") + else: + print() + # Compute hits at "level x or higher" + print("Hits@level+ =", end='') + for i in possible_levels: + for j in possible_levels: + if j >= i: + 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 possible_levels: + print(" [%d+] %3d" % (i, count_per_level_and_up[i]), end='') + if output_format: + print("
        ") + else: + print() + if sloc > 0: + print("Hits/KSLOC@level+ =", end='') + for i in possible_levels: + print(" [%d+] %3g" % ( + i, count_per_level_and_up[i] * 1000.0 / sloc), end='') + 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_dotdirs_skipped: + print("Dot directories skipped =", num_dotdirs_skipped, "(--followdotdir overrides)") + 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("See 'Secure Programming HOWTO'") + print("(https://dwheeler.com/secure-programs) for more information.") + else: + print("See 'Secure Programming HOWTO'") + print("(https://dwheeler.com/secure-programs) for more information.") + if output_format: + print("") + print("") + + +def save_if_desired(): + # We'll save entire hitlist, even if only differences displayed. + if savehitlist: + if not quiet: + print("Saving hitlist to", savehitlist) + f = open(savehitlist, "wb") + pickle.dump(hitlist, f) + f.close() + + +def flawfind(): + process_options() + display_header() + initialize_ruleset() + if process_files(): + show_final_results() + save_if_desired() + return 1 if error_level_exceeded else 0 + + +if __name__ == '__main__': + try: + sys.exit(flawfind()) + except KeyboardInterrupt: + print("*** Flawfinder interrupted") diff --git a/flawfinder.1 b/flawfinder.1 new file mode 100644 index 0000000..71412c4 --- /dev/null +++ b/flawfinder.1 @@ -0,0 +1,1268 @@ +'\" +.\" (C) Copyright 2001-2018 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 "4 Apr 2018" "Flawfinder" "Flawfinder" +.SH NAME +flawfinder \- lexically find potential security flaws ("hits") in source code +.SH SYNOPSIS +.B flawfinder +.\" Documentation: +.RB [ \-\-help | \-h ] +.RB [ \-\-version ] +.RB [ \-\-listrules ] +.br +.\" Selecting Input Data: +.RB [ \-\-allowlink ] +.RB [ \-\-followdotdir ] +.RB [ \-\-nolink ] +.br +.RB [ \-\-patch=\fIfilename\fR | \-P\ \fIfilename\fR ] +.br +.\" Selecting Hits to Display: +.RB [ \-\-inputs | \-I ] +[ \fB\-\-minlevel=\fR\fIX\fR | \fB\-m\fR\ \fIX\fR ] +.RB [ \-\-falsepositive | \-F ] +.br +.RB [ \-\-neverignore | \-n ] +.br +[\fB\-\-regex=\fR\fIPATTERN\fR | \fB\-e\fR \fIPATTERN\fR] +.br +.\" Selecting Output Format: +.RB [ \-\-context | \-c ] +.RB [ \-\-columns | \-C ] +.RB [ \-\-csv ] +.RB [ \-\-dataonly | \-D ] +.RB [ \-\-html | \-H ] +.RB [ \-\-immediate | -i ] +.RB [ \-\-singleline | \-S ] +.RB [ \-\-omittime ] +.RB [ \-\-quiet | \-Q ] +.RB [ \-\-error-level=\fRLEVEL\fR ] +.br +.\" Managing hit list. +[\fB\-\-loadhitlist=\fR\fIF\fR] +[\fB\-\-savehitlist=\fR\fIF\fR] +[\fB\-\-diffhitlist=\fR\fIF\fR] +.br +.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. +Flawfinder does \fInot\fR require that you be able to build your software, +so it can be used even with incomplete source code. +If you only want to have \fIchanges\fR reviewed, save a unified diff +of those changes (created by GNU "diff -u" or "svn diff" or "git diff") +in a patch file and use the \-\-patch (\-P) option. +.PP +Flawfinder will produce a list of ``hits'' (potential +security flaws, also called findings), +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 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. +Hit descriptions also note the relevant +Common Weakness Enumeration (CWE) identifier(s) in parentheses, +as discussed below. +Flawfinder is officially CWE-Compatible. +Hit descriptions with "[MS-banned]" indicate functions that are in the +banned list of functions released by Microsoft; see +http://msdn.microsoft.com/en-us/library/bb288454.aspx +for more information about banned functions. +.PP +Not every hit (aka finding) 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 +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 comment directives say +(more confusingly, \-\-neverignore ignores the ignores). +.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. +The \-\-listrules option reports the list of current rules and their +default risk levels. +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 +Flawfinder is a simple tool, leading to some fundamental pros and cons. +Flawfinder works by doing simple lexical tokenization +(skipping comments and correctly tokenizing strings), +looking for token matches to the database +(particularly to find function calls). +Flawfinder is thus similar to RATS and ITS4, which also +use simple lexical tokenization. +Flawfinder then examines the +text of the function parameters to estimate risk. +Unlike tools such as splint, gcc's warning flags, +and clang, flawfinder does \fInot\fR use or have access to +information about control flow, data flow, or data types when +searching for potential vulnerabilities or estimating the level of risk. +Thus, flawfinder will necessarily +produce many false positives for vulnerabilities +and fail to report many vulnerabilities. +On the other hand, flawfinder can find vulnerabilities in programs that +cannot be built or cannot be linked. +It can often work with programs that cannot even be compiled +(at least by the reviewer's tools). +Flawfinder also doesn't get as confused by macro definitions +and other oddities that more sophisticated tools have trouble with. +Flawfinder can also be useful as a simple +introduction to static analysis tools in general, +since it is easy to start using and easy to understand. +.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", ".c++", ".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 +(the \-\-allowlink option follows symbolic links). +.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 can easily integrate into a continuous integration system. +You might want to check out the \-\-error\-level option to help do that. +.PP +Flawfinder is released under the GNU GPL license version 2 or later (GPLv2+). +.PP +Flawfinder 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. +Flawfinder is similar in many ways to RATS, if you are familiar with RATS. + +.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 see a large number of entries. +Each entry has 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 "https://dwheeler.com/secure-programs" +.I "Secure Programming HOWTO" +.UE +at +https://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 input data, +select which hits to display, +select the output format, +and perform hitlist management. +The commonly-used flawfinder options +support the standard option syntax defined in the +POSIX (Issue 7, 2013 Edition) section ``Utility Conventions''. +Flawfinder also supports the GNU long options +(double-dash options of form \-\-\fIoption\fR) +as defined in the \fIGNU C Library Reference Manual\fR +``Program Argument Syntax Conventions'' +and \fIGNU Coding Standards\fR ``Standards for Command Line Interfaces''. +Long option arguments can be provided as ``--name=value'' or ``-name value''. +All options can be accessed using the more +readable GNU long option conventions; +some less commonly used options can \fIonly\fR be accessed +using long option conventions. + +.SS "Documentation" + +.TP 12 +.BI \-\-help +.TP +.BI \-h +.\" Leave -? undocumented... it also invokes help. +Show usage (help) information. + +.TP +.BI \-\-version +Shows (just) the version number and exits. + +.TP 12 +.BI \-\-listrules +List the terms (tokens) +that trigger further examination, their default risk level, +and the default warning (including the CWE identifier(s), if applicable), +all tab-separated. +The terms are primarily names of potentially-dangerous functions. +Note that the reported risk level and warning +for some specific code may be different than the default, +depending on how the term is used. +Combine with \-D if you do not want the usual header. +Flawfinder version 1.29 changed the separator from spaces to tabs, and +added the default warning field. + +.SS "Selecting Input Data" + +.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 \-\-followdotdir +Enter directories whose names begin with ".". +Normally such directories are ignored, since they normally +include version control private data (such as .git/ or .svn/), +build metadata (such as .makepp), +configuration information, and so on. + +.TP +.BI \-\-nolink +Ignored. +Historically this disabled following symbolic links; +this behavior is now the default. + +.TP 12 +\fB\-\-patch=\fR\fIpatchfile\fR +.TP +\fB\-P\fR \fIpatchfile\fR +Examine the selected files or directories, but only report hits in lines +that are added or modified as described in the given patch file. +The patch file must be in a recognized unified diff format +(e.g., the output of GNU "diff -u old new", "svn diff", or "git diff [commit]"). +Flawfinder assumes that the patch has already been applied to the files. +The patch file can also include changes to irrelevant files +(they will simply be ignored). +The line numbers given in the patch file are used to determine which +lines were changed, so if you have modified the files since the +patch file was created, regenerate the patch file first. +Beware that the file names of the new files +given in the patch file must match exactly, +including upper/lower case, path prefix, and directory +separator (\\ vs. /). +Only unified diff format is accepted (GNU diff, svn diff, and +git diff output is okay); +if you have a different format, again regenerate it first. +Only hits that occur on resultant changed lines, or immediately +above and below them, are reported. +This option implies \-\-neverignore. +\fBWarning\fR: Do \fInot\fR pass a patch file without the +\fB\-P\fR, because flawfinder will then try to treat the file as a +source file. +This will often work, but the line numbers will be relative +to the beginning of the patch file, not the positions in the +source code. +Note that you \fBmust\fR also provide the actual files to analyze, +and not just the patch file; when using \fB\-P\fR files are only reported +if they are both listed in the patch and also listed (directly or indirectly) +in the list of files to analyze. + + +.SS "Selecting Hits to Display" + +.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. + +.TP +\fB\-\-regexp=\fR\fIPATTERN\fR +.TP +\fB-e\fR \fIPATTERN\fR +Only report hits with text that matches the regular expression pattern PATTERN. +For example, to only report hits containing the text "CWE-120", +use ``\-\-regex CWE-120''. +These option flag names are the same as grep. + + +.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 \-\-csv +Generate output in comma-separated-value (CSV) format. +This is the recommended format for sending to other tools for processing. +It will always generate a header row, followed by 0 or more data rows +(one data row for each hit). +Selecting this option automatically enables \-\-quiet and +\-\-dataonly. +The headers are mostly self-explanatory. +"File" is the filename, "Line" is the line number, +"Column" is the column (starting from 1), +"Level" is the risk level (0-5, 5 is riskiest), +"Category" is the general flawfinder category, +"Name" is the name of the triggering rule, +"Warning" is text explaining why it is a hit (finding), +"Suggestion" is text suggesting how it might be fixed, +"Note" is other explanatory notes, +"CWEs" is the list of one or more CWEs, +"Context" is the source code line triggering the hit, +and "Fingerprint" is the SHA-256 hash of the context once +its leading and trailing whitespace have been removed +(the fingerprint may help detect and eliminate later duplications). +If you use Python3, the hash is of the context when encoded as UTF-8. + +.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 +.TP +.BI \-H +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. + +.TP +.BI "\-\-error-level=LEVEL" +Return a nonzero (false) error code if there is at least one +hit of LEVEL or higher. If a diffhitlist is provided, +hits noted in it are ignored. +This option can be useful within a continuous integration script, +especially if you mark known-okay lines as "flawfinder: ignore". +Usually you want level to be fairly high, such as 4 or 5. +By default, flawfinder returns 0 (true) on a successful run. + +.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. +Warning: Do \fInot\fR load hitlists from untrusted sources +(for security reasons). +These are internally implemented using Python's "pickle" facility, +which trusts the input. +Note that stored hitlists often cannot be read when using an older version +of Python, in particular, if savehitlist was used but +flawfinder was run using Python 3, +the hitlist can't be loaded by running flawfinder with Python 2. + +.TP +\fB\-\-diffhitlist=\fR\fIF\fR +Show only hits (loaded or analyzed) not in F. +F was presumably created previously using \-\-savehitlist. +Warning: Do \fInot\fR diff hitlists from untrusted sources +(for security reasons). +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. + +.SS "Character Encoding" + +Flawfinder presumes that the character encoding your system uses is +also the character encoding used by your source files. +Even if this isn't correct, if you run flawfinder with Python 2 +these non-conformities often do not impact processing in practice. + +However, if you run flawfinder with Python 3, this can be a problem. +Python 3 wants the world to always use encodings perfectly correctly, +everywhere, even though the world often doesn't care what Python 3 wants. +This is a problem even if the non-conforming text is in comments or strings +(where it often doesn't matter). +Python 3 fails to provide useful built-ins to deal with +the messiness of the real world, so it's +non-trivial to deal with this problem without depending on external +libraries (which we're trying to avoid). + +A symptom of this problem +is if you run flawfinder and you see an error message like this: + +\fIUnicodeDecodeError: 'utf-8' codec can't decode byte ... in position ...: +invalid continuation byte\fR + +If this happens to you, there are several options. + +The first option is to +convert the encoding of the files to be analyzed so that it's +a single encoding (usually the system encoding). +For example, the program "iconv" can be used to convert encodings. +This works well if some files have one encoding, and some have another, +but they are consistent within a single file. +If the files have encoding errors, you'll have to fix them. +I strongly recommend using the UTF-8 encoding for all source code +and in the system itself; if you do that, many problems disappear. + +The second option is to +tell flawfinder what the encoding of the files is. +E.G., you can set the LANG environment variable. +You can set PYTHONIOENCODING to +the encoding you want your output to be in, if that's different. +This in theory would work, but I haven't had much success with this. + +The third option is to run flawfinder using Python 2 instead of Python 3. +E.g., "python2 flawfinder ...". + +.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-3.16" +Examine all the C/C++ files in the directory +/usr/src/linux-3.16 and all its subdirectories (recursively), +reporting on all hits found. +By default flawfinder will skip symbolic links and +directories with names that start with a period. + +.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 \-\-csv ." +Examine the current directory down (recursively), and report all +hits in CSV format. +This is the recommended form if you want to further process +flawfinder output using other tools +(such as data correlation tools). + +.TP +.B "flawfinder \-QD mydir" +Examine mydir and report only the actual results +(removing the header and footer of the output). +This form may be useful +if the output will be piped into other tools for further analysis, +though CSV format is probably the better choice in that case. +The \-C (\-\-columns) and \-S (\-\-singleline) +options can also be useful if you're piping the data +into other tools. + +.TP +.B "flawfinder \-QDSC mydir" +Examine mydir, reporting only the actual results (no header or footer). +Each hit is reported on one line, and column numbers are reported. +This can be a useful command if you are feeding +flawfinder output to 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. + +.TP 12 +.B "flawfinder \-\-patch recent.patch ." +Examine the current directory recursively, but only report lines +that were changed or added in the already-applied patchfile named +\fIrecent.patch\fR. + +.TP +\fBflawfinder \-\-regex "CWE-120|CWE-126" src/\fR +Examine directory \fIsrc\fR recursively, but only report hits +where CWE-120 or CWE-126 apply. + +.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 +(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. + +.SS "Invoking from Integrated Development Environments (IDEs)" +.PP +For (other) IDEs, consult your IDE's set of plug-ins. + +.SH COMMON WEAKNESS ENUMERATION (CWE) +.PP +The Common Weakness Enumeration (CWE) +is ``a formal list or dictionary of common software weaknesses +that can occur in software's architecture, design, code or implementation +that can lead to exploitable security vulnerabilities... +created to serve as a common language for +describing software security weaknesses'' +(https://cwe.mitre.org/about/faq.html). +For more information on CWEs, see https://cwe.mitre.org. +.PP +Flawfinder supports the CWE and is officially CWE-Compatible. +Hit descriptions typically include a relevant +Common Weakness Enumeration (CWE) identifier in parentheses +where there is known to be a relevant CWE. +For example, many of the buffer-related hits mention +CWE-120, the CWE identifier for +``buffer copy without checking size of input'' +(aka ``Classic Buffer Overflow''). +In a few cases more than one CWE identifier may be listed. +The HTML report also includes hypertext links to the CWE definitions +hosted at MITRE. +In this way, flawfinder is designed to meet the CWE-Output requirement. +.PP +In some cases there are CWE mapping and usage challenges; here is how +flawfinder handles them. +If the same entry maps to multiple CWEs simultaneously, +all the CWE mappings are listed as separated by commas. +This often occurs with CWE-20, Improper Input Validation; +thus the report "CWE-676, CWE-120" maps to two CWEs. +In addition, flawfinder provides additional information for those who are +are interested in the CWE/SANS top 25 list 2011 (https://cwe.mitre.org/top25/) +when mappings are not directly to them. +Many people will want to search for specific CWEs in this top 25 list, +such as CWE-120 (classic buffer overflow). +The challenge is that some flawfinder hits map +to a more general CWE that would include a top 25 item, while in some +other cases hits map to a more specific vulnerability that is +only a subset of a top 25 item. +To resolve this, in some cases flawfinder will list a sequence of CWEs +in the format "more-general/more-specific", where the CWE actually +being mapped is followed by a "!". +This is always done whenever a flaw is not mapped directly to +a top 25 CWE, but the mapping is related to such a CWE. +So "CWE-119!/CWE-120" means that the vulnerability is mapped +to CWE-119 and that CWE-120 is a subset of CWE-119. +In contrast, "CWE-362/CWE-367!" means that the hit is mapped to +CWE-367, a subset of CWE-362. +Note that this is a subtle syntax change from flawfinder version 1.31; +in flawfinder version 1.31, +the form "more-general:more-specific" meant what is now listed as +"more-general!/more-specific", while +"more-general/more-specific" meant "more-general/more-specific!". +Tools can handle both the version 1.31 and the current format, +if they wish, by noting that the older format did not use "!" at all +(and thus this is easy to distinguish). +These mapping mechanisms simplify searching for certain CWEs. +.PP +CWE version 2.7 (released June 23, 2014) was used for the mapping. +The current CWE mappings select the most specific CWE the tool can determine. +In theory, most CWE security elements (signatures/patterns that the +tool searches for) could theoretically be mapped to +CWE-676 (Use of Potentially Dangerous Function), but such a mapping would +not be useful. +Thus, more specific mappings were preferred where one could be found. +Flawfinder is a lexical analysis tool; as a result, it is impractical +for it to be more specific than the mappings currently implemented. +This also means that it is unlikely to need much +updating for map currency; it simply doesn't have enough information to +refine to a detailed CWE level that CWE changes would typically affect. +The list of CWE identifiers was generated automatically using "make show-cwes", +so there is confidence that this list is correct. +Please report CWE mapping problems as bugs if you find any. +.PP +Flawfinder may fail to find a vulnerability, even if flawfinder covers +one of these CWE weaknesses. +That said, flawfinder does find vulnerabilities listed by the CWEs it covers, +and it will not report lines without those vulnerabilities in many cases. +Thus, as required for any tool intending to be CWE compatible, +flawfinder has a rate of false positives less than 100% +and a rate of false negatives less than 100%. +Flawfinder almost always reports whenever it finds a match to a +CWE security element (a signature/pattern as defined in its database), +though certain obscure constructs can cause it to fail (see BUGS below). +.PP +Flawfinder can report on the following CWEs +(these are the CWEs that flawfinder covers; ``*'' marks those in the +CWE/SANS top 25 list): +.IP \(bu 2 +CWE-20: Improper Input Validation +.IP \(bu 2 +CWE-22: Improper Limitation of a Pathname to a Restricted Directory (``Path Traversal'') +.IP \(bu +CWE-78: Improper Neutralization of Special Elements used in an OS Command (``OS Command Injection'')* +.IP \(bu +CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer +(a parent of CWE-120*, so this is shown as CWE-119!/CWE-120) +.IP \(bu +CWE-120: Buffer Copy without Checking Size of Input (``Classic Buffer Overflow'')* +.IP \(bu +CWE-126: Buffer Over-read +.IP \(bu +CWE-134: Uncontrolled Format String* +.IP \(bu +CWE-190: Integer Overflow or Wraparound* +.IP \(bu +CWE-250: Execution with Unnecessary Privileges +.IP \(bu +CWE-327: Use of a Broken or Risky Cryptographic Algorithm* +.IP \(bu +CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization (``Race Condition'') +.IP \(bu +CWE-377: Insecure Temporary File +.IP \(bu +CWE-676: Use of Potentially Dangerous Function* +.IP \(bu +CWE-732: Incorrect Permission Assignment for Critical Resource* +.IP \(bu +CWE-785: Use of Path Manipulation Function without Maximum-sized Buffer +(child of CWE-120*, so this is shown as CWE-120/CWE-785) +.IP \(bu +CWE-807: Reliance on Untrusted Inputs in a Security Decision* +.IP \(bu +CWE-829: Inclusion of Functionality from Untrusted Control Sphere* +.PP +You can select a specific subset of CWEs to report by using +the ``\-\-regex'' (-e) option. +This option accepts a regular expression, so you can select multiple CWEs, +e.g., ``\-\-regex "CWE-120|CWE-126"''. +If you select multiple CWEs with ``|'' on a command line +you will typically need to quote the parameters (since an +unquoted ``|'' is the pipe symbol). +Flawfinder is designed to meet the CWE-Searchable requirement. +.PP +If your goal is to report a subset of CWEs that are listed in a file, +that can be achieved on a Unix-like system using the ``\-\-regex'' aka +``\-e'' option. +The file must be in regular expression format. +For example, +``flawfinder -e $(cat file1)'' would report only hits that matched +the pattern in ``file1''. +If file1 contained ``CWE-120|CWE-126'' it +would only report hits matching those CWEs. +.PP +A list of all CWE security elements +(the signatures/patterns that flawfinder looks for) +can be found by using the ``\-\-listrules'' option. +Each line lists the signature token (typically a function name) +that may lead to a hit, the default risk level, and +the default warning (which includes the default CWE identifier). +For most purposes this is also enough if you want to see what +CWE security elements map to which CWEs, or the reverse. +For example, to see the most of the signatures (function names) +that map to CWE-327, +without seeing the default risk level or detailed warning text, +run ``flawfinder \-\-listrules | grep CWE-327 | cut -f1''. +You can also see the tokens without a CWE mapping this way by running +``flawfinder -D --listrules | grep -v CWE-''. +However, while \-\-listrules lists all CWE security elements, +it only lists the default mappings +from CWE security elements to CWE identifiers. +It does not include the refinements +that flawfinder applies (e.g., by examining function parameters). +.PP +If you want a detailed and exact mapping between the CWE security elements +and CWE identifiers, the flawfinder source code (included in the distribution) +is the best place for that information. +This detailed information is primarily of interest to those few +people who are trying to refine the CWE mappings of flawfinder +or refine CWE in general. +The source code documents the mapping between the security elements +to the respective CWE identifiers, and is a single Python file. +The ``c_rules'' dataset defines most rules, with reference to a +function that may make further refinements. +You can search the dataset for +function names to see what CWE it generates by default; +if first parameter is not ``normal'' then that is the name of +a refining Python method that may select different CWEs +(depending on additional information). +Conversely, you can search for ``CWE-number'' and find what security +elements (signatures or patterns) refer to that CWE identifier. +For most people, this is much more than they need; most people just want to +scan their source code to quickly find problems. + + +.SH SECURITY +.PP +The whole point of this tool is to help find vulnerabilities so they +can be fixed. +However, developers and reviewers must +know how to develop secure software to use this tool, because otherwise, +\fIa fool with a tool is still a fool\fR. +My book at https://dwheeler.com/secure-programs may help. +.PP +This tool should be, at most, a small part of a larger software +development process designed +to eliminate or reduce the impact of vulnerabilities. +Developers and reviewers need know how to develop secure software, +and they need to apply this knowledge to reduce the +risks of vulnerabilities in the first place. +.PP +Different vulnerability-finding tools tend to find different vulnerabilities. +Thus, you are best off using human review and a variety of tools. +This tool can help find some vulnerabilities, but by no means all. +.PP +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 GitHub, 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 that the analyst cannot trust. +The problem is 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 +.PP +Do \fInot\fR load or diff hitlists from untrusted sources. +They are implemented using the Python pickle module, and the pickle +module is not intended to be secure against +erroneous or maliciously constructed data. +Stored hitlists are intended for later use by the same user who created +the hitlist; in that context this restriction is not a problem. + +.SH BUGS +.PP +Flawfinder is based on simple text pattern matching, which is +part of its fundamental design and not easily changed. +This design approach leads to a number of fundamental limitations, e.g., +a higher false positive rate, and is the underlying cause of +most of the bugs listed here. +On the positive side, flawfinder doesn't get confused by many +complicated preprocessor sequences that other tools sometimes choke on; +flawfinder can often handle code that cannot link, and sometimes +cannot even compile or build. +.PP +Flawfinder is currently limited to C/C++. +In addition, when analyzing C++ it focuses primarily on the C subset of C++. +For example, flawfinder does not report on expressions like cin >> charbuf, +where charbuf is a char array. +That is because flawfinder doesn't have type information, +and ">>" is safe with many other types; reporting on all ">>" +would lead to too many false positives. +That said, +it's designed so that adding support for other languages should be easy +where its text-based approach can usefully apply. +.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 typically not a problem for C code. +In C code, a function with the same name as a common library routine name +often indicates that the developer is simply rewriting a +common library routine with the same interface, say for portability's sake. +C programs tend to avoid reusing the same name for a different purpose +(since in C function names are global by default). +There are reasonable odds that +these rewritten routines will be vulnerable to the same kinds of misuse, +and thus, reusing these rules is a reasonable approach. +However, this can be a much more serious problem in C++ +code which heavily uses classes and namespaces, since the +same method name may have many different meanings. +The \-\-falsepositive option can help somewhat in this case. +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 +Flawfinder reports vulnerabilities regardless of the parameters of +"#if" or "#ifdef". +A construct "#if VALUE" will often have VALUE of 0 in some cases, and +non-zero in others. +Similarly, "#ifdef VALUE" will have VALUE defined in some cases, and +not defined in others. +Flawfinder reports in all cases, which +means that flawfinder has a chance of reporting vulnerabilities in +all alternatives. +This is not a bug, this is intended behavior. +.PP +Flawfinder will report hits even if they are between +a literal "#if 0" and "#endif". +It would be possible to change this particular situation, but directly +using "#if 0" to comment-out code (other than during debugging) is itself +that the removal is very temporary (in which case we should report it) or +an indicator of a problem with poor code practices. +If you want to permanently get rid of code, then +delete it instead of using "#if 0", since you can always see what it was +using your version control software. +If you don't use version control software, then that's the bug +you need to fix right now. +.PP +Some complex or unusual constructs can mislead flawfinder. +In particular, if a parameter begins with gettext(" and ends with ), +flawfinder will presume that the parameter of gettext is a constant. +This means it 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. +.PP +The routine to detect statically defined character arrays uses +simple text matching; some complicated expressions 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 default 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 are using flawfinder's output in other tools, consider using its +CSV format instead (which can handle this). +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 +Flawfinder is not internationalized, so it currently +does not support localization. +.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 +(failures to report security vulnerabilities). +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, and is especially true +for tools like flawfinder that use a simple lexical analysis and +pattern analysis to identify potential vulnerabilities. +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 simple tool. + +.SH "SEE ALSO" +See the flawfinder website at https://dwheeler.com/flawfinder. +You should also see the +.I "Secure Programming HOWTO" +at +.IR "https://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 100755 index 0000000..ff1ac9e Binary files /dev/null and b/flawfinder.1.gz differ diff --git a/flawfinder.pdf b/flawfinder.pdf new file mode 100755 index 0000000..3ae6310 Binary files /dev/null and b/flawfinder.pdf differ diff --git a/flawfinder.ps b/flawfinder.ps new file mode 100755 index 0000000..c4ae95a Binary files /dev/null and b/flawfinder.ps differ diff --git a/flawfinder.spec b/flawfinder.spec new file mode 100644 index 0000000..fc371fa --- /dev/null +++ b/flawfinder.spec @@ -0,0 +1,47 @@ +Name: flawfinder +Summary: Examines C/C++ source code for security flaws +Version: 2.0.10 +Release: 1%{?dist} +License: GPLv2+ +Group: Development/Tools +URL: http://dwheeler.com/flawfinder/ +Source: http://dwheeler.com/flawfinder/%{name}-%{version}.tar.gz +Requires: python +BuildArch: noarch +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + +%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. + +%prep +%setup -q + +%build +make %{?_smp_mflags} + +%install +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 +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root,-) +%doc README.md ChangeLog COPYING flawfinder.ps +%{_bindir}/* +%{_mandir}/man1/* + +%changelog +* Mon Aug 27 2007 Horst H. von Brand 1.27-2 +- Fix specfile as per Fedora guidelines + +* 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/flawfinder.yapf b/flawfinder.yapf new file mode 100755 index 0000000..e69de29 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..5b005a1 --- /dev/null +++ b/junk.c @@ -0,0 +1,10 @@ + +#include + +main() { + char abuf[1000]; + FILE *FR = stdin; + fscanf(FR, "%2000s", abuf); + printf("Result = %s\n", abuf); + strcpy(new,old); +} diff --git a/makefile b/makefile new file mode 100644 index 0000000..642190f --- /dev/null +++ b/makefile @@ -0,0 +1,271 @@ +# Flawfinder. +# Released under the General Public License (GPL) version 2 or later. +# (C) 2001-2017 David A. Wheeler. + +# See "release_process.md" for release process, including +# how to change version numbers. + +NAME=flawfinder +VERSION=2.0.10 +RPM_VERSION=1 +VERSIONEDNAME=$(NAME)-$(VERSION) +ARCH=noarch + +SAMPLE_DIR=/usr/src/linux-2.2.16 +PYTHON=python +PYTHON2=python2 +PYTHON3=python3 + +# Flawfinder has traditionally used INSTALL_DIR, INSTALL_DIR_BIN, and +# INSTALL_DIR_MAN. Here we add support for GNU variables like prefix, etc.; +# users who override the older flawfinder-specific variable names will +# not notice any changes. We define exec_prefix oddly so we can +# quietly merge these 2 systems: + +prefix=/usr/local +INSTALL_DIR=$(prefix) +exec_prefix=$(INSTALL_DIR) +bindir=$(exec_prefix)/bin +INSTALL_DIR_BIN=$(bindir) + +datarootdir=$(INSTALL_DIR)/share +mandir=$(datarootdir)/man +man1dir=$(mandir)/man1 +INSTALL_DIR_MAN=$(man1dir) + +FLEX=flex + +# 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 + +DESTDIR= + +all: flawfinder.pdf flawfinder.1.gz + chmod -R a+rX * + +# We use 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). +MKDIR_P=mkdir -p + +INSTALL_PROGRAM=cp -p +INSTALL_DATA=cp -p + +# 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. +install: + -$(MKDIR_P) $(DESTDIR)$(INSTALL_DIR_BIN) + $(INSTALL_PROGRAM) flawfinder $(DESTDIR)$(INSTALL_DIR_BIN)/flawfinder$(PYTHONEXT) + -$(MKDIR_P) $(DESTDIR)$(INSTALL_DIR_MAN) + $(INSTALL_DATA) flawfinder.1 $(DESTDIR)$(INSTALL_DIR_MAN)/flawfinder.1 + +uninstall: + rm -f $(DESTDIR)$(INSTALL_DIR_BIN)/flawfinder$(PYTHONEXT) + rm -f $(DESTDIR)$(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 + +# Not built by default, since man2html is not widely available +# and the PDF is prettier. +flawfinder.html: flawfinder.1 + man2html flawfinder.1 | tail -n +3 > flawfinder.html + +clean: + rm -f *.pyc + rm -f flawfinder-$(VERSION).tar.gz + rm -f cwe.c cwe + rm -f *.tar *.exe ./cwe + +distribute: clean flawfinder.pdf flawfinder.ps + rm -fr build dist flawfinder.egg-info ,tempdir + chmod -R a+rX * + mkdir ,tempdir + cp -p [a-zA-Z]* ,tempdir + rm -f ,tempdir/*.tar.gz + rm -f ,tempdir/*.rpm + # We don't need both "flawfinder" and "flawfinder.py": + rm -f ,tempdir/flawfinder.py + mv ,tempdir flawfinder-$(VERSION) + # Nobody else needs "update" either. + rm -f ,tempdir/update + # Don't need compressed version of document. + rm -f ,tempdir/flawfinder.1.gz + # Don't include (out of date) index.html + rm -f ,tempdir/index.html + tar cvfz flawfinder-$(VERSION).tar.gz flawfinder-$(VERSION) + chown --reference=. flawfinder-$(VERSION).tar.gz + rm -fr flawfinder-$(VERSION) + +dist: distribute + +# This *creates* a PyPi distribution package. Use "upload-pypi" to upload it +pypi: + python setup.py bdist_wheel --universal + +# NOTE: Only do this after running "make pypi" & being satisfied with it +# Use "-r pypitest" to upload to pypitest. +upload-pypi: + twine upload dist/* + +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_001: flawfinder test.c test2.c + @echo 'test_001 (text output)' + @# Omit time report so that results are always the same textually. + @$(PYTHON) ./flawfinder --omittime test.c test2.c > test-results.txt + @echo >> test-results.txt + @echo "Testing for no ending newline:" >> test-results.txt + @$(PYTHON) ./flawfinder --omittime no-ending-newline.c | \ + grep 'Lines analyzed' >> test-results.txt + @diff -u correct-results.txt test-results.txt + +test_002: flawfinder test.c test2.c + @echo 'test_002 (HTML output)' + @$(PYTHON) ./flawfinder --omittime --html --context test.c test2.c > test-results.html + @diff -u correct-results.html test-results.html + +test_003: flawfinder test.c test2.c + @echo 'test_003 (CSV output)' + @$(PYTHON) ./flawfinder --csv test.c test2.c > test-results.csv + @diff -u correct-results.csv test-results.csv + +test_004: flawfinder test.c + @echo 'test_004 (single-line)' + @$(PYTHON) ./flawfinder -m 5 -S -DC --quiet test.c > \ + test-results-004.txt + @diff -u correct-results-004.txt test-results-004.txt + +test_005: flawfinder test-diff-005.patch test-patched.c + @echo 'test_005 (diff)' + @$(PYTHON) ./flawfinder -SQDC -P test-diff-005.patch \ + test-patched.c > test-results-005.txt + @diff -u correct-results-005.txt test-results-005.txt + +test_006: flawfinder test.c + @echo 'test_006 (save/load hitlist)' + @$(PYTHON) ./flawfinder -S -DC --quiet \ + --savehitlist test-saved-hitlist-006.txt \ + test.c > test-junk-006.txt + @$(PYTHON) ./flawfinder -SQDC -m 5 \ + --loadhitlist test-saved-hitlist-006.txt > \ + test-results-006.txt + @diff -u correct-results-006.txt test-results-006.txt + +test_007: setup.py + @echo 'test_007 (setup.py sane)' + @test "`$(PYTHON) setup.py --name`" = 'flawfinder' + @test "`$(PYTHON) setup.py --license`" = 'GPL-2.0+' + @test "`$(PYTHON) setup.py --author`" = 'David A. Wheeler' + +test_008: flawfinder test.c + @echo 'test_008 (diff hitlist)' + @$(PYTHON) ./flawfinder -S -DC --quiet \ + --savehitlist test-saved-hitlist-008.txt \ + test.c > test-junk-008.txt + @$(PYTHON) ./flawfinder -S -C --quiet --omittime \ + --diffhitlist test-saved-hitlist-008.txt test.c > \ + test-results-008.txt + @diff -u correct-results-008.txt test-results-008.txt + +# Run all tests on *one* version of Python; +# output shows differences from expected results. +# If everything works as expected, it just prints test numbers. +# Set PYTHON as needed, including to "" +test: test_001 test_002 test_003 test_004 test_005 test_006 test_007 test_008 + @echo 'All tests pass!' + +# Usual check routine. Run all tests using *both* python2 and python3. +check: + @echo "Testing with $(PYTHON2)" + @PYTHON="$(PYTHON2)" $(MAKE) test + @echo + @echo "Testing with $(PYTHON3)" + @PYTHON="$(PYTHON3)" $(MAKE) test + +# Run "make test-is-correct" if the results are as expected. +test-is-correct: test-results.txt + cp -p test-results.txt correct-results.txt + cp -p test-results.html correct-results.html + cp -p test-results.csv correct-results.csv + cp -p test-results-004.txt correct-results-004.txt + cp -p test-results-005.txt correct-results-005.txt + cp -p test-results-006.txt correct-results-006.txt + cp -p test-results-008.txt correct-results-008.txt + +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.md *.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 + +# This is a developer convenience target, not intended for general use. +my-install: flawfinder.pdf flawfinder.ps test + cp -p $(VERSIONEDNAME).tar.gz \ + flawfinder flawfinder.1 makefile \ + flawfinder.pdf flawfinder.ps ChangeLog \ + test.c test2.c test-results.txt test-results.html \ + /home/dwheeler/dwheeler.com/flawfinder/ + +# This is intended to be a local capability to list CWEs +cwe.c: cwe.l + $(FLEX) -o cwe.c cwe.l + +cwe: cwe.c + $(CC) -o cwe cwe.c -lfl + +show-cwes: cwe + ./cwe < flawfinder | sort -u -V + +pylint: + pylint flawfinder + +.PHONY: install clean test check profile test-is-correct rpm \ + uninstall distribute my-install show-cwes pylint + +# 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/no-ending-newline.c b/no-ending-newline.c new file mode 100644 index 0000000..06166af --- /dev/null +++ b/no-ending-newline.c @@ -0,0 +1,32 @@ +// Test file to show bug in 1.27 + +#include +#include +#include + +int main() +{ + FILE *f; + char buf[1024], *s; + int first; + + first = 1; + while(fgets(buf, sizeof(buf), stdin) != 0) { + if(first == 0) { + printf("\n"); + } + s = buf; + while(*s != '\0') { + if(*s == '\n' || *s == '\r') { + *s = '\0'; + break; + } + s++; + } + printf("%s", buf); + first = 0; + } +} + +/* end with spaces and no \n or \r */ + \ No newline at end of file diff --git a/pylintrc b/pylintrc new file mode 100644 index 0000000..809fb2d --- /dev/null +++ b/pylintrc @@ -0,0 +1,436 @@ +[MASTER] + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code +extension-pkg-whitelist= + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS + +# Add files or directories matching the regex patterns to the blacklist. The +# regex matches against base names, not paths. +ignore-patterns= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. +jobs=1 + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Pickle collected data for later comparisons. +persistent=yes + +# Specify a configuration file. +#rcfile= + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +confidence= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +# Flawfinder specifics: This disables "invalid-name", because that checker +# has a serious bug: it can't handle global variables and thinks they are +# constants (so it raises a hailstorm of incorrect reports). +# We *use* global-statement, so don't warn about it. +# TODO: perhaps stop disabling some, e.g., +# missing-docstring, too-many-statements, +# too-many-branches,too-many-locals,too-many-nested-blocks +disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,invalid-name,missing-docstring,global-statement,too-many-statements,too-many-branches,too-many-locals,too-many-instance-attributes,too-many-nested-blocks + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable= + + +[REPORTS] + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio).You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages +reports=no + +# Activate the evaluation score. +score=yes + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + + +[BASIC] + +# Naming hint for argument names +argument-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Regular expression matching correct argument names +argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Naming hint for attribute names +attr-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Regular expression matching correct attribute names +attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Naming hint for class attribute names +class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Regular expression matching correct class attribute names +class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Naming hint for class names +class-name-hint=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression matching correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Naming hint for constant names +const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression matching correct constant names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# Naming hint for function names +function-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Regular expression matching correct function names +function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=no + +# Naming hint for inline iteration names +inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ + +# Regular expression matching correct inline iteration names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Naming hint for method names +method-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Regular expression matching correct method names +method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Naming hint for module names +module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression matching correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +property-classes=abc.abstractproperty + +# Naming hint for variable names +variable-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Regular expression matching correct variable names +variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +# TODO: Flawfinder specific - eventually we'll bring this down to 80 +max-line-length=500 + +# Maximum number of lines in a module +# Flawfinder specific - we want this to be a single file +max-module-lines=5000 + +# List of optional constructs for which whitespace checking is disabled. `dict- +# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. +# `trailing-comma` allows a space between comma and closing bracket: (a, ). +# `empty-line` allows space-only lines. +no-space-check=trailing-comma,dict-separator + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +# notes=FIXME,XXX,TODO +# Flawfinder specifics: We already note them, no need to report +notes= + + +[SIMILARITIES] + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + +# Minimum lines number of a similarity. +min-similarity-lines=4 + + +[SPELLING] + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_,_cb + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.*|^ignored_|^unused_ + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,future.builtins + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict,_fields,_replace,_source,_make + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=5 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Maximum number of boolean expressions in a if statement +max-bool-expr=5 + +# Maximum number of branch for function / method body +max-branches=12 + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of statements in function / method body +max-statements=50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + + +[IMPORTS] + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,TERMIOS,Bastion,rexec + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception diff --git a/release_process.md b/release_process.md new file mode 100644 index 0000000..32721fd --- /dev/null +++ b/release_process.md @@ -0,0 +1,87 @@ +# Release process + +Here's information on how to release an update to flawfinder. + +## Changing version number + +Ensure that the version number is the intended final value. +Make sure every release has a unique version number. + +To change version number, edit the following files: +makefile +flawfinder +flawfinder.spec +setup.py +index.html # in dwheeler.com/flawfinder + +Then run: + +~~~~ +make test && make test-is-correct # update version number in tests +~~~~ + +## Test it + +~~~~ +make check # Run tests in Python 2 and 3 +~~~~ + +## Tag version + +Once you're sure this is the *real* version, tag it: + +~~~~ +git tag VERSION +git push --tags origin # SourceForge +git push --tags github # GitHub +~~~~ + +## Create tarball + +Run: + +~~~~ +make distribute +~~~~ + + +## Post tarball + +Then post the tarball flawfinder-VERSION.tar.gz to +the usual places: + +* SourceForge "files" directory, and set it to be the default download. +* dwheeler.com/flawfinder + +Do this *before* creating the PyPi distribution package for pip. + +## Post to pip + +First, install the programs to create a PyPi distribution package +if they are not already installed. On Cygwin first run: + +~~~~ +python -m ensurepip +pip install --upgrade pip +pip install wheel +pip install twine +~~~~ + +Then create a PyPi distribution package (for Python2 and Python3): + +~~~~ +make pypi +~~~~ + +Now upload the PyPi distribution package: + +~~~~ +make upload-pypi +~~~~ + +## After it's uploaded + +Change the version number in the repo NOW, so that there will not +be two different released versions with the same version number. +See the list at the beginning of this document for the list of +files to change. diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..7b90e6e --- /dev/null +++ b/setup.cfg @@ -0,0 +1,13 @@ +[metadata] +description-file = README.md + +[bdist_wheel] +universal=1 + +[bdist_rpm] +release = 1 +doc_files = ChangeLog + README.md + COPYING + flawfinder.ps + flawfinder.pdf diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..f73ea7e --- /dev/null +++ b/setup.py @@ -0,0 +1,47 @@ +#!/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. + +"""Setup script for the flawfinder tool.""" + +from setuptools import setup # Don't need find_packages + +setup (# Distribution meta-data + name = "flawfinder", + version = "2.0.10", + # We install a script, not a separate package. + # packages = ["flawfinder"], # Must be same as name + # Do not need: packages=find_packages(), + description = "a program that examines source code looking for security weaknesses", + author = "David A. Wheeler", + author_email = "dwheeler@dwheeler.com", + license = 'GPL-2.0+', + 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://dwheeler.com/flawfinder/", + download_url = "https://sourceforge.net/projects/flawfinder/files/flawfinder-2.0.8.tar.gz/download", + zip_safe = True, + keywords = ['analysis', 'security', 'analyzer'], + classifiers = [ + 'Development Status :: 5 - Production/Stable', + 'Environment :: Console', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)', + 'Natural Language :: English', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + 'Operating System :: OS Independent', + 'Topic :: Security', + 'Topic :: Software Development :: Build Tools', + 'Topic :: Software Development :: Quality Assurance', + 'Topic :: Software Development :: Testing' + ], + python_requires = '>=2.7', + 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-diff-005.patch b/test-diff-005.patch new file mode 100644 index 0000000..b971de7 --- /dev/null +++ b/test-diff-005.patch @@ -0,0 +1,13 @@ +--- test.c 2017-08-26 15:33:59.480235200 -0400 ++++ test-patched.c 2017-08-23 22:20:22.458331500 -0400 +@@ -9,6 +9,10 @@ + printf("hello\n"); + } + ++int bad(char *a, char *b) { ++ strcpy(b, a); ++} ++ + /* This is a strcpy test. */ + + int demo(char *a, char *b) { diff --git a/test-junk-006.txt b/test-junk-006.txt new file mode 100755 index 0000000..a5ac99d --- /dev/null +++ b/test-junk-006.txt @@ -0,0 +1,38 @@ +test.c:32:2: [5] (buffer) gets:Does not check for buffer overflows (CWE-120, CWE-20). Use fgets() instead. +test.c:60:3: [5] (buffer) strncat:Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120). Consider strcat_s, strlcat, snprintf, 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:61:3: [5] (buffer) _tcsncat:Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120). Consider strcat_s, 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:64:3: [5] (buffer) MultiByteToWideChar:Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is high, it appears that the size is given as bytes, but the function requires size as characters. +test.c:66:3: [5] (buffer) MultiByteToWideChar:Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is high, it appears that the size is given as bytes, but the function requires size as characters. +test.c:77:3: [5] (misc) SetSecurityDescriptorDacl:Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732). +test.c:77:3: [5] (misc) SetSecurityDescriptorDacl:Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732). +test.c:17:2: [4] (buffer) strcpy:Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120). Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused). +test.c:20:2: [4] (buffer) sprintf:Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or vsnprintf. +test.c:21:2: [4] (buffer) sprintf:Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or vsnprintf. +test.c:22:2: [4] (format) sprintf:Potential format string problem (CWE-134). Make format string constant. +test.c:23:2: [4] (format) printf:If format strings can be influenced by an attacker, they can be exploited (CWE-134). Use a constant for the format specification. +test.c:25:2: [4] (buffer) scanf:The scanf() family's %s operation, without a limit specification, permits buffer overflows (CWE-120, CWE-20). Specify a limit to %s, or use a different input function. +test.c:27:2: [4] (buffer) scanf:The scanf() family's %s operation, without a limit specification, permits buffer overflows (CWE-120, CWE-20). Specify a limit to %s, or use a different input function. +test.c:38:2: [4] (format) syslog:If syslog's format strings can be influenced by an attacker, they can be exploited (CWE-134). Use a constant format string for syslog. +test.c:49:3: [4] (buffer) _mbscpy:Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120). Consider using a function version that stops copying at the end of the buffer. +test.c:56:3: [4] (buffer) lstrcat:Does not check for buffer overflows when concatenating to destination [MS-banned] (CWE-120). +test.c:79:3: [3] (shell) CreateProcess:This causes a new process to execute and is difficult to use safely (CWE-78). 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:79:3: [3] (shell) CreateProcess:This causes a new process to execute and is difficult to use safely (CWE-78). 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:95:20: [3] (buffer) getopt_long:Some older implementations do not protect against internal buffer overflows (CWE-120, CWE-20). Check implementation on installation, or limit the size of all string inputs. +test.c:16:2: [2] (buffer) strcpy:Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120). Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused). Risk is low because the source is a constant string. +test.c:19:2: [2] (buffer) sprintf:Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or vsnprintf. Risk is low because the source has a constant maximum length. +test.c:45:3: [2] (buffer) char:Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length. +test.c:46:3: [2] (buffer) char:Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length. +test.c:50:3: [2] (buffer) memcpy:Does not check for buffer overflows when copying to destination (CWE-120). Make sure destination can always hold the source data. +test.c:53:3: [2] (buffer) memcpy:Does not check for buffer overflows when copying to destination (CWE-120). Make sure destination can always hold the source data. +test.c:54:3: [2] (buffer) memcpy:Does not check for buffer overflows when copying to destination (CWE-120). Make sure destination can always hold the source data. +test.c:55:3: [2] (buffer) CopyMemory:Does not check for buffer overflows when copying to destination (CWE-120). Make sure destination can always hold the source data. +test.c:101:7: [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? (CWE-362). +test.c:15:2: [1] (buffer) strcpy:Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120). Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused). Risk is low because the source is a constant character. +test.c:18:2: [1] (buffer) sprintf:Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or vsnprintf. Risk is low because the source is a constant character. +test.c:26:2: [1] (buffer) scanf:It's unclear if the %s limit in the format string is small enough (CWE-120). Check that the limit is sufficiently small, or use a different input function. +test.c:57:3: [1] (buffer) strncpy:Easily used incorrectly; doesn't always \0-terminate or check for invalid pointers [MS-banned] (CWE-120). +test.c:58:3: [1] (buffer) _tcsncpy:Easily used incorrectly; doesn't always \0-terminate or check for invalid pointers [MS-banned] (CWE-120). +test.c:59:3: [1] (buffer) strncat:Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120). Consider strcat_s, strlcat, snprintf, or automatically resizing strings. +test.c:62:7: [1] (buffer) strlen:Does not handle strings that are not \0-terminated; if given one it may perform an over-read (it could cause a crash if unprotected) (CWE-126). +test.c:68:3: [1] (buffer) MultiByteToWideChar:Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is very low, the length appears to be in characters not bytes. +test.c:70:3: [1] (buffer) MultiByteToWideChar:Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is very low, the length appears to be in characters not bytes. diff --git a/test-junk-008.txt b/test-junk-008.txt new file mode 100644 index 0000000..a5ac99d --- /dev/null +++ b/test-junk-008.txt @@ -0,0 +1,38 @@ +test.c:32:2: [5] (buffer) gets:Does not check for buffer overflows (CWE-120, CWE-20). Use fgets() instead. +test.c:60:3: [5] (buffer) strncat:Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120). Consider strcat_s, strlcat, snprintf, 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:61:3: [5] (buffer) _tcsncat:Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120). Consider strcat_s, 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:64:3: [5] (buffer) MultiByteToWideChar:Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is high, it appears that the size is given as bytes, but the function requires size as characters. +test.c:66:3: [5] (buffer) MultiByteToWideChar:Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is high, it appears that the size is given as bytes, but the function requires size as characters. +test.c:77:3: [5] (misc) SetSecurityDescriptorDacl:Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732). +test.c:77:3: [5] (misc) SetSecurityDescriptorDacl:Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732). +test.c:17:2: [4] (buffer) strcpy:Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120). Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused). +test.c:20:2: [4] (buffer) sprintf:Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or vsnprintf. +test.c:21:2: [4] (buffer) sprintf:Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or vsnprintf. +test.c:22:2: [4] (format) sprintf:Potential format string problem (CWE-134). Make format string constant. +test.c:23:2: [4] (format) printf:If format strings can be influenced by an attacker, they can be exploited (CWE-134). Use a constant for the format specification. +test.c:25:2: [4] (buffer) scanf:The scanf() family's %s operation, without a limit specification, permits buffer overflows (CWE-120, CWE-20). Specify a limit to %s, or use a different input function. +test.c:27:2: [4] (buffer) scanf:The scanf() family's %s operation, without a limit specification, permits buffer overflows (CWE-120, CWE-20). Specify a limit to %s, or use a different input function. +test.c:38:2: [4] (format) syslog:If syslog's format strings can be influenced by an attacker, they can be exploited (CWE-134). Use a constant format string for syslog. +test.c:49:3: [4] (buffer) _mbscpy:Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120). Consider using a function version that stops copying at the end of the buffer. +test.c:56:3: [4] (buffer) lstrcat:Does not check for buffer overflows when concatenating to destination [MS-banned] (CWE-120). +test.c:79:3: [3] (shell) CreateProcess:This causes a new process to execute and is difficult to use safely (CWE-78). 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:79:3: [3] (shell) CreateProcess:This causes a new process to execute and is difficult to use safely (CWE-78). 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:95:20: [3] (buffer) getopt_long:Some older implementations do not protect against internal buffer overflows (CWE-120, CWE-20). Check implementation on installation, or limit the size of all string inputs. +test.c:16:2: [2] (buffer) strcpy:Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120). Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused). Risk is low because the source is a constant string. +test.c:19:2: [2] (buffer) sprintf:Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or vsnprintf. Risk is low because the source has a constant maximum length. +test.c:45:3: [2] (buffer) char:Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length. +test.c:46:3: [2] (buffer) char:Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length. +test.c:50:3: [2] (buffer) memcpy:Does not check for buffer overflows when copying to destination (CWE-120). Make sure destination can always hold the source data. +test.c:53:3: [2] (buffer) memcpy:Does not check for buffer overflows when copying to destination (CWE-120). Make sure destination can always hold the source data. +test.c:54:3: [2] (buffer) memcpy:Does not check for buffer overflows when copying to destination (CWE-120). Make sure destination can always hold the source data. +test.c:55:3: [2] (buffer) CopyMemory:Does not check for buffer overflows when copying to destination (CWE-120). Make sure destination can always hold the source data. +test.c:101:7: [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? (CWE-362). +test.c:15:2: [1] (buffer) strcpy:Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120). Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused). Risk is low because the source is a constant character. +test.c:18:2: [1] (buffer) sprintf:Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or vsnprintf. Risk is low because the source is a constant character. +test.c:26:2: [1] (buffer) scanf:It's unclear if the %s limit in the format string is small enough (CWE-120). Check that the limit is sufficiently small, or use a different input function. +test.c:57:3: [1] (buffer) strncpy:Easily used incorrectly; doesn't always \0-terminate or check for invalid pointers [MS-banned] (CWE-120). +test.c:58:3: [1] (buffer) _tcsncpy:Easily used incorrectly; doesn't always \0-terminate or check for invalid pointers [MS-banned] (CWE-120). +test.c:59:3: [1] (buffer) strncat:Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120). Consider strcat_s, strlcat, snprintf, or automatically resizing strings. +test.c:62:7: [1] (buffer) strlen:Does not handle strings that are not \0-terminated; if given one it may perform an over-read (it could cause a crash if unprotected) (CWE-126). +test.c:68:3: [1] (buffer) MultiByteToWideChar:Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is very low, the length appears to be in characters not bytes. +test.c:70:3: [1] (buffer) MultiByteToWideChar:Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is very low, the length appears to be in characters not bytes. diff --git a/test-patched.c b/test-patched.c new file mode 100644 index 0000000..9ee11a1 --- /dev/null +++ b/test-patched.c @@ -0,0 +1,121 @@ +/* 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"); +} + +int bad(char *a, char *b) { + strcpy(b, a); +} + +/* 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/test-preproc.c b/test-preproc.c new file mode 100755 index 0000000..38b0d27 --- /dev/null +++ b/test-preproc.c @@ -0,0 +1,1515 @@ +# 1 "test.c" +# 1 "" +# 1 "" +# 1 "test.c" + + + +# 1 "/usr/include/stdio.h" 1 3 4 +# 29 "/usr/include/stdio.h" 3 4 +# 1 "/usr/include/_ansi.h" 1 3 4 +# 15 "/usr/include/_ansi.h" 3 4 +# 1 "/usr/include/newlib.h" 1 3 4 +# 14 "/usr/include/newlib.h" 3 4 +# 1 "/usr/include/_newlib_version.h" 1 3 4 +# 15 "/usr/include/newlib.h" 2 3 4 +# 16 "/usr/include/_ansi.h" 2 3 4 +# 1 "/usr/include/sys/config.h" 1 3 4 + + + +# 1 "/usr/include/machine/ieeefp.h" 1 3 4 +# 5 "/usr/include/sys/config.h" 2 3 4 +# 1 "/usr/include/sys/features.h" 1 3 4 +# 6 "/usr/include/sys/config.h" 2 3 4 +# 233 "/usr/include/sys/config.h" 3 4 +# 1 "/usr/include/cygwin/config.h" 1 3 4 +# 234 "/usr/include/sys/config.h" 2 3 4 +# 17 "/usr/include/_ansi.h" 2 3 4 +# 30 "/usr/include/stdio.h" 2 3 4 + + + + + +# 1 "/usr/include/sys/cdefs.h" 1 3 4 +# 43 "/usr/include/sys/cdefs.h" 3 4 +# 1 "/usr/include/machine/_default_types.h" 1 3 4 +# 41 "/usr/include/machine/_default_types.h" 3 4 + +# 41 "/usr/include/machine/_default_types.h" 3 4 +typedef signed char __int8_t; + +typedef unsigned char __uint8_t; +# 55 "/usr/include/machine/_default_types.h" 3 4 +typedef short int __int16_t; + +typedef short unsigned int __uint16_t; +# 77 "/usr/include/machine/_default_types.h" 3 4 +typedef int __int32_t; + +typedef unsigned int __uint32_t; +# 103 "/usr/include/machine/_default_types.h" 3 4 +typedef long int __int64_t; + +typedef long unsigned int __uint64_t; +# 134 "/usr/include/machine/_default_types.h" 3 4 +typedef signed char __int_least8_t; + +typedef unsigned char __uint_least8_t; +# 160 "/usr/include/machine/_default_types.h" 3 4 +typedef short int __int_least16_t; + +typedef short unsigned int __uint_least16_t; +# 182 "/usr/include/machine/_default_types.h" 3 4 +typedef int __int_least32_t; + +typedef unsigned int __uint_least32_t; +# 200 "/usr/include/machine/_default_types.h" 3 4 +typedef long int __int_least64_t; + +typedef long unsigned int __uint_least64_t; +# 214 "/usr/include/machine/_default_types.h" 3 4 +typedef long int __intmax_t; + + + + + + + +typedef long unsigned int __uintmax_t; + + + + + + + +typedef long int __intptr_t; + +typedef long unsigned int __uintptr_t; +# 44 "/usr/include/sys/cdefs.h" 2 3 4 + +# 1 "/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/stddef.h" 1 3 4 +# 216 "/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/stddef.h" 3 4 +typedef long unsigned int size_t; +# 46 "/usr/include/sys/cdefs.h" 2 3 4 +# 36 "/usr/include/stdio.h" 2 3 4 +# 1 "/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/stddef.h" 1 3 4 +# 149 "/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/stddef.h" 3 4 +typedef long int ptrdiff_t; +# 328 "/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/stddef.h" 3 4 +typedef short unsigned int wchar_t; +# 426 "/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/stddef.h" 3 4 +typedef struct { + long long __max_align_ll __attribute__((__aligned__(__alignof__(long long)))); + long double __max_align_ld __attribute__((__aligned__(__alignof__(long double)))); +} max_align_t; +# 37 "/usr/include/stdio.h" 2 3 4 + + + +# 1 "/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/stdarg.h" 1 3 4 +# 40 "/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/stdarg.h" 3 4 +typedef __builtin_va_list __gnuc_va_list; +# 41 "/usr/include/stdio.h" 2 3 4 + + + + + +typedef __gnuc_va_list va_list; +# 60 "/usr/include/stdio.h" 3 4 +# 1 "/usr/include/sys/reent.h" 1 3 4 +# 13 "/usr/include/sys/reent.h" 3 4 +# 1 "/usr/include/_ansi.h" 1 3 4 +# 14 "/usr/include/sys/reent.h" 2 3 4 +# 1 "/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/stddef.h" 1 3 4 +# 15 "/usr/include/sys/reent.h" 2 3 4 +# 1 "/usr/include/sys/_types.h" 1 3 4 +# 24 "/usr/include/sys/_types.h" 3 4 +# 1 "/usr/include/machine/_types.h" 1 3 4 +# 17 "/usr/include/machine/_types.h" 3 4 +typedef __int64_t __blkcnt_t; + + +typedef __int32_t __blksize_t; + + +typedef __uint32_t __dev_t; + + + +typedef unsigned long __fsblkcnt_t; + + + +typedef unsigned long __fsfilcnt_t; + + +typedef __uint32_t __uid_t; + + +typedef __uint32_t __gid_t; + + +typedef __uint64_t __ino_t; + + +typedef long long __key_t; + + +typedef __uint16_t __sa_family_t; + + + +typedef int __socklen_t; +# 25 "/usr/include/sys/_types.h" 2 3 4 +# 1 "/usr/include/sys/lock.h" 1 3 4 +# 12 "/usr/include/sys/lock.h" 3 4 +typedef void *_LOCK_T; +# 42 "/usr/include/sys/lock.h" 3 4 +void __cygwin_lock_init(_LOCK_T *); +void __cygwin_lock_init_recursive(_LOCK_T *); +void __cygwin_lock_fini(_LOCK_T *); +void __cygwin_lock_lock(_LOCK_T *); +int __cygwin_lock_trylock(_LOCK_T *); +void __cygwin_lock_unlock(_LOCK_T *); +# 26 "/usr/include/sys/_types.h" 2 3 4 +# 44 "/usr/include/sys/_types.h" 3 4 +typedef long _off_t; + + + + + +typedef int __pid_t; +# 65 "/usr/include/sys/_types.h" 3 4 +typedef __uint32_t __id_t; +# 88 "/usr/include/sys/_types.h" 3 4 +typedef __uint32_t __mode_t; + + + + + +__extension__ typedef long long _off64_t; + + + + + +typedef _off_t __off_t; + + +typedef _off64_t __loff_t; +# 114 "/usr/include/sys/_types.h" 3 4 +typedef long _fpos_t; + + + + + +typedef _off64_t _fpos64_t; +# 129 "/usr/include/sys/_types.h" 3 4 +typedef long unsigned int __size_t; +# 145 "/usr/include/sys/_types.h" 3 4 +typedef long signed int _ssize_t; +# 156 "/usr/include/sys/_types.h" 3 4 +typedef _ssize_t __ssize_t; + + +# 1 "/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/stddef.h" 1 3 4 +# 357 "/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/stddef.h" 3 4 +typedef unsigned int wint_t; +# 160 "/usr/include/sys/_types.h" 2 3 4 + + + +typedef struct +{ + int __count; + union + { + wint_t __wch; + unsigned char __wchb[4]; + } __value; +} _mbstate_t; + + + +typedef _LOCK_T _flock_t; + + + + +typedef void *_iconv_t; + + + +typedef unsigned long __clock_t; + + +typedef long __time_t; + + +typedef unsigned long __clockid_t; + + +typedef unsigned long __timer_t; +# 203 "/usr/include/sys/_types.h" 3 4 +typedef unsigned short __nlink_t; +typedef long __suseconds_t; +typedef unsigned long __useconds_t; + + +typedef __builtin_va_list __va_list; +# 16 "/usr/include/sys/reent.h" 2 3 4 +# 25 "/usr/include/sys/reent.h" 3 4 +typedef unsigned int __ULong; +# 38 "/usr/include/sys/reent.h" 3 4 +struct _reent; + +struct __locale_t; + + + + + + +struct _Bigint +{ + struct _Bigint *_next; + int _k, _maxwds, _sign, _wds; + __ULong _x[1]; +}; + + +struct __tm +{ + int __tm_sec; + int __tm_min; + int __tm_hour; + int __tm_mday; + int __tm_mon; + int __tm_year; + int __tm_wday; + int __tm_yday; + int __tm_isdst; +}; + + + + + + + +struct _on_exit_args { + void * _fnargs[32]; + void * _dso_handle[32]; + + __ULong _fntypes; + + + __ULong _is_cxa; +}; +# 93 "/usr/include/sys/reent.h" 3 4 +struct _atexit { + struct _atexit *_next; + int _ind; + + void (*_fns[32])(void); + struct _on_exit_args _on_exit_args; +}; +# 117 "/usr/include/sys/reent.h" 3 4 +struct __sbuf { + unsigned char *_base; + int _size; +}; +# 181 "/usr/include/sys/reent.h" 3 4 +struct __sFILE { + unsigned char *_p; + int _r; + int _w; + short _flags; + short _file; + struct __sbuf _bf; + int _lbfsize; + + + + + + + void * _cookie; + + _ssize_t (__attribute__((__cdecl__)) * _read) (struct _reent *, void *, char *, size_t) + ; + _ssize_t (__attribute__((__cdecl__)) * _write) (struct _reent *, void *, const char *, size_t) + + ; + _fpos_t (__attribute__((__cdecl__)) * _seek) (struct _reent *, void *, _fpos_t, int); + int (__attribute__((__cdecl__)) * _close) (struct _reent *, void *); + + + struct __sbuf _ub; + unsigned char *_up; + int _ur; + + + unsigned char _ubuf[3]; + unsigned char _nbuf[1]; + + + struct __sbuf _lb; + + + int _blksize; + _off_t _offset; + + + struct _reent *_data; + + + + _flock_t _lock; + + _mbstate_t _mbstate; + int _flags2; +}; +# 239 "/usr/include/sys/reent.h" 3 4 +struct __sFILE64 { + unsigned char *_p; + int _r; + int _w; + short _flags; + short _file; + struct __sbuf _bf; + int _lbfsize; + + struct _reent *_data; + + + void * _cookie; + + _ssize_t (__attribute__((__cdecl__)) * _read) (struct _reent *, void *, char *, size_t) + ; + _ssize_t (__attribute__((__cdecl__)) * _write) (struct _reent *, void *, const char *, size_t) + + ; + _fpos_t (__attribute__((__cdecl__)) * _seek) (struct _reent *, void *, _fpos_t, int); + int (__attribute__((__cdecl__)) * _close) (struct _reent *, void *); + + + struct __sbuf _ub; + unsigned char *_up; + int _ur; + + + unsigned char _ubuf[3]; + unsigned char _nbuf[1]; + + + struct __sbuf _lb; + + + int _blksize; + int _flags2; + + _off64_t _offset; + _fpos64_t (__attribute__((__cdecl__)) * _seek64) (struct _reent *, void *, _fpos64_t, int); + + + _flock_t _lock; + + _mbstate_t _mbstate; +}; +typedef struct __sFILE64 __FILE; + + + + + +struct _glue +{ + struct _glue *_next; + int _niobs; + __FILE *_iobs; +}; +# 319 "/usr/include/sys/reent.h" 3 4 +struct _rand48 { + unsigned short _seed[3]; + unsigned short _mult[3]; + unsigned short _add; + + + + +}; +# 569 "/usr/include/sys/reent.h" 3 4 +struct _reent +{ + int _errno; + + + + + __FILE *_stdin, *_stdout, *_stderr; + + int _inc; + char _emergency[25]; + + + int _unspecified_locale_info; + struct __locale_t *_locale; + + int __sdidinit; + + void (__attribute__((__cdecl__)) * __cleanup) (struct _reent *); + + + struct _Bigint *_result; + int _result_k; + struct _Bigint *_p5s; + struct _Bigint **_freelist; + + + int _cvtlen; + char *_cvtbuf; + + union + { + struct + { + unsigned int _unused_rand; + char * _strtok_last; + char _asctime_buf[26]; + struct __tm _localtime_buf; + int _gamma_signgam; + __extension__ unsigned long long _rand_next; + struct _rand48 _r48; + _mbstate_t _mblen_state; + _mbstate_t _mbtowc_state; + _mbstate_t _wctomb_state; + char _l64a_buf[8]; + char _signal_buf[24]; + int _getdate_err; + _mbstate_t _mbrlen_state; + _mbstate_t _mbrtowc_state; + _mbstate_t _mbsrtowcs_state; + _mbstate_t _wcrtomb_state; + _mbstate_t _wcsrtombs_state; + int _h_errno; + } _reent; + + + + struct + { + + unsigned char * _nextf[30]; + unsigned int _nmalloc[30]; + } _unused; + } _new; + + + + struct _atexit *_atexit; + struct _atexit _atexit0; + + + + void (**(_sig_func))(int); + + + + + struct _glue __sglue; + + __FILE __sf[3]; + +}; +# 775 "/usr/include/sys/reent.h" 3 4 +extern struct _reent *_impure_ptr ; +extern struct _reent *const _global_impure_ptr ; + +void _reclaim_reent (struct _reent *); + + + + + + struct _reent * __attribute__((__cdecl__)) __getreent (void); +# 61 "/usr/include/stdio.h" 2 3 4 +# 1 "/usr/include/sys/types.h" 1 3 4 +# 28 "/usr/include/sys/types.h" 3 4 +typedef __uint8_t u_int8_t; + + +typedef __uint16_t u_int16_t; + + +typedef __uint32_t u_int32_t; + + +typedef __uint64_t u_int64_t; + +typedef int register_t; +# 62 "/usr/include/sys/types.h" 3 4 +# 1 "/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/stddef.h" 1 3 4 +# 63 "/usr/include/sys/types.h" 2 3 4 + +# 1 "/usr/include/sys/_stdint.h" 1 3 4 +# 20 "/usr/include/sys/_stdint.h" 3 4 +typedef __int8_t int8_t ; + + + +typedef __uint8_t uint8_t ; + + + + + + + +typedef __int16_t int16_t ; + + + +typedef __uint16_t uint16_t ; + + + + + + + +typedef __int32_t int32_t ; + + + +typedef __uint32_t uint32_t ; + + + + + + + +typedef __int64_t int64_t ; + + + +typedef __uint64_t uint64_t ; + + + + + + +typedef __intmax_t intmax_t; + + + + +typedef __uintmax_t uintmax_t; + + + + +typedef __intptr_t intptr_t; + + + + +typedef __uintptr_t uintptr_t; +# 65 "/usr/include/sys/types.h" 2 3 4 + + +# 1 "/usr/include/machine/endian.h" 1 3 4 + + + + + +# 1 "/usr/include/machine/_endian.h" 1 3 4 +# 14 "/usr/include/machine/_endian.h" 3 4 +# 1 "/usr/include/bits/endian.h" 1 3 4 +# 15 "/usr/include/machine/_endian.h" 2 3 4 +# 23 "/usr/include/machine/_endian.h" 3 4 +static __inline__ __uint32_t __ntohl(__uint32_t); +static __inline__ __uint16_t __ntohs(__uint16_t); + +static __inline__ __uint32_t +__ntohl(__uint32_t _x) +{ + __asm__("bswap %0" : "=r" (_x) : "0" (_x)); + return _x; +} + +static __inline__ __uint16_t +__ntohs(__uint16_t _x) +{ + __asm__("xchgb %b0,%h0" + : "=Q" (_x) + : "0" (_x)); + return _x; +} +# 7 "/usr/include/machine/endian.h" 2 3 4 +# 68 "/usr/include/sys/types.h" 2 3 4 +# 1 "/usr/include/sys/select.h" 1 3 4 +# 25 "/usr/include/sys/select.h" 3 4 +# 1 "/usr/include/sys/_sigset.h" 1 3 4 +# 41 "/usr/include/sys/_sigset.h" 3 4 +typedef unsigned long __sigset_t; +# 26 "/usr/include/sys/select.h" 2 3 4 +# 1 "/usr/include/sys/_timeval.h" 1 3 4 +# 35 "/usr/include/sys/_timeval.h" 3 4 +typedef __suseconds_t suseconds_t; + + + + +typedef long time_t; +# 52 "/usr/include/sys/_timeval.h" 3 4 +struct timeval { + time_t tv_sec; + suseconds_t tv_usec; +}; +# 27 "/usr/include/sys/select.h" 2 3 4 +# 1 "/usr/include/sys/timespec.h" 1 3 4 +# 38 "/usr/include/sys/timespec.h" 3 4 +# 1 "/usr/include/sys/_timespec.h" 1 3 4 +# 45 "/usr/include/sys/_timespec.h" 3 4 +struct timespec { + time_t tv_sec; + long tv_nsec; +}; +# 39 "/usr/include/sys/timespec.h" 2 3 4 +# 58 "/usr/include/sys/timespec.h" 3 4 +struct itimerspec { + struct timespec it_interval; + struct timespec it_value; +}; +# 28 "/usr/include/sys/select.h" 2 3 4 + + + +typedef __sigset_t sigset_t; +# 45 "/usr/include/sys/select.h" 3 4 +typedef unsigned long fd_mask; + + + + + + + +typedef struct _types_fd_set { + fd_mask fds_bits[(((64)+(((sizeof (fd_mask) * 8))-1))/((sizeof (fd_mask) * 8)))]; +} _types_fd_set; +# 71 "/usr/include/sys/select.h" 3 4 + + +int select (int __n, _types_fd_set *__readfds, _types_fd_set *__writefds, _types_fd_set *__exceptfds, struct timeval *__timeout) + ; + +int pselect (int __n, _types_fd_set *__readfds, _types_fd_set *__writefds, _types_fd_set *__exceptfds, const struct timespec *__timeout, const sigset_t *__set) + + ; + + + +# 69 "/usr/include/sys/types.h" 2 3 4 + + + + +typedef __uint32_t in_addr_t; + + + + +typedef __uint16_t in_port_t; +# 87 "/usr/include/sys/types.h" 3 4 +typedef unsigned char u_char; + + + +typedef unsigned short u_short; + + + +typedef unsigned int u_int; + + + +typedef unsigned long u_long; + + + + + + + +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; + + + +typedef __blkcnt_t blkcnt_t; + + + + +typedef __blksize_t blksize_t; + + + + +typedef unsigned long clock_t; +# 135 "/usr/include/sys/types.h" 3 4 +typedef long daddr_t; + + + +typedef char * caddr_t; + + + + +typedef __fsblkcnt_t fsblkcnt_t; +typedef __fsfilcnt_t fsfilcnt_t; + + + + +typedef __id_t id_t; + + + + +typedef __ino_t ino_t; +# 173 "/usr/include/sys/types.h" 3 4 +typedef __off_t off_t; + + + +typedef __dev_t dev_t; + + + +typedef __uid_t uid_t; + + + +typedef __gid_t gid_t; + + + + +typedef __pid_t pid_t; + + + + +typedef __key_t key_t; + + + + +typedef _ssize_t ssize_t; + + + + +typedef __mode_t mode_t; + + + + +typedef __nlink_t nlink_t; + + + + +typedef __clockid_t clockid_t; + + + + + +typedef __timer_t timer_t; + + + + + +typedef __useconds_t useconds_t; +# 236 "/usr/include/sys/types.h" 3 4 +typedef __int64_t sbintime_t; + + +# 1 "/usr/include/sys/_pthreadtypes.h" 1 3 4 +# 15 "/usr/include/sys/_pthreadtypes.h" 3 4 +typedef struct __pthread_t {char __dummy;} *pthread_t; +typedef struct __pthread_mutex_t {char __dummy;} *pthread_mutex_t; + +typedef struct __pthread_key_t {char __dummy;} *pthread_key_t; +typedef struct __pthread_attr_t {char __dummy;} *pthread_attr_t; +typedef struct __pthread_mutexattr_t {char __dummy;} *pthread_mutexattr_t; +typedef struct __pthread_condattr_t {char __dummy;} *pthread_condattr_t; +typedef struct __pthread_cond_t {char __dummy;} *pthread_cond_t; +typedef struct __pthread_barrierattr_t {char __dummy;} *pthread_barrierattr_t; +typedef struct __pthread_barrier_t {char __dummy;} *pthread_barrier_t; + + +typedef struct +{ + pthread_mutex_t mutex; + int state; +} +pthread_once_t; +typedef struct __pthread_spinlock_t {char __dummy;} *pthread_spinlock_t; +typedef struct __pthread_rwlock_t {char __dummy;} *pthread_rwlock_t; +typedef struct __pthread_rwlockattr_t {char __dummy;} *pthread_rwlockattr_t; +# 240 "/usr/include/sys/types.h" 2 3 4 +# 1 "/usr/include/machine/types.h" 1 3 4 +# 19 "/usr/include/machine/types.h" 3 4 +# 1 "/usr/include/endian.h" 1 3 4 +# 38 "/usr/include/endian.h" 3 4 +# 1 "/usr/include/bits/byteswap.h" 1 3 4 +# 16 "/usr/include/bits/byteswap.h" 3 4 +static __inline unsigned short +__bswap_16 (unsigned short __x) +{ + return (__x >> 8) | (__x << 8); +} + +static __inline unsigned int +__bswap_32 (unsigned int __x) +{ + return (__bswap_16 (__x & 0xffff) << 16) | (__bswap_16 (__x >> 16)); +} + +static __inline unsigned long long +__bswap_64 (unsigned long long __x) +{ + return (((unsigned long long) __bswap_32 (__x & 0xffffffffull)) << 32) | (__bswap_32 (__x >> 32)); +} +# 39 "/usr/include/endian.h" 2 3 4 +# 20 "/usr/include/machine/types.h" 2 3 4 +# 1 "/usr/include/bits/wordsize.h" 1 3 4 +# 21 "/usr/include/machine/types.h" 2 3 4 + + + + +typedef struct timespec timespec_t; + + + + +typedef struct timespec timestruc_t; + + +typedef __loff_t loff_t; +# 46 "/usr/include/machine/types.h" 3 4 +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + + + + + + +typedef unsigned long vm_offset_t; + + + + +typedef unsigned long vm_size_t; + + + + +typedef void *vm_object_t; + + + + +typedef char *addr_t; + + + + + +# 1 "/usr/include/sys/sysmacros.h" 1 3 4 +# 12 "/usr/include/sys/sysmacros.h" 3 4 +# 1 "/usr/include/sys/types.h" 1 3 4 +# 13 "/usr/include/sys/sysmacros.h" 2 3 4 + +static __inline__ int gnu_dev_major(dev_t); +static __inline__ int gnu_dev_minor(dev_t); +static __inline__ dev_t gnu_dev_makedev(int, int); + +static __inline__ int +gnu_dev_major(dev_t dev) +{ + return (int)(((dev) >> 16) & 0xffff); +} + +static __inline__ int +gnu_dev_minor(dev_t dev) +{ + return (int)((dev) & 0xffff); +} + +static __inline__ dev_t +gnu_dev_makedev(int maj, int min) +{ + return (((maj) << 16) | ((min) & 0xffff)); +} +# 81 "/usr/include/machine/types.h" 2 3 4 +# 241 "/usr/include/sys/types.h" 2 3 4 +# 62 "/usr/include/stdio.h" 2 3 4 + + + + +typedef __FILE FILE; + + + + +typedef _fpos64_t fpos_t; + + + + + + + +# 1 "/usr/include/sys/stdio.h" 1 3 4 +# 33 "/usr/include/sys/stdio.h" 3 4 + + +ssize_t __attribute__((__cdecl__)) getline (char **, size_t *, FILE *); +ssize_t __attribute__((__cdecl__)) getdelim (char **, size_t *, int, FILE *); + + +# 80 "/usr/include/stdio.h" 2 3 4 +# 181 "/usr/include/stdio.h" 3 4 +char * __attribute__((__cdecl__)) ctermid (char *); + + + + +FILE * __attribute__((__cdecl__)) tmpfile (void); +char * __attribute__((__cdecl__)) tmpnam (char *); + +char * __attribute__((__cdecl__)) tempnam (const char *, const char *); + +int __attribute__((__cdecl__)) fclose (FILE *); +int __attribute__((__cdecl__)) fflush (FILE *); +FILE * __attribute__((__cdecl__)) freopen (const char *restrict, const char *restrict, FILE *restrict); +void __attribute__((__cdecl__)) setbuf (FILE *restrict, char *restrict); +int __attribute__((__cdecl__)) setvbuf (FILE *restrict, char *restrict, int, size_t); +int __attribute__((__cdecl__)) fprintf (FILE *restrict, const char *restrict, ...) __attribute__ ((__format__ (__printf__, 2, 3))) + ; +int __attribute__((__cdecl__)) fscanf (FILE *restrict, const char *restrict, ...) __attribute__ ((__format__ (__scanf__, 2, 3))) + ; +int __attribute__((__cdecl__)) printf (const char *restrict, ...) __attribute__ ((__format__ (__printf__, 1, 2))) + ; +int __attribute__((__cdecl__)) scanf (const char *restrict, ...) __attribute__ ((__format__ (__scanf__, 1, 2))) + ; +int __attribute__((__cdecl__)) sscanf (const char *restrict, const char *restrict, ...) __attribute__ ((__format__ (__scanf__, 2, 3))) + ; +int __attribute__((__cdecl__)) vfprintf (FILE *restrict, const char *restrict, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 2, 0))) + ; +int __attribute__((__cdecl__)) vprintf (const char *, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 1, 0))) + ; +int __attribute__((__cdecl__)) vsprintf (char *restrict, const char *restrict, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 2, 0))) + ; +int __attribute__((__cdecl__)) fgetc (FILE *); +char * __attribute__((__cdecl__)) fgets (char *restrict, int, FILE *restrict); +int __attribute__((__cdecl__)) fputc (int, FILE *); +int __attribute__((__cdecl__)) fputs (const char *restrict, FILE *restrict); +int __attribute__((__cdecl__)) getc (FILE *); +int __attribute__((__cdecl__)) getchar (void); +char * __attribute__((__cdecl__)) gets (char *); +int __attribute__((__cdecl__)) putc (int, FILE *); +int __attribute__((__cdecl__)) putchar (int); +int __attribute__((__cdecl__)) puts (const char *); +int __attribute__((__cdecl__)) ungetc (int, FILE *); +size_t __attribute__((__cdecl__)) fread (void * restrict, size_t _size, size_t _n, FILE *restrict); +size_t __attribute__((__cdecl__)) fwrite (const void * restrict , size_t _size, size_t _n, FILE *); + + + +int __attribute__((__cdecl__)) fgetpos (FILE *restrict, fpos_t *restrict); + +int __attribute__((__cdecl__)) fseek (FILE *, long, int); + + + +int __attribute__((__cdecl__)) fsetpos (FILE *, const fpos_t *); + +long __attribute__((__cdecl__)) ftell ( FILE *); +void __attribute__((__cdecl__)) rewind (FILE *); +void __attribute__((__cdecl__)) clearerr (FILE *); +int __attribute__((__cdecl__)) feof (FILE *); +int __attribute__((__cdecl__)) ferror (FILE *); +void __attribute__((__cdecl__)) perror (const char *); + +FILE * __attribute__((__cdecl__)) fopen (const char *restrict _name, const char *restrict _type); +int __attribute__((__cdecl__)) sprintf (char *restrict, const char *restrict, ...) __attribute__ ((__format__ (__printf__, 2, 3))) + ; +int __attribute__((__cdecl__)) remove (const char *); +int __attribute__((__cdecl__)) rename (const char *, const char *); +# 257 "/usr/include/stdio.h" 3 4 +int __attribute__((__cdecl__)) fseeko (FILE *, off_t, int); +off_t __attribute__((__cdecl__)) ftello ( FILE *); + + + + + + + +int __attribute__((__cdecl__)) snprintf (char *restrict, size_t, const char *restrict, ...) __attribute__ ((__format__ (__printf__, 3, 4))) + ; +int __attribute__((__cdecl__)) vsnprintf (char *restrict, size_t, const char *restrict, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 3, 0))) + ; +int __attribute__((__cdecl__)) vfscanf (FILE *restrict, const char *restrict, __gnuc_va_list) __attribute__ ((__format__ (__scanf__, 2, 0))) + ; +int __attribute__((__cdecl__)) vscanf (const char *, __gnuc_va_list) __attribute__ ((__format__ (__scanf__, 1, 0))) + ; +int __attribute__((__cdecl__)) vsscanf (const char *restrict, const char *restrict, __gnuc_va_list) __attribute__ ((__format__ (__scanf__, 2, 0))) + ; +# 284 "/usr/include/stdio.h" 3 4 +int __attribute__((__cdecl__)) asiprintf (char **, const char *, ...) __attribute__ ((__format__ (__printf__, 2, 3))) + ; +char * __attribute__((__cdecl__)) asniprintf (char *, size_t *, const char *, ...) __attribute__ ((__format__ (__printf__, 3, 4))) + ; +char * __attribute__((__cdecl__)) asnprintf (char *restrict, size_t *restrict, const char *restrict, ...) __attribute__ ((__format__ (__printf__, 3, 4))) + ; + +int __attribute__((__cdecl__)) diprintf (int, const char *, ...) __attribute__ ((__format__ (__printf__, 2, 3))) + ; + +int __attribute__((__cdecl__)) fiprintf (FILE *, const char *, ...) __attribute__ ((__format__ (__printf__, 2, 3))) + ; +int __attribute__((__cdecl__)) fiscanf (FILE *, const char *, ...) __attribute__ ((__format__ (__scanf__, 2, 3))) + ; +int __attribute__((__cdecl__)) iprintf (const char *, ...) __attribute__ ((__format__ (__printf__, 1, 2))) + ; +int __attribute__((__cdecl__)) iscanf (const char *, ...) __attribute__ ((__format__ (__scanf__, 1, 2))) + ; +int __attribute__((__cdecl__)) siprintf (char *, const char *, ...) __attribute__ ((__format__ (__printf__, 2, 3))) + ; +int __attribute__((__cdecl__)) siscanf (const char *, const char *, ...) __attribute__ ((__format__ (__scanf__, 2, 3))) + ; +int __attribute__((__cdecl__)) sniprintf (char *, size_t, const char *, ...) __attribute__ ((__format__ (__printf__, 3, 4))) + ; +int __attribute__((__cdecl__)) vasiprintf (char **, const char *, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 2, 0))) + ; +char * __attribute__((__cdecl__)) vasniprintf (char *, size_t *, const char *, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 3, 0))) + ; +char * __attribute__((__cdecl__)) vasnprintf (char *, size_t *, const char *, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 3, 0))) + ; +int __attribute__((__cdecl__)) vdiprintf (int, const char *, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 2, 0))) + ; +int __attribute__((__cdecl__)) vfiprintf (FILE *, const char *, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 2, 0))) + ; +int __attribute__((__cdecl__)) vfiscanf (FILE *, const char *, __gnuc_va_list) __attribute__ ((__format__ (__scanf__, 2, 0))) + ; +int __attribute__((__cdecl__)) viprintf (const char *, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 1, 0))) + ; +int __attribute__((__cdecl__)) viscanf (const char *, __gnuc_va_list) __attribute__ ((__format__ (__scanf__, 1, 0))) + ; +int __attribute__((__cdecl__)) vsiprintf (char *, const char *, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 2, 0))) + ; +int __attribute__((__cdecl__)) vsiscanf (const char *, const char *, __gnuc_va_list) __attribute__ ((__format__ (__scanf__, 2, 0))) + ; +int __attribute__((__cdecl__)) vsniprintf (char *, size_t, const char *, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 3, 0))) + ; +# 339 "/usr/include/stdio.h" 3 4 +FILE * __attribute__((__cdecl__)) fdopen (int, const char *); + +int __attribute__((__cdecl__)) fileno (FILE *); + + +int __attribute__((__cdecl__)) pclose (FILE *); +FILE * __attribute__((__cdecl__)) popen (const char *, const char *); + + + +void __attribute__((__cdecl__)) setbuffer (FILE *, char *, int); +int __attribute__((__cdecl__)) setlinebuf (FILE *); + + + +int __attribute__((__cdecl__)) getw (FILE *); +int __attribute__((__cdecl__)) putw (int, FILE *); + + +int __attribute__((__cdecl__)) getc_unlocked (FILE *); +int __attribute__((__cdecl__)) getchar_unlocked (void); +void __attribute__((__cdecl__)) flockfile (FILE *); +int __attribute__((__cdecl__)) ftrylockfile (FILE *); +void __attribute__((__cdecl__)) funlockfile (FILE *); +int __attribute__((__cdecl__)) putc_unlocked (int, FILE *); +int __attribute__((__cdecl__)) putchar_unlocked (int); +# 374 "/usr/include/stdio.h" 3 4 +int __attribute__((__cdecl__)) dprintf (int, const char *restrict, ...) __attribute__ ((__format__ (__printf__, 2, 3))) + ; + +FILE * __attribute__((__cdecl__)) fmemopen (void *restrict, size_t, const char *restrict); + + +FILE * __attribute__((__cdecl__)) open_memstream (char **, size_t *); +int __attribute__((__cdecl__)) vdprintf (int, const char *restrict, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 2, 0))) + ; + + + +int __attribute__((__cdecl__)) renameat (int, const char *, int, const char *); + + + + + + +int __attribute__((__cdecl__)) _asiprintf_r (struct _reent *, char **, const char *, ...) __attribute__ ((__format__ (__printf__, 3, 4))) + ; +char * __attribute__((__cdecl__)) _asniprintf_r (struct _reent *, char *, size_t *, const char *, ...) __attribute__ ((__format__ (__printf__, 4, 5))) + ; +char * __attribute__((__cdecl__)) _asnprintf_r (struct _reent *, char *restrict, size_t *restrict, const char *restrict, ...) __attribute__ ((__format__ (__printf__, 4, 5))) + ; +int __attribute__((__cdecl__)) _asprintf_r (struct _reent *, char **restrict, const char *restrict, ...) __attribute__ ((__format__ (__printf__, 3, 4))) + ; +int __attribute__((__cdecl__)) _diprintf_r (struct _reent *, int, const char *, ...) __attribute__ ((__format__ (__printf__, 3, 4))) + ; +int __attribute__((__cdecl__)) _dprintf_r (struct _reent *, int, const char *restrict, ...) __attribute__ ((__format__ (__printf__, 3, 4))) + ; +int __attribute__((__cdecl__)) _fclose_r (struct _reent *, FILE *); +int __attribute__((__cdecl__)) _fcloseall_r (struct _reent *); +FILE * __attribute__((__cdecl__)) _fdopen_r (struct _reent *, int, const char *); +int __attribute__((__cdecl__)) _fflush_r (struct _reent *, FILE *); +int __attribute__((__cdecl__)) _fgetc_r (struct _reent *, FILE *); +int __attribute__((__cdecl__)) _fgetc_unlocked_r (struct _reent *, FILE *); +char * __attribute__((__cdecl__)) _fgets_r (struct _reent *, char *restrict, int, FILE *restrict); +char * __attribute__((__cdecl__)) _fgets_unlocked_r (struct _reent *, char *restrict, int, FILE *restrict); + + + + +int __attribute__((__cdecl__)) _fgetpos_r (struct _reent *, FILE *, fpos_t *); +int __attribute__((__cdecl__)) _fsetpos_r (struct _reent *, FILE *, const fpos_t *); + +int __attribute__((__cdecl__)) _fiprintf_r (struct _reent *, FILE *, const char *, ...) __attribute__ ((__format__ (__printf__, 3, 4))) + ; +int __attribute__((__cdecl__)) _fiscanf_r (struct _reent *, FILE *, const char *, ...) __attribute__ ((__format__ (__scanf__, 3, 4))) + ; +FILE * __attribute__((__cdecl__)) _fmemopen_r (struct _reent *, void *restrict, size_t, const char *restrict); +FILE * __attribute__((__cdecl__)) _fopen_r (struct _reent *, const char *restrict, const char *restrict); +FILE * __attribute__((__cdecl__)) _freopen_r (struct _reent *, const char *restrict, const char *restrict, FILE *restrict); +int __attribute__((__cdecl__)) _fprintf_r (struct _reent *, FILE *restrict, const char *restrict, ...) __attribute__ ((__format__ (__printf__, 3, 4))) + ; +int __attribute__((__cdecl__)) _fpurge_r (struct _reent *, FILE *); +int __attribute__((__cdecl__)) _fputc_r (struct _reent *, int, FILE *); +int __attribute__((__cdecl__)) _fputc_unlocked_r (struct _reent *, int, FILE *); +int __attribute__((__cdecl__)) _fputs_r (struct _reent *, const char *restrict, FILE *restrict); +int __attribute__((__cdecl__)) _fputs_unlocked_r (struct _reent *, const char *restrict, FILE *restrict); +size_t __attribute__((__cdecl__)) _fread_r (struct _reent *, void * restrict, size_t _size, size_t _n, FILE *restrict); +size_t __attribute__((__cdecl__)) _fread_unlocked_r (struct _reent *, void * restrict, size_t _size, size_t _n, FILE *restrict); +int __attribute__((__cdecl__)) _fscanf_r (struct _reent *, FILE *restrict, const char *restrict, ...) __attribute__ ((__format__ (__scanf__, 3, 4))) + ; +int __attribute__((__cdecl__)) _fseek_r (struct _reent *, FILE *, long, int); +int __attribute__((__cdecl__)) _fseeko_r (struct _reent *, FILE *, _off_t, int); +long __attribute__((__cdecl__)) _ftell_r (struct _reent *, FILE *); +_off_t __attribute__((__cdecl__)) _ftello_r (struct _reent *, FILE *); +void __attribute__((__cdecl__)) _rewind_r (struct _reent *, FILE *); +size_t __attribute__((__cdecl__)) _fwrite_r (struct _reent *, const void * restrict, size_t _size, size_t _n, FILE *restrict); +size_t __attribute__((__cdecl__)) _fwrite_unlocked_r (struct _reent *, const void * restrict, size_t _size, size_t _n, FILE *restrict); +int __attribute__((__cdecl__)) _getc_r (struct _reent *, FILE *); +int __attribute__((__cdecl__)) _getc_unlocked_r (struct _reent *, FILE *); +int __attribute__((__cdecl__)) _getchar_r (struct _reent *); +int __attribute__((__cdecl__)) _getchar_unlocked_r (struct _reent *); +char * __attribute__((__cdecl__)) _gets_r (struct _reent *, char *); +int __attribute__((__cdecl__)) _iprintf_r (struct _reent *, const char *, ...) __attribute__ ((__format__ (__printf__, 2, 3))) + ; +int __attribute__((__cdecl__)) _iscanf_r (struct _reent *, const char *, ...) __attribute__ ((__format__ (__scanf__, 2, 3))) + ; +FILE * __attribute__((__cdecl__)) _open_memstream_r (struct _reent *, char **, size_t *); +void __attribute__((__cdecl__)) _perror_r (struct _reent *, const char *); +int __attribute__((__cdecl__)) _printf_r (struct _reent *, const char *restrict, ...) __attribute__ ((__format__ (__printf__, 2, 3))) + ; +int __attribute__((__cdecl__)) _putc_r (struct _reent *, int, FILE *); +int __attribute__((__cdecl__)) _putc_unlocked_r (struct _reent *, int, FILE *); +int __attribute__((__cdecl__)) _putchar_unlocked_r (struct _reent *, int); +int __attribute__((__cdecl__)) _putchar_r (struct _reent *, int); +int __attribute__((__cdecl__)) _puts_r (struct _reent *, const char *); +int __attribute__((__cdecl__)) _remove_r (struct _reent *, const char *); +int __attribute__((__cdecl__)) _rename_r (struct _reent *, const char *_old, const char *_new) + ; +int __attribute__((__cdecl__)) _scanf_r (struct _reent *, const char *restrict, ...) __attribute__ ((__format__ (__scanf__, 2, 3))) + ; +int __attribute__((__cdecl__)) _siprintf_r (struct _reent *, char *, const char *, ...) __attribute__ ((__format__ (__printf__, 3, 4))) + ; +int __attribute__((__cdecl__)) _siscanf_r (struct _reent *, const char *, const char *, ...) __attribute__ ((__format__ (__scanf__, 3, 4))) + ; +int __attribute__((__cdecl__)) _sniprintf_r (struct _reent *, char *, size_t, const char *, ...) __attribute__ ((__format__ (__printf__, 4, 5))) + ; +int __attribute__((__cdecl__)) _snprintf_r (struct _reent *, char *restrict, size_t, const char *restrict, ...) __attribute__ ((__format__ (__printf__, 4, 5))) + ; +int __attribute__((__cdecl__)) _sprintf_r (struct _reent *, char *restrict, const char *restrict, ...) __attribute__ ((__format__ (__printf__, 3, 4))) + ; +int __attribute__((__cdecl__)) _sscanf_r (struct _reent *, const char *restrict, const char *restrict, ...) __attribute__ ((__format__ (__scanf__, 3, 4))) + ; +char * __attribute__((__cdecl__)) _tempnam_r (struct _reent *, const char *, const char *); +FILE * __attribute__((__cdecl__)) _tmpfile_r (struct _reent *); +char * __attribute__((__cdecl__)) _tmpnam_r (struct _reent *, char *); +int __attribute__((__cdecl__)) _ungetc_r (struct _reent *, int, FILE *); +int __attribute__((__cdecl__)) _vasiprintf_r (struct _reent *, char **, const char *, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 3, 0))) + ; +char * __attribute__((__cdecl__)) _vasniprintf_r (struct _reent*, char *, size_t *, const char *, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 4, 0))) + ; +char * __attribute__((__cdecl__)) _vasnprintf_r (struct _reent*, char *, size_t *, const char *, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 4, 0))) + ; +int __attribute__((__cdecl__)) _vasprintf_r (struct _reent *, char **, const char *, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 3, 0))) + ; +int __attribute__((__cdecl__)) _vdiprintf_r (struct _reent *, int, const char *, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 3, 0))) + ; +int __attribute__((__cdecl__)) _vdprintf_r (struct _reent *, int, const char *restrict, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 3, 0))) + ; +int __attribute__((__cdecl__)) _vfiprintf_r (struct _reent *, FILE *, const char *, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 3, 0))) + ; +int __attribute__((__cdecl__)) _vfiscanf_r (struct _reent *, FILE *, const char *, __gnuc_va_list) __attribute__ ((__format__ (__scanf__, 3, 0))) + ; +int __attribute__((__cdecl__)) _vfprintf_r (struct _reent *, FILE *restrict, const char *restrict, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 3, 0))) + ; +int __attribute__((__cdecl__)) _vfscanf_r (struct _reent *, FILE *restrict, const char *restrict, __gnuc_va_list) __attribute__ ((__format__ (__scanf__, 3, 0))) + ; +int __attribute__((__cdecl__)) _viprintf_r (struct _reent *, const char *, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 2, 0))) + ; +int __attribute__((__cdecl__)) _viscanf_r (struct _reent *, const char *, __gnuc_va_list) __attribute__ ((__format__ (__scanf__, 2, 0))) + ; +int __attribute__((__cdecl__)) _vprintf_r (struct _reent *, const char *restrict, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 2, 0))) + ; +int __attribute__((__cdecl__)) _vscanf_r (struct _reent *, const char *restrict, __gnuc_va_list) __attribute__ ((__format__ (__scanf__, 2, 0))) + ; +int __attribute__((__cdecl__)) _vsiprintf_r (struct _reent *, char *, const char *, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 3, 0))) + ; +int __attribute__((__cdecl__)) _vsiscanf_r (struct _reent *, const char *, const char *, __gnuc_va_list) __attribute__ ((__format__ (__scanf__, 3, 0))) + ; +int __attribute__((__cdecl__)) _vsniprintf_r (struct _reent *, char *, size_t, const char *, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 4, 0))) + ; +int __attribute__((__cdecl__)) _vsnprintf_r (struct _reent *, char *restrict, size_t, const char *restrict, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 4, 0))) + ; +int __attribute__((__cdecl__)) _vsprintf_r (struct _reent *, char *restrict, const char *restrict, __gnuc_va_list) __attribute__ ((__format__ (__printf__, 3, 0))) + ; +int __attribute__((__cdecl__)) _vsscanf_r (struct _reent *, const char *restrict, const char *restrict, __gnuc_va_list) __attribute__ ((__format__ (__scanf__, 3, 0))) + ; + + + +int __attribute__((__cdecl__)) fpurge (FILE *); +ssize_t __attribute__((__cdecl__)) __getdelim (char **, size_t *, int, FILE *); +ssize_t __attribute__((__cdecl__)) __getline (char **, size_t *, FILE *); + + +void __attribute__((__cdecl__)) clearerr_unlocked (FILE *); +int __attribute__((__cdecl__)) feof_unlocked (FILE *); +int __attribute__((__cdecl__)) ferror_unlocked (FILE *); +int __attribute__((__cdecl__)) fileno_unlocked (FILE *); +int __attribute__((__cdecl__)) fflush_unlocked (FILE *); +int __attribute__((__cdecl__)) fgetc_unlocked (FILE *); +int __attribute__((__cdecl__)) fputc_unlocked (int, FILE *); +size_t __attribute__((__cdecl__)) fread_unlocked (void * restrict, size_t _size, size_t _n, FILE *restrict); +size_t __attribute__((__cdecl__)) fwrite_unlocked (const void * restrict , size_t _size, size_t _n, FILE *); +# 574 "/usr/include/stdio.h" 3 4 +int __attribute__((__cdecl__)) __srget_r (struct _reent *, FILE *); +int __attribute__((__cdecl__)) __swbuf_r (struct _reent *, int, FILE *); + + + + + + + +FILE *__attribute__((__cdecl__)) funopen (const void * __cookie, int (*__readfn)(void * __c, char *__buf, size_t __n), int (*__writefn)(void * __c, const char *__buf, size_t __n), _fpos64_t (*__seekfn)(void * __c, _fpos64_t __off, int __whence), int (*__closefn)(void * __c)) + + + + + + ; +FILE *__attribute__((__cdecl__)) _funopen_r (struct _reent *, const void * __cookie, int (*__readfn)(void * __c, char *__buf, size_t __n), int (*__writefn)(void * __c, const char *__buf, size_t __n), _fpos64_t (*__seekfn)(void * __c, _fpos64_t __off, int __whence), int (*__closefn)(void * __c)) + + + + + + ; +# 664 "/usr/include/stdio.h" 3 4 +static __inline__ int __sgetc_r(struct _reent *__ptr, FILE *__p); + +static __inline__ int __sgetc_r(struct _reent *__ptr, FILE *__p) + { + int __c = (--(__p)->_r < 0 ? __srget_r(__ptr, __p) : (int)(*(__p)->_p++)); + if ((__p->_flags & 0x4000) && (__c == '\r')) + { + int __c2 = (--(__p)->_r < 0 ? __srget_r(__ptr, __p) : (int)(*(__p)->_p++)); + if (__c2 == '\n') + __c = __c2; + else + ungetc(__c2, __p); + } + return __c; + } + + + + + +static __inline__ int __sputc_r(struct _reent *_ptr, int _c, FILE *_p) { + + if ((_p->_flags & 0x4000) && _c == '\n') + __sputc_r (_ptr, '\r', _p); + + if (--_p->_w >= 0 || (_p->_w >= _p->_lbfsize && (char)_c != '\n')) + return (*_p->_p++ = _c); + else + return (__swbuf_r(_ptr, _c, _p)); +} +# 769 "/usr/include/stdio.h" 3 4 + +# 5 "test.c" 2 + + + + +# 8 "test.c" +main() { + printf("hello\n"); +} + + + +int demo(char *a, char *b) { + strcpy(a, "\n"); + strcpy(a, gettext("Hello there")); + 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); + printf("\\"); + + gets(f); + gets(f); + + + syslog(LOG_ERR,"cannot open config file (%s): %s",filename,strerror(errno)) + syslog(LOG_CRIT,"malloc() failed"); + + syslog(LOG_ERR, attacker_string); + +} + + + +demo2() { + char d[20]; + char s[20]; + int n; + + _mbscpy(d,s); + memcpy(d,s); + CopyMemory(d,s); + lstrcat(d,s); + strncpy(d,s); + _tcsncpy(d,s); + strncat(d,s,10); + strncat(d,s,sizeof(d)); + _tcsncat(d,s,sizeof(d)); + n = strlen(d); + + MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName)); + + MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName); + + MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName)/sizeof(wszUserName[0])); + + MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName /sizeof(wszUserName[0])); + + + + + + + SetSecurityDescriptorDacl(&sd,TRUE, +# 73 "test.c" 3 4 + ((void *)0) +# 73 "test.c" + ,FALSE); + + CreateProcess( +# 75 "test.c" 3 4 + ((void *)0) +# 75 "test.c" + , "C:\\Program Files\\GoodGuy\\GoodGuy.exe -x", ""); + + 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, +# 91 "test.c" 3 4 + ((void *)0) +# 91 "test.c" + )) != +# 91 "test.c" 3 4 + (-1) +# 91 "test.c" + ) { + } +} + +int testfile() { + FILE *f; + f = fopen("/etc/passwd", "r"); + fclose(f); +} +# 113 "test.c" +int accesstest() { + int access = 0; + +} diff --git a/test-results-004.txt b/test-results-004.txt new file mode 100755 index 0000000..e898119 --- /dev/null +++ b/test-results-004.txt @@ -0,0 +1,7 @@ +test.c:32:2: [5] (buffer) gets:Does not check for buffer overflows (CWE-120, CWE-20). Use fgets() instead. +test.c:60:3: [5] (buffer) strncat:Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120). Consider strcat_s, strlcat, snprintf, 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:61:3: [5] (buffer) _tcsncat:Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120). Consider strcat_s, 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:64:3: [5] (buffer) MultiByteToWideChar:Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is high, it appears that the size is given as bytes, but the function requires size as characters. +test.c:66:3: [5] (buffer) MultiByteToWideChar:Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is high, it appears that the size is given as bytes, but the function requires size as characters. +test.c:77:3: [5] (misc) SetSecurityDescriptorDacl:Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732). +test.c:77:3: [5] (misc) SetSecurityDescriptorDacl:Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732). diff --git a/test-results-005.txt b/test-results-005.txt new file mode 100755 index 0000000..5e83b7c --- /dev/null +++ b/test-results-005.txt @@ -0,0 +1 @@ +test-patched.c:13:2: [4] (buffer) strcpy:Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120). Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused). diff --git a/test-results-006.txt b/test-results-006.txt new file mode 100755 index 0000000..e898119 --- /dev/null +++ b/test-results-006.txt @@ -0,0 +1,7 @@ +test.c:32:2: [5] (buffer) gets:Does not check for buffer overflows (CWE-120, CWE-20). Use fgets() instead. +test.c:60:3: [5] (buffer) strncat:Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120). Consider strcat_s, strlcat, snprintf, 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:61:3: [5] (buffer) _tcsncat:Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120). Consider strcat_s, 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:64:3: [5] (buffer) MultiByteToWideChar:Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is high, it appears that the size is given as bytes, but the function requires size as characters. +test.c:66:3: [5] (buffer) MultiByteToWideChar:Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is high, it appears that the size is given as bytes, but the function requires size as characters. +test.c:77:3: [5] (misc) SetSecurityDescriptorDacl:Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732). +test.c:77:3: [5] (misc) SetSecurityDescriptorDacl:Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732). diff --git a/test-results-008.txt b/test-results-008.txt new file mode 100644 index 0000000..be0c58d --- /dev/null +++ b/test-results-008.txt @@ -0,0 +1,17 @@ +Flawfinder version 2.0.10, (C) 2001-2019 David A. Wheeler. +Showing hits not in test-saved-hitlist-008.txt +Number of rules (primarily dangerous function names) in C/C++ ruleset: 223 + +ANALYSIS SUMMARY: + +No hits found. +Lines analyzed = 121 +Physical Source Lines of Code (SLOC) = 84 +Hits@level = [0] 0 [1] 0 [2] 0 [3] 0 [4] 0 [5] 0 +Hits@level+ = [0+] 0 [1+] 0 [2+] 0 [3+] 0 [4+] 0 [5+] 0 +Hits/KSLOC@level+ = [0+] 0 [1+] 0 [2+] 0 [3+] 0 [4+] 0 [5+] 0 +Suppressed hits = 2 (use --neverignore to show them) +Minimum risk level = 1 +There may be other security vulnerabilities; review your code! +See 'Secure Programming HOWTO' +(https://dwheeler.com/secure-programs) for more information. diff --git a/test-results.csv b/test-results.csv new file mode 100755 index 0000000..a4599b5 --- /dev/null +++ b/test-results.csv @@ -0,0 +1,39 @@ +File,Line,Column,Level,Category,Name,Warning,Suggestion,Note,CWEs,Context,Fingerprint +test.c,32,2,5,buffer,gets,"Does not check for buffer overflows (CWE-120, CWE-20)",Use fgets() instead,,"CWE-120, CWE-20", gets(f);,6a5bb383fb44030b0d9428b17359e94ba3979bc1ce702be450427f85592c649a +test.c,60,3,5,buffer,strncat,"Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120)","Consider strcat_s, strlcat, snprintf, or automatically resizing strings","Risk is high; the length parameter appears to be a constant, instead of computing the number of characters left.",CWE-120," strncat(d,s,sizeof(d)); /* Misuse - this should be flagged as riskier. */",cbd19c308547e79af13436d8f7dbcf6c62e49e4f62ba9aee38fbef29e0772f74 +test.c,61,3,5,buffer,_tcsncat,"Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120)","Consider strcat_s, strlcat, or automatically resizing strings","Risk is high; the length parameter appears to be a constant, instead of computing the number of characters left.",CWE-120," _tcsncat(d,s,sizeof(d)); /* Misuse - flag as riskier */",c3f6ba2c710efc878e66df4578894fd408452cb7cdec7ae6f492a3b1796f8c42 +test.c,64,3,5,buffer,MultiByteToWideChar,"Requires maximum length in CHARACTERS, not bytes (CWE-120)",,"Risk is high, it appears that the size is given as bytes, but the function requires size as characters.",CWE-120," MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName));",4f5b73ff337a54d6e1d9a369659ca0ddb4f80e6b7e38a17e5b112f6d3e266e69 +test.c,66,3,5,buffer,MultiByteToWideChar,"Requires maximum length in CHARACTERS, not bytes (CWE-120)",,"Risk is high, it appears that the size is given as bytes, but the function requires size as characters.",CWE-120," MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName);",9ecdc1e903acc16a646bf7909a630ae22a7593b70952c39ce6bd9c5a23fad0fd +test.c,77,3,5,misc,SetSecurityDescriptorDacl,"Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732)",,,CWE-732," SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE);",5fed1e135b593b4c943e66e89a26ff131eba18b83a32a8af37d1c0bd7b01aadb +test.c,77,3,5,misc,SetSecurityDescriptorDacl,"Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732)",,,CWE-732," SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE);",5fed1e135b593b4c943e66e89a26ff131eba18b83a32a8af37d1c0bd7b01aadb +test.c,17,2,4,buffer,strcpy,Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120),"Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused)",,CWE-120," strcpy(b, a);",c01c8472bb53022e912da4da2faebc67d537855da324020c44bfd5e608a79b77 +test.c,20,2,4,buffer,sprintf,Does not check for buffer overflows (CWE-120),"Use sprintf_s, snprintf, or vsnprintf",,CWE-120," sprintf(s, ""hello %s"", bug);",814237858ab012010f3355a49480dd6fa0a2cb8cf8356a98ac1c17c9febf6521 +test.c,21,2,4,buffer,sprintf,Does not check for buffer overflows (CWE-120),"Use sprintf_s, snprintf, or vsnprintf",,CWE-120," sprintf(s, gettext(""hello %s""), bug);",b793f18f143fb2297c49e0639384ad73db86eb01a44377aa4d5d09b44b03d747 +test.c,22,2,4,format,sprintf,Potential format string problem (CWE-134),Make format string constant,,CWE-134," sprintf(s, unknown, bug);",16ebc2ff96ee4bab2695783709e97b597ca9c8b8cc149e33aed859f0fafd3431 +test.c,23,2,4,format,printf,"If format strings can be influenced by an attacker, they can be exploited (CWE-134)",Use a constant for the format specification,,CWE-134," printf(bf, x);",46f42896019245d2dffc4caf4fe018b073ce2a58203676eaa28b6374558a5b5d +test.c,25,2,4,buffer,scanf,"The scanf() family's %s operation, without a limit specification, permits buffer overflows (CWE-120, CWE-20)","Specify a limit to %s, or use a different input function",,"CWE-120, CWE-20"," scanf(""%s"", s);",3f169dd9fe508f70438f818770a3cb8b0f228e4245ea11a929a5fb0a7839fd5f +test.c,27,2,4,buffer,scanf,"The scanf() family's %s operation, without a limit specification, permits buffer overflows (CWE-120, CWE-20)","Specify a limit to %s, or use a different input function",,"CWE-120, CWE-20"," scanf(""%s"", s);",3f169dd9fe508f70438f818770a3cb8b0f228e4245ea11a929a5fb0a7839fd5f +test.c,38,2,4,format,syslog,"If syslog's format strings can be influenced by an attacker, they can be exploited (CWE-134)",Use a constant format string for syslog,,CWE-134," syslog(LOG_ERR, attacker_string);",22e98963d5af7b197a090bd522d2d39b8d8ee7bdf08453fd2008939c92cd9677 +test.c,49,3,4,buffer,_mbscpy,Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120),Consider using a function version that stops copying at the end of the buffer,,CWE-120," _mbscpy(d,s); /* like strcpy, this doesn't check for buffer overflow */",e00a4a1a0a3603db98a23fcff3c9cdfd9012f5a81826814d9508e0f22089b993 +test.c,56,3,4,buffer,lstrcat,Does not check for buffer overflows when concatenating to destination [MS-banned] (CWE-120),,,CWE-120," lstrcat(d,s);",364b4c512862fdccbca27d2fa7737995b5d24b637a760976c940ae636218d340 +test.c,79,3,3,shell,CreateProcess,This causes a new process to execute and is difficult to use safely (CWE-78),"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",,CWE-78," CreateProcess(NULL, ""C:\\Program Files\\GoodGuy\\GoodGuy.exe -x"", """");",3c712b38d0857bde3832d85ad35ac9859be55c5f5f1c20af659a577dd4d0acbf +test.c,79,3,3,shell,CreateProcess,This causes a new process to execute and is difficult to use safely (CWE-78),"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",,CWE-78," CreateProcess(NULL, ""C:\\Program Files\\GoodGuy\\GoodGuy.exe -x"", """");",3c712b38d0857bde3832d85ad35ac9859be55c5f5f1c20af659a577dd4d0acbf +test.c,95,20,3,buffer,getopt_long,"Some older implementations do not protect against internal buffer overflows (CWE-120, CWE-20)","Check implementation on installation, or limit the size of all string inputs",,"CWE-120, CWE-20"," while ((optc = getopt_long (argc, argv, ""a"",longopts, NULL )) != EOF) {",5bedf6e5bccf596008ef191ec4c5d4cc51a32cff0c05ef62d5f10fab93d0cc24 +test.c,16,2,2,buffer,strcpy,Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120),"Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused)",Risk is low because the source is a constant string.,CWE-120," strcpy(a, gettext(""Hello there"")); // Did this work?",d64070fb93ff0bb797fb926f4dddc7212d42f77e288d5ceb0cd30ed2979fa28d +test.c,19,2,2,buffer,sprintf,Does not check for buffer overflows (CWE-120),"Use sprintf_s, snprintf, or vsnprintf",Risk is low because the source has a constant maximum length.,CWE-120," sprintf(s, ""hello"");",907b46be1c3ea7b38f90a4d1b0f43b7751cd8cbe38fae840930ff006b702157d +test.c,45,3,2,buffer,char,"Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120)","Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length",,CWE-119!/CWE-120, char d[20];,36c87517700337a59cc3ad3218cfdde56cad37d69cdeccee5a55ab232d5c7946 +test.c,46,3,2,buffer,char,"Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120)","Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length",,CWE-119!/CWE-120, char s[20];,213de8e8815fc84c423b55fd845fea541f25744718e486234364bb457863b597 +test.c,50,3,2,buffer,memcpy,Does not check for buffer overflows when copying to destination (CWE-120),Make sure destination can always hold the source data,,CWE-120," memcpy(d,s); // fail - no size",e667b352fb0748c67b607b11577b11bad87545779c39923e61839dd04056055f +test.c,53,3,2,buffer,memcpy,Does not check for buffer overflows when copying to destination (CWE-120),Make sure destination can always hold the source data,,CWE-120," memcpy(&n,s,sizeof(s)); // fail - sizeof not of destination",01bcc2c8ba2d928ac3315b4dcc6593042ea05e62888a10a6d2cf16797a65ed32 +test.c,54,3,2,buffer,memcpy,Does not check for buffer overflows when copying to destination (CWE-120),Make sure destination can always hold the source data,,CWE-120," memcpy(d,s,n); // fail - size unguessable",2517a2fb5981193a6017cca660d16e85aab133706cbec302df97aaa623fc77ef +test.c,55,3,2,buffer,CopyMemory,Does not check for buffer overflows when copying to destination (CWE-120),Make sure destination can always hold the source data,,CWE-120," CopyMemory(d,s);",977f8c805ddd76ff32e0f7aea08701ba97d9ce6955136e98b308ed4f70eb2e11 +test.c,101,7,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? (CWE-362)",,,CWE-362," f = fopen(""/etc/passwd"", ""r""); ",2ec6928c77a8b54caa61d0459f367c4394ee1f5e6f488753f587bfa9c780bad8 +test.c,15,2,1,buffer,strcpy,Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120),"Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused)",Risk is low because the source is a constant character.,CWE-120," strcpy(a, ""\n""); // Did this work?",0badc5f4c500d17b42794feaca54ee0f49e607a32510af3ed749579001017edb +test.c,18,2,1,buffer,sprintf,Does not check for buffer overflows (CWE-120),"Use sprintf_s, snprintf, or vsnprintf",Risk is low because the source is a constant character.,CWE-120," sprintf(s, ""\n"");",c65fbd60851f3c8ace22332805966606488c0d242c1823493c582e267609b1a7 +test.c,26,2,1,buffer,scanf,It's unclear if the %s limit in the format string is small enough (CWE-120),"Check that the limit is sufficiently small, or use a different input function",,CWE-120," scanf(""%10s"", s);",e24c4c801f10acfa93098b2bef58524efe4f88237f2dd8b58be9afa838616afe +test.c,57,3,1,buffer,strncpy,Easily used incorrectly; doesn't always \0-terminate or check for invalid pointers [MS-banned] (CWE-120),,,CWE-120," strncpy(d,s);",8fa14bf72393a00f667ffcc06b7b7e5f0b6d2f16d8d67444db06b0deb35b5f5e +test.c,58,3,1,buffer,_tcsncpy,Easily used incorrectly; doesn't always \0-terminate or check for invalid pointers [MS-banned] (CWE-120),,,CWE-120," _tcsncpy(d,s);",691fabd4ca960a00e4c538eee0187ee0fdf59bd43dd71e792c14175150369b8b +test.c,59,3,1,buffer,strncat,"Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120)","Consider strcat_s, strlcat, snprintf, or automatically resizing strings",,CWE-120," strncat(d,s,10);",dd92f996a554bfbc038bea27640ba25dcf298383140a8330dca7cdacf493a701 +test.c,62,7,1,buffer,strlen,Does not handle strings that are not \0-terminated; if given one it may perform an over-read (it could cause a crash if unprotected) (CWE-126),,,CWE-126, n = strlen(d);,db7201c7df7f543ea76febb060bda167e414e71e3d18095fe1def69f8c47a4f6 +test.c,68,3,1,buffer,MultiByteToWideChar,"Requires maximum length in CHARACTERS, not bytes (CWE-120)",,"Risk is very low, the length appears to be in characters not bytes.",CWE-120," MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName)/sizeof(wszUserName[0]));",1813fc329227b38abae867d8023a9e29c7517d679fe55c86f8300dde681b6470 +test.c,70,3,1,buffer,MultiByteToWideChar,"Requires maximum length in CHARACTERS, not bytes (CWE-120)",,"Risk is very low, the length appears to be in characters not bytes.",CWE-120," MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName /sizeof(wszUserName[0]));",7c6cdcb10ad3a16b8bfd56e3dac84829f9bc3e39d4dde74a2be9bbe000102fc5 diff --git a/test-results.html b/test-results.html new file mode 100755 index 0000000..3fe1d99 --- /dev/null +++ b/test-results.html @@ -0,0 +1,344 @@ + + + + +Flawfinder Results + + + + +

        Flawfinder Results

        +Here are the security scan results from +Flawfinder version 2.0.10, +(C) 2001-2019 David A. Wheeler. +Number of rules (primarily dangerous function names) in C/C++ ruleset: 223 +

        +Examining test.c
        +Examining test2.c
        + +

        Final Results

        +
          +
        • test.c:32: [5] (buffer) gets: + Does not check for buffer overflows (CWE-120, CWE-20). Use + fgets() instead. +
          + gets(f);
          +
          +
        • test.c:60: [5] (buffer) strncat: + Easily used incorrectly (e.g., incorrectly computing the correct maximum + size to add) [MS-banned] (CWE-120). + Consider strcat_s, strlcat, snprintf, 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:61: [5] (buffer) _tcsncat: + Easily used incorrectly (e.g., incorrectly computing the correct maximum + size to add) [MS-banned] (CWE-120). + Consider strcat_s, 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:64: [5] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes (CWE-120). 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:66: [5] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes (CWE-120). 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:77: [5] (misc) SetSecurityDescriptorDacl: + Never create NULL ACLs; an attacker can set it to Everyone (Deny All + Access), which would even forbid administrator access (CWE-732). +
          +  SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE);
          +
          +
        • test.c:77: [5] (misc) SetSecurityDescriptorDacl: + Never create NULL ACLs; an attacker can set it to Everyone (Deny All + Access), which would even forbid administrator access (CWE-732). +
          +  SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE);
          +
          +
        • test.c:17: [4] (buffer) strcpy: + Does not check for buffer overflows when copying to destination [MS-banned] + (CWE-120). + Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily + misused). +
          + strcpy(b, a);
          +
          +
        • test.c:20: [4] (buffer) sprintf: + Does not check for buffer overflows (CWE-120). Use + sprintf_s, snprintf, or vsnprintf. +
          + sprintf(s, "hello %s", bug);
          +
          +
        • test.c:21: [4] (buffer) sprintf: + Does not check for buffer overflows (CWE-120). Use + sprintf_s, snprintf, or vsnprintf. +
          + sprintf(s, gettext("hello %s"), bug);
          +
          +
        • test.c:22: [4] (format) sprintf: + Potential format string problem (CWE-134). 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 + (CWE-134). + 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 (CWE-120, CWE-20). 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 (CWE-120, CWE-20). 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 (CWE-134). 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 [MS-banned] + (CWE-120). + 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:56: [4] (buffer) lstrcat: + Does not check for buffer overflows when concatenating to destination + [MS-banned] (CWE-120). +
          +  lstrcat(d,s);
          +
          +
        • test.c:79: [3] (shell) CreateProcess: + This causes a new process to execute and is difficult to use safely (CWE-78). 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:79: [3] (shell) CreateProcess: + This causes a new process to execute and is difficult to use safely (CWE-78). 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:95: [3] (buffer) getopt_long: + Some older implementations do not protect against internal buffer overflows + (CWE-120, CWE-20). 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 [MS-banned] + (CWE-120). + Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy 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 (CWE-120). Use + sprintf_s, 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 improperly restricted, leading to potential + overflows or other issues (CWE-119!/CWE-120). + 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 improperly restricted, leading to potential + overflows or other issues (CWE-119!/CWE-120). + 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 (CWE-120). Make + sure destination can always hold the source data. +
          +  memcpy(d,s); // fail - no size
          +
          +
        • test.c:53: [2] (buffer) memcpy: + Does not check for buffer overflows when copying to destination (CWE-120). Make + sure destination can always hold the source data. +
          +  memcpy(&n,s,sizeof(s)); // fail - sizeof not of destination
          +
          +
        • test.c:54: [2] (buffer) memcpy: + Does not check for buffer overflows when copying to destination (CWE-120). Make + sure destination can always hold the source data. +
          +  memcpy(d,s,n); // fail - size unguessable
          +
          +
        • test.c:55: [2] (buffer) CopyMemory: + Does not check for buffer overflows when copying to destination (CWE-120). Make + sure destination can always hold the source data. +
          +  CopyMemory(d,s);
          +
          +
        • test.c:101: [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? (CWE-362). +
          +  f = fopen("/etc/passwd", "r"); 
          +
          +
        • test.c:15: [1] (buffer) strcpy: + Does not check for buffer overflows when copying to destination [MS-banned] + (CWE-120). + Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy 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 (CWE-120). Use + sprintf_s, 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 (CWE-120). Check + that the limit is sufficiently small, or use a different input function. +
          + scanf("%10s", s);
          +
          +
        • test.c:57: [1] (buffer) strncpy: + Easily used incorrectly; doesn't always \0-terminate or check for invalid + pointers [MS-banned] (CWE-120). +
          +  strncpy(d,s);
          +
          +
        • test.c:58: [1] (buffer) _tcsncpy: + Easily used incorrectly; doesn't always \0-terminate or check for invalid + pointers [MS-banned] (CWE-120). +
          +  _tcsncpy(d,s);
          +
          +
        • test.c:59: [1] (buffer) strncat: + Easily used incorrectly (e.g., incorrectly computing the correct maximum + size to add) [MS-banned] (CWE-120). + Consider strcat_s, strlcat, snprintf, or automatically resizing strings. +
          +  strncat(d,s,10);
          +
          +
        • test.c:62: [1] (buffer) strlen: + Does not handle strings that are not \0-terminated; if given one it may + perform an over-read (it could cause a crash if unprotected) (CWE-126). +
          +  n = strlen(d);
          +
          +
        • test.c:68: [1] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes (CWE-120). 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:70: [1] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes (CWE-120). 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]));
          +
          +
        +

        Analysis Summary

        +

        +Hits = 38 +
        +Lines analyzed = 122 +
        +Physical Source Lines of Code (SLOC) = 84 +
        +Hits@level = [0] 16 [1] 9 [2] 9 [3] 3 [4] 10 [5] 7
        +Hits@level+ = [0+] 54 [1+] 38 [2+] 29 [3+] 20 [4+] 17 [5+] 7
        +Hits/KSLOC@level+ = [0+] 642.857 [1+] 452.381 [2+] 345.238 [3+] 238.095 [4+] 202.381 [5+] 83.3333
        +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! +
        +See 'Secure Programming HOWTO' +(https://dwheeler.com/secure-programs) for more information. + + diff --git a/test-results.txt b/test-results.txt new file mode 100755 index 0000000..fd1d4b3 --- /dev/null +++ b/test-results.txt @@ -0,0 +1,163 @@ +Flawfinder version 2.0.10, (C) 2001-2019 David A. Wheeler. +Number of rules (primarily dangerous function names) in C/C++ ruleset: 223 +Examining test.c +Examining test2.c + +FINAL RESULTS: + +test.c:32: [5] (buffer) gets: + Does not check for buffer overflows (CWE-120, CWE-20). Use fgets() instead. +test.c:60: [5] (buffer) strncat: + Easily used incorrectly (e.g., incorrectly computing the correct maximum + size to add) [MS-banned] (CWE-120). Consider strcat_s, strlcat, snprintf, + 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:61: [5] (buffer) _tcsncat: + Easily used incorrectly (e.g., incorrectly computing the correct maximum + size to add) [MS-banned] (CWE-120). Consider strcat_s, 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:64: [5] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is high, + it appears that the size is given as bytes, but the function requires size + as characters. +test.c:66: [5] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is high, + it appears that the size is given as bytes, but the function requires size + as characters. +test.c:77: [5] (misc) SetSecurityDescriptorDacl: + Never create NULL ACLs; an attacker can set it to Everyone (Deny All + Access), which would even forbid administrator access (CWE-732). +test.c:77: [5] (misc) SetSecurityDescriptorDacl: + Never create NULL ACLs; an attacker can set it to Everyone (Deny All + Access), which would even forbid administrator access (CWE-732). +test.c:17: [4] (buffer) strcpy: + Does not check for buffer overflows when copying to destination [MS-banned] + (CWE-120). Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy + easily misused). +test.c:20: [4] (buffer) sprintf: + Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or + vsnprintf. +test.c:21: [4] (buffer) sprintf: + Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or + vsnprintf. +test.c:22: [4] (format) sprintf: + Potential format string problem (CWE-134). Make format string constant. +test.c:23: [4] (format) printf: + If format strings can be influenced by an attacker, they can be exploited + (CWE-134). 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 (CWE-120, CWE-20). 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 (CWE-120, CWE-20). 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 (CWE-134). Use a constant format string for syslog. +test.c:49: [4] (buffer) _mbscpy: + Does not check for buffer overflows when copying to destination [MS-banned] + (CWE-120). Consider using a function version that stops copying at the end + of the buffer. +test.c:56: [4] (buffer) lstrcat: + Does not check for buffer overflows when concatenating to destination + [MS-banned] (CWE-120). +test.c:79: [3] (shell) CreateProcess: + This causes a new process to execute and is difficult to use safely + (CWE-78). 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:79: [3] (shell) CreateProcess: + This causes a new process to execute and is difficult to use safely + (CWE-78). 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:95: [3] (buffer) getopt_long: + Some older implementations do not protect against internal buffer overflows + (CWE-120, CWE-20). 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 [MS-banned] + (CWE-120). Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy + easily misused). Risk is low because the source is a constant string. +test.c:19: [2] (buffer) sprintf: + Does not check for buffer overflows (CWE-120). Use sprintf_s, 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 improperly restricted, leading to potential + overflows or other issues (CWE-119!/CWE-120). 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 improperly restricted, leading to potential + overflows or other issues (CWE-119!/CWE-120). 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 (CWE-120). + Make sure destination can always hold the source data. +test.c:53: [2] (buffer) memcpy: + Does not check for buffer overflows when copying to destination (CWE-120). + Make sure destination can always hold the source data. +test.c:54: [2] (buffer) memcpy: + Does not check for buffer overflows when copying to destination (CWE-120). + Make sure destination can always hold the source data. +test.c:55: [2] (buffer) CopyMemory: + Does not check for buffer overflows when copying to destination (CWE-120). + Make sure destination can always hold the source data. +test.c:101: [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? (CWE-362). +test.c:15: [1] (buffer) strcpy: + Does not check for buffer overflows when copying to destination [MS-banned] + (CWE-120). Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy + easily misused). Risk is low because the source is a constant character. +test.c:18: [1] (buffer) sprintf: + Does not check for buffer overflows (CWE-120). Use sprintf_s, 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 + (CWE-120). Check that the limit is sufficiently small, or use a different + input function. +test.c:57: [1] (buffer) strncpy: + Easily used incorrectly; doesn't always \0-terminate or check for invalid + pointers [MS-banned] (CWE-120). +test.c:58: [1] (buffer) _tcsncpy: + Easily used incorrectly; doesn't always \0-terminate or check for invalid + pointers [MS-banned] (CWE-120). +test.c:59: [1] (buffer) strncat: + Easily used incorrectly (e.g., incorrectly computing the correct maximum + size to add) [MS-banned] (CWE-120). Consider strcat_s, strlcat, snprintf, + or automatically resizing strings. +test.c:62: [1] (buffer) strlen: + Does not handle strings that are not \0-terminated; if given one it may + perform an over-read (it could cause a crash if unprotected) (CWE-126). +test.c:68: [1] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is very + low, the length appears to be in characters not bytes. +test.c:70: [1] (buffer) MultiByteToWideChar: + Requires maximum length in CHARACTERS, not bytes (CWE-120). Risk is very + low, the length appears to be in characters not bytes. + +ANALYSIS SUMMARY: + +Hits = 38 +Lines analyzed = 122 +Physical Source Lines of Code (SLOC) = 84 +Hits@level = [0] 16 [1] 9 [2] 9 [3] 3 [4] 10 [5] 7 +Hits@level+ = [0+] 54 [1+] 38 [2+] 29 [3+] 20 [4+] 17 [5+] 7 +Hits/KSLOC@level+ = [0+] 642.857 [1+] 452.381 [2+] 345.238 [3+] 238.095 [4+] 202.381 [5+] 83.3333 +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! +See 'Secure Programming HOWTO' +(https://dwheeler.com/secure-programs) for more information. + +Testing for no ending newline: +Lines analyzed = 32 diff --git a/test-saved-hitlist-006.txt b/test-saved-hitlist-006.txt new file mode 100755 index 0000000..2879f68 --- /dev/null +++ b/test-saved-hitlist-006.txt @@ -0,0 +1,2368 @@ +(lp0 +ccopy_reg +_reconstructor +p1 +(c__main__ +Hit +p2 +c__builtin__ +object +p3 +Ntp4 +Rp5 +(dp6 +S'category' +p7 +S'buffer' +p8 +sS'end' +p9 +I692 +sS'name' +p10 +S'gets' +p11 +sS'parameters' +p12 +(lp13 +S'' +p14 +aS'f' +p15 +asS'level' +p16 +I5 +sS'url' +p17 +g14 +sS'column' +p18 +I2 +sS'context_text' +p19 +S' gets(f);' +p20 +sS'hook' +p21 +c__main__ +normal +p22 +sS'warning' +p23 +S'Does not check for buffer overflows (CWE-120, CWE-20)' +p24 +sS'suggestion' +p25 +S'Use fgets() instead' +p26 +sS'input' +p27 +I1 +sS'line' +p28 +I32 +sS'filename' +p29 +S'test.c' +p30 +sS'start' +p31 +I688 +sbag1 +(g2 +g3 +Ntp32 +Rp33 +(dp34 +g7 +g8 +sg9 +I1462 +sg10 +S'strncat' +p35 +sg12 +(lp36 +g14 +aS'd' +p37 +aS's' +p38 +aS'sizeof(d)' +p39 +asg16 +I5 +sg17 +g14 +sg18 +I3 +sg19 +S' strncat(d,s,sizeof(d)); /* Misuse - this should be flagged as riskier. */' +p40 +sS'note' +p41 +S'Risk is high; the length parameter appears to be a constant, instead of computing the number of characters left.' +p42 +sg21 +c__main__ +c_strncat +p43 +sg23 +S'Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120)' +p44 +sg25 +S'Consider strcat_s, strlcat, snprintf, or automatically resizing strings' +p45 +sg28 +I60 +sg29 +g30 +sg31 +I1455 +sbag1 +(g2 +g3 +Ntp46 +Rp47 +(dp48 +g7 +g8 +sg9 +I1539 +sg10 +S'_tcsncat' +p49 +sg12 +(lp50 +g14 +aS'd' +p51 +aS's' +p52 +aS'sizeof(d)' +p53 +asg16 +I5 +sg17 +g14 +sg18 +I3 +sg19 +S' _tcsncat(d,s,sizeof(d)); /* Misuse - flag as riskier */' +p54 +sg41 +g42 +sg21 +g43 +sg23 +g44 +sg25 +S'Consider strcat_s, strlcat, or automatically resizing strings' +p55 +sg28 +I61 +sg29 +g30 +sg31 +I1531 +sbag1 +(g2 +g3 +Ntp56 +Rp57 +(dp58 +g7 +g8 +sg9 +I1680 +sg10 +S'MultiByteToWideChar' +p59 +sg12 +(lp60 +g14 +aS'CP_ACP' +p61 +aS'0' +p62 +aS'szName' +p63 +aS'-1' +p64 +aS'wszUserName' +p65 +aS'sizeof(wszUserName)' +p66 +asg16 +I5 +sg17 +g14 +sg18 +I3 +sg19 +S' MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName));' +p67 +sg41 +S'Risk is high, it appears that the size is given as bytes, but the function requires size as characters.' +p68 +sg21 +c__main__ +c_multi_byte_to_wide_char +p69 +sg23 +S'Requires maximum length in CHARACTERS, not bytes (CWE-120)' +p70 +sg25 +g14 +sg28 +I64 +sg29 +g30 +sg31 +I1661 +sbag1 +(g2 +g3 +Ntp71 +Rp72 +(dp73 +g7 +g8 +sg9 +I1815 +sg10 +S'MultiByteToWideChar' +p74 +sg12 +(lp75 +g14 +aS'CP_ACP' +p76 +aS'0' +p77 +aS'szName' +p78 +aS'-1' +p79 +aS'wszUserName' +p80 +aS'sizeof wszUserName' +p81 +asg16 +I5 +sg17 +g14 +sg18 +I3 +sg19 +S' MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName);' +p82 +sg41 +g68 +sg21 +g69 +sg23 +g70 +sg25 +g14 +sg28 +I66 +sg29 +g30 +sg31 +I1796 +sbag1 +(g2 +g3 +Ntp83 +Rp84 +(dp85 +g7 +S'misc' +p86 +sg9 +I2533 +sg10 +S'SetSecurityDescriptorDacl' +p87 +sg12 +(lp88 +g14 +aS'&sd' +p89 +aS'TRUE' +p90 +aS'NULL' +p91 +aS'FALSE' +p92 +asg16 +I5 +sg17 +g14 +sg18 +I3 +sg31 +I2508 +sg19 +S' SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE);' +p93 +sg21 +c__main__ +c_hit_if_null +p94 +sg23 +S'Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732)' +p95 +sg25 +g14 +sg28 +I77 +sg29 +g30 +sS'check_for_null' +p96 +I3 +sbag84 +ag1 +(g2 +g3 +Ntp97 +Rp98 +(dp99 +g7 +g8 +sg9 +I372 +sg10 +S'strcpy' +p100 +sg12 +(lp101 +g14 +aS'b' +p102 +aS'a' +p103 +asg16 +I4 +sg17 +g14 +sg18 +I2 +sg19 +S' strcpy(b, a);' +p104 +sg21 +c__main__ +c_buffer +p105 +sg23 +S'Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120)' +p106 +sg25 +S'Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused)' +p107 +sg28 +I17 +sg29 +g30 +sg31 +I366 +sbag1 +(g2 +g3 +Ntp108 +Rp109 +(dp110 +g7 +g8 +sg9 +I429 +sg10 +S'sprintf' +p111 +sg12 +(lp112 +g14 +aS's' +p113 +aS'"hello %s"' +p114 +aS'bug' +p115 +asg16 +I4 +sg17 +g14 +sg18 +I2 +sg19 +S' sprintf(s, "hello %s", bug);' +p116 +sg21 +c__main__ +c_sprintf +p117 +sg23 +S'Does not check for buffer overflows (CWE-120)' +p118 +sg25 +S'Use sprintf_s, snprintf, or vsnprintf' +p119 +sg28 +I20 +sg29 +g30 +sg31 +I422 +sbag1 +(g2 +g3 +Ntp120 +Rp121 +(dp122 +g7 +g8 +sg9 +I459 +sg10 +S'sprintf' +p123 +sg12 +(lp124 +g14 +aS's' +p125 +aS'gettext("hello %s")' +p126 +aS'bug' +p127 +asg16 +I4 +sg17 +g14 +sg18 +I2 +sg19 +S' sprintf(s, gettext("hello %s"), bug);' +p128 +sg21 +g117 +sg23 +g118 +sg25 +g119 +sg28 +I21 +sg29 +g30 +sg31 +I452 +sbag1 +(g2 +g3 +Ntp129 +Rp130 +(dp131 +g7 +S'format' +p132 +sg9 +I498 +sg10 +S'sprintf' +p133 +sg12 +(lp134 +g14 +aS's' +p135 +aS'unknown' +p136 +aS'bug' +p137 +asg16 +I4 +sg17 +g14 +sg18 +I2 +sg19 +S' sprintf(s, unknown, bug);' +p138 +sg21 +g117 +sg23 +S'Potential format string problem (CWE-134)' +p139 +sg25 +S'Make format string constant' +p140 +sg28 +I22 +sg29 +g30 +sg31 +I491 +sbag1 +(g2 +g3 +Ntp141 +Rp142 +(dp143 +g7 +g132 +sg9 +I524 +sg10 +S'printf' +p144 +sg12 +(lp145 +g14 +aS'bf' +p146 +aS'x' +p147 +asg16 +I4 +sg17 +g14 +sg18 +I2 +sg19 +S' printf(bf, x);' +p148 +sg21 +c__main__ +c_printf +p149 +sg23 +S'If format strings can be influenced by an attacker, they can be exploited (CWE-134)' +p150 +sg25 +S'Use a constant for the format specification' +p151 +sg28 +I23 +sg29 +g30 +sg31 +I518 +sbag1 +(g2 +g3 +Ntp152 +Rp153 +(dp154 +g7 +g8 +sg9 +I557 +sg10 +S'scanf' +p155 +sg12 +(lp156 +g14 +aS'"%s"' +p157 +aS's' +p158 +asg16 +I4 +sg17 +g14 +sg18 +I2 +sg19 +S' scanf("%s", s);' +p159 +sg21 +c__main__ +c_scanf +p160 +sg23 +S"The scanf() family's %s operation, without a limit specification, permits buffer overflows (CWE-120, CWE-20)" +p161 +sg25 +S'Specify a limit to %s, or use a different input function' +p162 +sg27 +I1 +sg28 +I25 +sg29 +g30 +sg31 +I552 +sbag1 +(g2 +g3 +Ntp163 +Rp164 +(dp165 +g7 +g8 +sg9 +I593 +sg10 +S'scanf' +p166 +sg12 +(lp167 +g14 +aS'"%s"' +p168 +ag158 +asg16 +I4 +sg17 +g14 +sg18 +I2 +sg19 +S' scanf("%s", s);' +p169 +sg21 +g160 +sg23 +g161 +sg25 +g162 +sg27 +I1 +sg28 +I27 +sg29 +g30 +sg31 +I588 +sbag1 +(g2 +g3 +Ntp170 +Rp171 +(dp172 +g7 +g132 +sg9 +I997 +sg10 +S'syslog' +p173 +sg12 +(lp174 +g14 +aS'LOG_ERR' +p175 +aS'attacker_string' +p176 +asg16 +I4 +sg17 +g14 +sg18 +I2 +sg19 +S' syslog(LOG_ERR, attacker_string);' +p177 +sg21 +g149 +sS'format_position' +p178 +I2 +sg23 +S"If syslog's format strings can be influenced by an attacker, they can be exploited (CWE-134)" +p179 +sg25 +S'Use a constant format string for syslog' +p180 +sg28 +I38 +sg29 +g30 +sg31 +I991 +sbag1 +(g2 +g3 +Ntp181 +Rp182 +(dp183 +g7 +g8 +sg9 +I1088 +sg10 +S'_mbscpy' +p184 +sg12 +(lp185 +g14 +aS'd' +p186 +aS's' +p187 +asg16 +I4 +sg17 +g14 +sg18 +I3 +sg19 +S" _mbscpy(d,s); /* like strcpy, this doesn't check for buffer overflow */" +p188 +sg21 +g105 +sg23 +g106 +sg25 +S'Consider using a function version that stops copying at the end of the buffer' +p189 +sg28 +I49 +sg29 +g30 +sg31 +I1081 +sbag1 +(g2 +g3 +Ntp190 +Rp191 +(dp192 +g7 +g8 +sg9 +I1394 +sg10 +S'lstrcat' +p193 +sg12 +(lp194 +g14 +aS'd' +p195 +aS's' +p196 +asg16 +I4 +sg17 +g14 +sg18 +I3 +sg19 +S' lstrcat(d,s);' +p197 +sg21 +g105 +sg23 +S'Does not check for buffer overflows when concatenating to destination [MS-banned] (CWE-120)' +p198 +sg25 +g14 +sg28 +I56 +sg29 +g30 +sg31 +I1387 +sbag1 +(g2 +g3 +Ntp199 +Rp200 +(dp201 +g7 +S'shell' +p202 +sg9 +I2634 +sg10 +S'CreateProcess' +p203 +sg12 +(lp204 +g14 +aS'NULL' +p205 +aS'"C:\\\\Program Files\\\\GoodGuy\\\\GoodGuy.exe -x"' +p206 +aS'""' +p207 +asg16 +I3 +sg17 +g14 +sg18 +I3 +sg31 +I2621 +sg19 +S' CreateProcess(NULL, "C:\\\\Program Files\\\\GoodGuy\\\\GoodGuy.exe -x", "");' +p208 +sg21 +g94 +sg23 +S'This causes a new process to execute and is difficult to use safely (CWE-78)' +p209 +sg25 +S'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' +p210 +sg28 +I79 +sg29 +g30 +sg96 +I1 +sbag200 +ag1 +(g2 +g3 +Ntp211 +Rp212 +(dp213 +g7 +g8 +sg9 +I3057 +sg10 +S'getopt_long' +p214 +sg12 +(lp215 +g14 +aS'argc' +p216 +aS'argv' +p217 +aS'"a"' +p218 +aS'longopts' +p219 +aS'NULL' +p220 +asg16 +I3 +sg17 +S'dangers-c' +p221 +sg18 +I20 +sg19 +S' while ((optc = getopt_long (argc, argv, "a",longopts, NULL )) != EOF) {' +p222 +sg21 +g22 +sg23 +S'Some older implementations do not protect against internal buffer overflows (CWE-120, CWE-20)' +p223 +sg25 +S'Check implementation on installation, or limit the size of all string inputs' +p224 +sg27 +I1 +sg28 +I95 +sg29 +g30 +sg31 +I3046 +sbag1 +(g2 +g3 +Ntp225 +Rp226 +(dp227 +g7 +g8 +sg9 +I318 +sg10 +S'strcpy' +p228 +sg12 +(lp229 +g14 +aS'a' +p230 +aS'gettext("Hello there")' +p231 +asg16 +I2 +sg17 +g14 +sg18 +I2 +sg19 +S' strcpy(a, gettext("Hello there")); // Did this work?' +p232 +sg41 +S'Risk is low because the source is a constant string.' +p233 +sg21 +g105 +sg23 +g106 +sg25 +g107 +sg28 +I16 +sg29 +g30 +sg31 +I312 +sbag1 +(g2 +g3 +Ntp234 +Rp235 +(dp236 +g7 +g8 +sg9 +I407 +sg10 +S'sprintf' +p237 +sg12 +(lp238 +g14 +aS's' +p239 +aS'"hello"' +p240 +asg16 +I2 +sg17 +g14 +sg18 +I2 +sg19 +S' sprintf(s, "hello");' +p241 +sg41 +S'Risk is low because the source has a constant maximum length.' +p242 +sg21 +g117 +sg23 +g118 +sg25 +g119 +sg28 +I19 +sg29 +g30 +sg31 +I400 +sbag1 +(g2 +g3 +Ntp243 +Rp244 +(dp245 +g7 +g8 +sg29 +g30 +sg9 +I1047 +sg10 +S'char' +p246 +sg12 +(lp247 +sg16 +I2 +sg17 +g14 +sS'lookahead' +p248 +S"char d[20];\n char s[20];\n int n;\n\n _mbscpy(d,s); /* like strcpy, this doesn't check for buffer overflow */\n memcpy(d,s); // fail - no size\n memcpy(d, s, sizeof(d)); // pass\n memcpy(& n, s, sizeof( n )); // pass\n memcpy(&n,s,sizeof(s)); // fail - sizeof not of destination\n memcpy(d,s,n); // fail - size unguessable\n CopyMemory(d,s);\n lstrcat(d,s);\n strncpy(d,s);\n _tcsncpy(d,s);\n strncat(d,s,10);\n strncat(d,s,sizeof(d)); /* Misuse - this should be flagged as riskier. */\n _tcsncat(d,s" +p249 +sg18 +I3 +sg19 +S' char d[20];' +p250 +sg21 +c__main__ +c_static_array +p251 +sg23 +S'Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120)' +p252 +sg25 +S'Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length' +p253 +sg28 +I45 +sS'extract_lookahead' +p254 +I1 +sg31 +I1043 +sbag1 +(g2 +g3 +Ntp255 +Rp256 +(dp257 +g7 +g8 +sg29 +g30 +sg9 +I1061 +sg10 +S'char' +p258 +sg12 +(lp259 +sg16 +I2 +sg17 +g14 +sg248 +S"char s[20];\n int n;\n\n _mbscpy(d,s); /* like strcpy, this doesn't check for buffer overflow */\n memcpy(d,s); // fail - no size\n memcpy(d, s, sizeof(d)); // pass\n memcpy(& n, s, sizeof( n )); // pass\n memcpy(&n,s,sizeof(s)); // fail - sizeof not of destination\n memcpy(d,s,n); // fail - size unguessable\n CopyMemory(d,s);\n lstrcat(d,s);\n strncpy(d,s);\n _tcsncpy(d,s);\n strncat(d,s,10);\n strncat(d,s,sizeof(d)); /* Misuse - this should be flagged as riskier. */\n _tcsncat(d,s,sizeof(d)); /" +p260 +sg18 +I3 +sg19 +S' char s[20];' +p261 +sg21 +g251 +sg23 +g252 +sg25 +g253 +sg28 +I46 +sg254 +I1 +sg31 +I1057 +sbag1 +(g2 +g3 +Ntp262 +Rp263 +(dp264 +g7 +g8 +sg9 +I1161 +sg10 +S'memcpy' +p265 +sg12 +(lp266 +g14 +aS'd' +p267 +aS's' +p268 +asg16 +I2 +sg17 +g14 +sg18 +I3 +sg19 +S' memcpy(d,s); // fail - no size' +p269 +sg21 +c__main__ +c_memcpy +p270 +sg23 +S'Does not check for buffer overflows when copying to destination (CWE-120)' +p271 +sg25 +S'Make sure destination can always hold the source data' +p272 +sg28 +I50 +sg29 +g30 +sg31 +I1155 +sbag1 +(g2 +g3 +Ntp273 +Rp274 +(dp275 +g7 +g8 +sg9 +I1268 +sg10 +S'memcpy' +p276 +sg12 +(lp277 +g14 +aS'&n' +p278 +aS's' +p279 +aS'sizeof(s)' +p280 +asg16 +I2 +sg17 +g14 +sg18 +I3 +sg19 +S' memcpy(&n,s,sizeof(s)); // fail - sizeof not of destination' +p281 +sg21 +g270 +sg23 +g271 +sg25 +g272 +sg28 +I53 +sg29 +g30 +sg31 +I1262 +sbag1 +(g2 +g3 +Ntp282 +Rp283 +(dp284 +g7 +g8 +sg9 +I1330 +sg10 +S'memcpy' +p285 +sg12 +(lp286 +g14 +aS'd' +p287 +aS's' +p288 +aS'n' +p289 +asg16 +I2 +sg17 +g14 +sg18 +I3 +sg19 +S' memcpy(d,s,n); // fail - size unguessable' +p290 +sg21 +g270 +sg23 +g271 +sg25 +g272 +sg28 +I54 +sg29 +g30 +sg31 +I1324 +sbag1 +(g2 +g3 +Ntp291 +Rp292 +(dp293 +g7 +g8 +sg9 +I1378 +sg10 +S'CopyMemory' +p294 +sg12 +(lp295 +g14 +aS'd' +p296 +aS's' +p297 +asg16 +I2 +sg17 +g14 +sg18 +I3 +sg19 +S' CopyMemory(d,s);' +p298 +sg21 +g270 +sg23 +g271 +sg25 +g272 +sg28 +I55 +sg29 +g30 +sg31 +I1368 +sbag1 +(g2 +g3 +Ntp299 +Rp300 +(dp301 +g7 +g86 +sg9 +I3151 +sg10 +S'fopen' +p302 +sg12 +(lp303 +g14 +aS'"/etc/passwd"' +p304 +aS'"r"' +p305 +asg16 +I2 +sg17 +g14 +sg18 +I7 +sg19 +S' f = fopen("/etc/passwd", "r"); ' +p306 +sg21 +g22 +sg23 +S'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? (CWE-362)' +p307 +sg25 +g14 +sg28 +I101 +sg29 +g30 +sg31 +I3146 +sbag1 +(g2 +g3 +Ntp308 +Rp309 +(dp310 +g7 +g8 +sg9 +I282 +sg10 +S'strcpy' +p311 +sg12 +(lp312 +g14 +aS'a' +p313 +aS'"\\n"' +p314 +asg16 +I1 +sg17 +g14 +sg18 +I2 +sg19 +S' strcpy(a, "\\n"); // Did this work?' +p315 +sg41 +S'Risk is low because the source is a constant character.' +p316 +sg21 +g105 +sg23 +g106 +sg25 +g107 +sg28 +I15 +sg29 +g30 +sg31 +I276 +sbag1 +(g2 +g3 +Ntp317 +Rp318 +(dp319 +g7 +g8 +sg9 +I388 +sg10 +S'sprintf' +p320 +sg12 +(lp321 +g14 +aS's' +p322 +aS'"\\n"' +p323 +asg16 +I1 +sg17 +g14 +sg18 +I2 +sg19 +S' sprintf(s, "\\n");' +p324 +sg41 +S'Risk is low because the source is a constant character.' +p325 +sg21 +g117 +sg23 +g118 +sg25 +g119 +sg28 +I18 +sg29 +g30 +sg31 +I381 +sbag1 +(g2 +g3 +Ntp326 +Rp327 +(dp328 +g7 +g8 +sg9 +I574 +sg10 +S'scanf' +p329 +sg12 +(lp330 +g14 +aS'"%10s"' +p331 +ag158 +asg16 +I1 +sg17 +g14 +sg18 +I2 +sg19 +S' scanf("%10s", s);' +p332 +sg21 +g160 +sg23 +S"It's unclear if the %s limit in the format string is small enough (CWE-120)" +p333 +sg25 +S'Check that the limit is sufficiently small, or use a different input function' +p334 +sg27 +I1 +sg28 +I26 +sg29 +g30 +sg31 +I569 +sbag1 +(g2 +g3 +Ntp335 +Rp336 +(dp337 +g7 +g8 +sg9 +I1410 +sg10 +S'strncpy' +p338 +sg12 +(lp339 +g14 +aS'd' +p340 +aS's' +p341 +asg16 +I1 +sg17 +g14 +sg18 +I3 +sg19 +S' strncpy(d,s);' +p342 +sg21 +g105 +sg23 +S"Easily used incorrectly; doesn't always \\0-terminate or check for invalid pointers [MS-banned] (CWE-120)" +p343 +sg25 +g14 +sg28 +I57 +sg29 +g30 +sg31 +I1403 +sbag1 +(g2 +g3 +Ntp344 +Rp345 +(dp346 +g7 +g8 +sg9 +I1427 +sg10 +S'_tcsncpy' +p347 +sg12 +(lp348 +g14 +aS'd' +p349 +aS's' +p350 +asg16 +I1 +sg17 +g14 +sg18 +I3 +sg19 +S' _tcsncpy(d,s);' +p351 +sg21 +g105 +sg23 +g343 +sg25 +g14 +sg28 +I58 +sg29 +g30 +sg31 +I1419 +sbag1 +(g2 +g3 +Ntp352 +Rp353 +(dp354 +g7 +g8 +sg9 +I1443 +sg10 +S'strncat' +p355 +sg12 +(lp356 +g14 +aS'd' +p357 +aS's' +p358 +aS'10' +p359 +asg16 +I1 +sg17 +g14 +sg18 +I3 +sg19 +S' strncat(d,s,10);' +p360 +sg21 +g43 +sg23 +g44 +sg25 +g45 +sg28 +I59 +sg29 +g30 +sg31 +I1436 +sbag1 +(g2 +g3 +Ntp361 +Rp362 +(dp363 +g7 +g8 +sg9 +I1599 +sg10 +S'strlen' +p364 +sg12 +(lp365 +g14 +aS'd' +p366 +asg16 +I1 +sg17 +g14 +sg18 +I7 +sg19 +S' n = strlen(d);' +p367 +sg21 +g22 +sg23 +S'Does not handle strings that are not \\0-terminated; if given one it may perform an over-read (it could cause a crash if unprotected) (CWE-126)' +p368 +sg25 +g14 +sg28 +I62 +sg29 +g30 +sg31 +I1593 +sbag1 +(g2 +g3 +Ntp369 +Rp370 +(dp371 +g7 +g8 +sg9 +I1918 +sg10 +S'MultiByteToWideChar' +p372 +sg12 +(lp373 +g14 +aS'CP_ACP' +p374 +aS'0' +p375 +aS'szName' +p376 +aS'-1' +p377 +aS'wszUserName' +p378 +aS'sizeof(wszUserName)/sizeof(wszUserName[0])' +p379 +asg16 +I1 +sg17 +g14 +sg18 +I3 +sg19 +S' MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName)/sizeof(wszUserName[0]));' +p380 +sg41 +S'Risk is very low, the length appears to be in characters not bytes.' +p381 +sg21 +g69 +sg23 +g70 +sg25 +g14 +sg28 +I68 +sg29 +g30 +sg31 +I1899 +sbag1 +(g2 +g3 +Ntp382 +Rp383 +(dp384 +g7 +g8 +sg9 +I2045 +sg10 +S'MultiByteToWideChar' +p385 +sg12 +(lp386 +g14 +aS'CP_ACP' +p387 +aS'0' +p388 +aS'szName' +p389 +aS'-1' +p390 +aS'wszUserName' +p391 +aS'sizeof wszUserName /sizeof(wszUserName[0])' +p392 +asg16 +I1 +sg17 +g14 +sg18 +I3 +sg19 +S' MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName /sizeof(wszUserName[0]));' +p393 +sg41 +g381 +sg21 +g69 +sg23 +g70 +sg25 +g14 +sg28 +I70 +sg29 +g30 +sg31 +I2026 +sbag1 +(g2 +g3 +Ntp394 +Rp395 +(dp396 +g7 +g132 +sg9 +I200 +sg10 +S'printf' +p397 +sg12 +(lp398 +g14 +aS'"hello\\n"' +p399 +asg16 +I0 +sg17 +g14 +sg18 +I2 +sg19 +S' printf("hello\\n");' +p400 +sg41 +S'Constant format string, so not considered risky.' +p401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I9 +sg29 +g30 +sg31 +I194 +sbag1 +(g2 +g3 +Ntp402 +Rp403 +(dp404 +g7 +g8 +sg9 +I539 +sg10 +S'scanf' +p405 +sg12 +(lp406 +g14 +aS'"%d"' +p407 +aS'&x' +p408 +asg16 +I0 +sg17 +g14 +sg18 +I2 +sg19 +S' scanf("%d", &x);' +p409 +sg41 +S'No risky scanf format detected.' +p410 +sg21 +g160 +sg23 +g161 +sg25 +g162 +sg27 +I1 +sg28 +I24 +sg29 +g30 +sg31 +I534 +sbag1 +(g2 +g3 +Ntp411 +Rp412 +(dp413 +g7 +g132 +sg9 +I643 +sg10 +S'printf' +p414 +sg12 +(lp415 +g14 +aS'"\\\\"' +p416 +asg16 +I0 +sg17 +g14 +sg18 +I2 +sg19 +S' printf("\\\\");' +p417 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I29 +sg29 +g30 +sg31 +I637 +sbag1 +(g2 +g3 +Ntp418 +Rp419 +(dp420 +g7 +g132 +sg9 +I837 +sg10 +S'syslog' +p421 +sg12 +(lp422 +g14 +aS'LOG_ERR' +p423 +aS'"cannot open config file (%s): %s"' +p424 +aS'filename' +p425 +aS'strerror(errno)' +p426 +asg16 +I0 +sg17 +g14 +sg18 +I2 +sg19 +S' syslog(LOG_ERR,"cannot open config file (%s): %s",filename,strerror(errno))' +p427 +sg41 +g401 +sg21 +g149 +sg178 +I2 +sg23 +g179 +sg25 +g180 +sg28 +I35 +sg29 +g30 +sg31 +I831 +sbag1 +(g2 +g3 +Ntp428 +Rp429 +(dp430 +g7 +g132 +sg9 +I914 +sg10 +S'syslog' +p431 +sg12 +(lp432 +g14 +aS'LOG_CRIT' +p433 +aS'"malloc() failed"' +p434 +asg16 +I0 +sg17 +g14 +sg18 +I2 +sg19 +S' syslog(LOG_CRIT,"malloc() failed");' +p435 +sg41 +g401 +sg21 +g149 +sg178 +I2 +sg23 +g179 +sg25 +g180 +sg28 +I36 +sg29 +g30 +sg31 +I908 +sbag1 +(g2 +g3 +Ntp436 +Rp437 +(dp438 +g7 +g132 +sg9 +I2745 +sg10 +S'printf' +p439 +sg12 +(lp440 +g14 +aS'"%c\\n"' +p441 +aS"'x'" +p442 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", \'x\');' +p443 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I81 +sg29 +g30 +sg31 +I2739 +sbag1 +(g2 +g3 +Ntp444 +Rp445 +(dp446 +g7 +g132 +sg9 +I2768 +sg10 +S'printf' +p447 +sg12 +(lp448 +g14 +aS'"%c\\n"' +p449 +aS'\'"\'' +p450 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", \'"\');' +p451 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I82 +sg29 +g30 +sg31 +I2762 +sbag1 +(g2 +g3 +Ntp452 +Rp453 +(dp454 +g7 +g132 +sg9 +I2791 +sg10 +S'printf' +p455 +sg12 +(lp456 +g14 +aS'"%c\\n"' +p457 +aS'\'\\"\'' +p458 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", \'\\"\');' +p459 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I83 +sg29 +g30 +sg31 +I2785 +sbag1 +(g2 +g3 +Ntp460 +Rp461 +(dp462 +g7 +g132 +sg9 +I2815 +sg10 +S'printf' +p463 +sg12 +(lp464 +g14 +aS'"%c\\n"' +p465 +aS"'\\''" +p466 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", \'\\\'\');' +p467 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I84 +sg29 +g30 +sg31 +I2809 +sbag1 +(g2 +g3 +Ntp468 +Rp469 +(dp470 +g7 +g132 +sg9 +I2839 +sg10 +S'printf' +p471 +sg12 +(lp472 +g14 +aS'"%c\\n"' +p473 +aS"'\\177'" +p474 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", \'\\177\');' +p475 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I85 +sg29 +g30 +sg31 +I2833 +sbag1 +(g2 +g3 +Ntp476 +Rp477 +(dp478 +g7 +g132 +sg9 +I2865 +sg10 +S'printf' +p479 +sg12 +(lp480 +g14 +aS'"%c\\n"' +p481 +aS"'\\xfe'" +p482 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", \'\\xfe\');' +p483 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I86 +sg29 +g30 +sg31 +I2859 +sbag1 +(g2 +g3 +Ntp484 +Rp485 +(dp486 +g7 +g132 +sg9 +I2891 +sg10 +S'printf' +p487 +sg12 +(lp488 +g14 +aS'"%c\\n"' +p489 +aS"'\\xd'" +p490 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", \'\\xd\');' +p491 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I87 +sg29 +g30 +sg31 +I2885 +sbag1 +(g2 +g3 +Ntp492 +Rp493 +(dp494 +g7 +g132 +sg9 +I2916 +sg10 +S'printf' +p495 +sg12 +(lp496 +g14 +aS'"%c\\n"' +p497 +aS"'\\n'" +p498 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", \'\\n\');' +p499 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I88 +sg29 +g30 +sg31 +I2910 +sbag1 +(g2 +g3 +Ntp500 +Rp501 +(dp502 +g7 +g132 +sg9 +I2940 +sg10 +S'printf' +p503 +sg12 +(lp504 +g14 +aS'"%c\\n"' +p505 +aS"'\\\\'" +p506 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", \'\\\\\');' +p507 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I89 +sg29 +g30 +sg31 +I2934 +sbag1 +(g2 +g3 +Ntp508 +Rp509 +(dp510 +g7 +g132 +sg9 +I2964 +sg10 +S'printf' +p511 +sg12 +(lp512 +g14 +aS'"%c\\n"' +p513 +aS'"\'"' +p514 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", "\'");' +p515 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I90 +sg29 +g30 +sg31 +I2958 +sbag1 +(g2 +g3 +Ntp516 +Rp517 +(dp518 +g7 +g132 +sg9 +I3289 +sg10 +S'fprintf' +p519 +sg12 +(lp520 +g14 +aS'stderr' +p521 +aS'"Assertion failed.\\n"\\\n "File: %s\\nLine: %d\\n"\\\n "Assertion: %s\\n\\n"' +p522 +aS'__FILE__' +p523 +aS'__LINE__' +p524 +aS'#x' +p525 +asg16 +I0 +sg17 +g14 +sg18 +I2 +sg19 +S' fprintf(stderr,"Assertion failed.\\n"\\' +p526 +sg41 +g401 +sg21 +g149 +sg178 +I2 +sg23 +g150 +sg25 +g151 +sg28 +I109 +sg29 +g30 +sg31 +I3282 +sba. \ No newline at end of file diff --git a/test-saved-hitlist-008.txt b/test-saved-hitlist-008.txt new file mode 100644 index 0000000..2879f68 --- /dev/null +++ b/test-saved-hitlist-008.txt @@ -0,0 +1,2368 @@ +(lp0 +ccopy_reg +_reconstructor +p1 +(c__main__ +Hit +p2 +c__builtin__ +object +p3 +Ntp4 +Rp5 +(dp6 +S'category' +p7 +S'buffer' +p8 +sS'end' +p9 +I692 +sS'name' +p10 +S'gets' +p11 +sS'parameters' +p12 +(lp13 +S'' +p14 +aS'f' +p15 +asS'level' +p16 +I5 +sS'url' +p17 +g14 +sS'column' +p18 +I2 +sS'context_text' +p19 +S' gets(f);' +p20 +sS'hook' +p21 +c__main__ +normal +p22 +sS'warning' +p23 +S'Does not check for buffer overflows (CWE-120, CWE-20)' +p24 +sS'suggestion' +p25 +S'Use fgets() instead' +p26 +sS'input' +p27 +I1 +sS'line' +p28 +I32 +sS'filename' +p29 +S'test.c' +p30 +sS'start' +p31 +I688 +sbag1 +(g2 +g3 +Ntp32 +Rp33 +(dp34 +g7 +g8 +sg9 +I1462 +sg10 +S'strncat' +p35 +sg12 +(lp36 +g14 +aS'd' +p37 +aS's' +p38 +aS'sizeof(d)' +p39 +asg16 +I5 +sg17 +g14 +sg18 +I3 +sg19 +S' strncat(d,s,sizeof(d)); /* Misuse - this should be flagged as riskier. */' +p40 +sS'note' +p41 +S'Risk is high; the length parameter appears to be a constant, instead of computing the number of characters left.' +p42 +sg21 +c__main__ +c_strncat +p43 +sg23 +S'Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120)' +p44 +sg25 +S'Consider strcat_s, strlcat, snprintf, or automatically resizing strings' +p45 +sg28 +I60 +sg29 +g30 +sg31 +I1455 +sbag1 +(g2 +g3 +Ntp46 +Rp47 +(dp48 +g7 +g8 +sg9 +I1539 +sg10 +S'_tcsncat' +p49 +sg12 +(lp50 +g14 +aS'd' +p51 +aS's' +p52 +aS'sizeof(d)' +p53 +asg16 +I5 +sg17 +g14 +sg18 +I3 +sg19 +S' _tcsncat(d,s,sizeof(d)); /* Misuse - flag as riskier */' +p54 +sg41 +g42 +sg21 +g43 +sg23 +g44 +sg25 +S'Consider strcat_s, strlcat, or automatically resizing strings' +p55 +sg28 +I61 +sg29 +g30 +sg31 +I1531 +sbag1 +(g2 +g3 +Ntp56 +Rp57 +(dp58 +g7 +g8 +sg9 +I1680 +sg10 +S'MultiByteToWideChar' +p59 +sg12 +(lp60 +g14 +aS'CP_ACP' +p61 +aS'0' +p62 +aS'szName' +p63 +aS'-1' +p64 +aS'wszUserName' +p65 +aS'sizeof(wszUserName)' +p66 +asg16 +I5 +sg17 +g14 +sg18 +I3 +sg19 +S' MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName));' +p67 +sg41 +S'Risk is high, it appears that the size is given as bytes, but the function requires size as characters.' +p68 +sg21 +c__main__ +c_multi_byte_to_wide_char +p69 +sg23 +S'Requires maximum length in CHARACTERS, not bytes (CWE-120)' +p70 +sg25 +g14 +sg28 +I64 +sg29 +g30 +sg31 +I1661 +sbag1 +(g2 +g3 +Ntp71 +Rp72 +(dp73 +g7 +g8 +sg9 +I1815 +sg10 +S'MultiByteToWideChar' +p74 +sg12 +(lp75 +g14 +aS'CP_ACP' +p76 +aS'0' +p77 +aS'szName' +p78 +aS'-1' +p79 +aS'wszUserName' +p80 +aS'sizeof wszUserName' +p81 +asg16 +I5 +sg17 +g14 +sg18 +I3 +sg19 +S' MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName);' +p82 +sg41 +g68 +sg21 +g69 +sg23 +g70 +sg25 +g14 +sg28 +I66 +sg29 +g30 +sg31 +I1796 +sbag1 +(g2 +g3 +Ntp83 +Rp84 +(dp85 +g7 +S'misc' +p86 +sg9 +I2533 +sg10 +S'SetSecurityDescriptorDacl' +p87 +sg12 +(lp88 +g14 +aS'&sd' +p89 +aS'TRUE' +p90 +aS'NULL' +p91 +aS'FALSE' +p92 +asg16 +I5 +sg17 +g14 +sg18 +I3 +sg31 +I2508 +sg19 +S' SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE);' +p93 +sg21 +c__main__ +c_hit_if_null +p94 +sg23 +S'Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732)' +p95 +sg25 +g14 +sg28 +I77 +sg29 +g30 +sS'check_for_null' +p96 +I3 +sbag84 +ag1 +(g2 +g3 +Ntp97 +Rp98 +(dp99 +g7 +g8 +sg9 +I372 +sg10 +S'strcpy' +p100 +sg12 +(lp101 +g14 +aS'b' +p102 +aS'a' +p103 +asg16 +I4 +sg17 +g14 +sg18 +I2 +sg19 +S' strcpy(b, a);' +p104 +sg21 +c__main__ +c_buffer +p105 +sg23 +S'Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120)' +p106 +sg25 +S'Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused)' +p107 +sg28 +I17 +sg29 +g30 +sg31 +I366 +sbag1 +(g2 +g3 +Ntp108 +Rp109 +(dp110 +g7 +g8 +sg9 +I429 +sg10 +S'sprintf' +p111 +sg12 +(lp112 +g14 +aS's' +p113 +aS'"hello %s"' +p114 +aS'bug' +p115 +asg16 +I4 +sg17 +g14 +sg18 +I2 +sg19 +S' sprintf(s, "hello %s", bug);' +p116 +sg21 +c__main__ +c_sprintf +p117 +sg23 +S'Does not check for buffer overflows (CWE-120)' +p118 +sg25 +S'Use sprintf_s, snprintf, or vsnprintf' +p119 +sg28 +I20 +sg29 +g30 +sg31 +I422 +sbag1 +(g2 +g3 +Ntp120 +Rp121 +(dp122 +g7 +g8 +sg9 +I459 +sg10 +S'sprintf' +p123 +sg12 +(lp124 +g14 +aS's' +p125 +aS'gettext("hello %s")' +p126 +aS'bug' +p127 +asg16 +I4 +sg17 +g14 +sg18 +I2 +sg19 +S' sprintf(s, gettext("hello %s"), bug);' +p128 +sg21 +g117 +sg23 +g118 +sg25 +g119 +sg28 +I21 +sg29 +g30 +sg31 +I452 +sbag1 +(g2 +g3 +Ntp129 +Rp130 +(dp131 +g7 +S'format' +p132 +sg9 +I498 +sg10 +S'sprintf' +p133 +sg12 +(lp134 +g14 +aS's' +p135 +aS'unknown' +p136 +aS'bug' +p137 +asg16 +I4 +sg17 +g14 +sg18 +I2 +sg19 +S' sprintf(s, unknown, bug);' +p138 +sg21 +g117 +sg23 +S'Potential format string problem (CWE-134)' +p139 +sg25 +S'Make format string constant' +p140 +sg28 +I22 +sg29 +g30 +sg31 +I491 +sbag1 +(g2 +g3 +Ntp141 +Rp142 +(dp143 +g7 +g132 +sg9 +I524 +sg10 +S'printf' +p144 +sg12 +(lp145 +g14 +aS'bf' +p146 +aS'x' +p147 +asg16 +I4 +sg17 +g14 +sg18 +I2 +sg19 +S' printf(bf, x);' +p148 +sg21 +c__main__ +c_printf +p149 +sg23 +S'If format strings can be influenced by an attacker, they can be exploited (CWE-134)' +p150 +sg25 +S'Use a constant for the format specification' +p151 +sg28 +I23 +sg29 +g30 +sg31 +I518 +sbag1 +(g2 +g3 +Ntp152 +Rp153 +(dp154 +g7 +g8 +sg9 +I557 +sg10 +S'scanf' +p155 +sg12 +(lp156 +g14 +aS'"%s"' +p157 +aS's' +p158 +asg16 +I4 +sg17 +g14 +sg18 +I2 +sg19 +S' scanf("%s", s);' +p159 +sg21 +c__main__ +c_scanf +p160 +sg23 +S"The scanf() family's %s operation, without a limit specification, permits buffer overflows (CWE-120, CWE-20)" +p161 +sg25 +S'Specify a limit to %s, or use a different input function' +p162 +sg27 +I1 +sg28 +I25 +sg29 +g30 +sg31 +I552 +sbag1 +(g2 +g3 +Ntp163 +Rp164 +(dp165 +g7 +g8 +sg9 +I593 +sg10 +S'scanf' +p166 +sg12 +(lp167 +g14 +aS'"%s"' +p168 +ag158 +asg16 +I4 +sg17 +g14 +sg18 +I2 +sg19 +S' scanf("%s", s);' +p169 +sg21 +g160 +sg23 +g161 +sg25 +g162 +sg27 +I1 +sg28 +I27 +sg29 +g30 +sg31 +I588 +sbag1 +(g2 +g3 +Ntp170 +Rp171 +(dp172 +g7 +g132 +sg9 +I997 +sg10 +S'syslog' +p173 +sg12 +(lp174 +g14 +aS'LOG_ERR' +p175 +aS'attacker_string' +p176 +asg16 +I4 +sg17 +g14 +sg18 +I2 +sg19 +S' syslog(LOG_ERR, attacker_string);' +p177 +sg21 +g149 +sS'format_position' +p178 +I2 +sg23 +S"If syslog's format strings can be influenced by an attacker, they can be exploited (CWE-134)" +p179 +sg25 +S'Use a constant format string for syslog' +p180 +sg28 +I38 +sg29 +g30 +sg31 +I991 +sbag1 +(g2 +g3 +Ntp181 +Rp182 +(dp183 +g7 +g8 +sg9 +I1088 +sg10 +S'_mbscpy' +p184 +sg12 +(lp185 +g14 +aS'd' +p186 +aS's' +p187 +asg16 +I4 +sg17 +g14 +sg18 +I3 +sg19 +S" _mbscpy(d,s); /* like strcpy, this doesn't check for buffer overflow */" +p188 +sg21 +g105 +sg23 +g106 +sg25 +S'Consider using a function version that stops copying at the end of the buffer' +p189 +sg28 +I49 +sg29 +g30 +sg31 +I1081 +sbag1 +(g2 +g3 +Ntp190 +Rp191 +(dp192 +g7 +g8 +sg9 +I1394 +sg10 +S'lstrcat' +p193 +sg12 +(lp194 +g14 +aS'd' +p195 +aS's' +p196 +asg16 +I4 +sg17 +g14 +sg18 +I3 +sg19 +S' lstrcat(d,s);' +p197 +sg21 +g105 +sg23 +S'Does not check for buffer overflows when concatenating to destination [MS-banned] (CWE-120)' +p198 +sg25 +g14 +sg28 +I56 +sg29 +g30 +sg31 +I1387 +sbag1 +(g2 +g3 +Ntp199 +Rp200 +(dp201 +g7 +S'shell' +p202 +sg9 +I2634 +sg10 +S'CreateProcess' +p203 +sg12 +(lp204 +g14 +aS'NULL' +p205 +aS'"C:\\\\Program Files\\\\GoodGuy\\\\GoodGuy.exe -x"' +p206 +aS'""' +p207 +asg16 +I3 +sg17 +g14 +sg18 +I3 +sg31 +I2621 +sg19 +S' CreateProcess(NULL, "C:\\\\Program Files\\\\GoodGuy\\\\GoodGuy.exe -x", "");' +p208 +sg21 +g94 +sg23 +S'This causes a new process to execute and is difficult to use safely (CWE-78)' +p209 +sg25 +S'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' +p210 +sg28 +I79 +sg29 +g30 +sg96 +I1 +sbag200 +ag1 +(g2 +g3 +Ntp211 +Rp212 +(dp213 +g7 +g8 +sg9 +I3057 +sg10 +S'getopt_long' +p214 +sg12 +(lp215 +g14 +aS'argc' +p216 +aS'argv' +p217 +aS'"a"' +p218 +aS'longopts' +p219 +aS'NULL' +p220 +asg16 +I3 +sg17 +S'dangers-c' +p221 +sg18 +I20 +sg19 +S' while ((optc = getopt_long (argc, argv, "a",longopts, NULL )) != EOF) {' +p222 +sg21 +g22 +sg23 +S'Some older implementations do not protect against internal buffer overflows (CWE-120, CWE-20)' +p223 +sg25 +S'Check implementation on installation, or limit the size of all string inputs' +p224 +sg27 +I1 +sg28 +I95 +sg29 +g30 +sg31 +I3046 +sbag1 +(g2 +g3 +Ntp225 +Rp226 +(dp227 +g7 +g8 +sg9 +I318 +sg10 +S'strcpy' +p228 +sg12 +(lp229 +g14 +aS'a' +p230 +aS'gettext("Hello there")' +p231 +asg16 +I2 +sg17 +g14 +sg18 +I2 +sg19 +S' strcpy(a, gettext("Hello there")); // Did this work?' +p232 +sg41 +S'Risk is low because the source is a constant string.' +p233 +sg21 +g105 +sg23 +g106 +sg25 +g107 +sg28 +I16 +sg29 +g30 +sg31 +I312 +sbag1 +(g2 +g3 +Ntp234 +Rp235 +(dp236 +g7 +g8 +sg9 +I407 +sg10 +S'sprintf' +p237 +sg12 +(lp238 +g14 +aS's' +p239 +aS'"hello"' +p240 +asg16 +I2 +sg17 +g14 +sg18 +I2 +sg19 +S' sprintf(s, "hello");' +p241 +sg41 +S'Risk is low because the source has a constant maximum length.' +p242 +sg21 +g117 +sg23 +g118 +sg25 +g119 +sg28 +I19 +sg29 +g30 +sg31 +I400 +sbag1 +(g2 +g3 +Ntp243 +Rp244 +(dp245 +g7 +g8 +sg29 +g30 +sg9 +I1047 +sg10 +S'char' +p246 +sg12 +(lp247 +sg16 +I2 +sg17 +g14 +sS'lookahead' +p248 +S"char d[20];\n char s[20];\n int n;\n\n _mbscpy(d,s); /* like strcpy, this doesn't check for buffer overflow */\n memcpy(d,s); // fail - no size\n memcpy(d, s, sizeof(d)); // pass\n memcpy(& n, s, sizeof( n )); // pass\n memcpy(&n,s,sizeof(s)); // fail - sizeof not of destination\n memcpy(d,s,n); // fail - size unguessable\n CopyMemory(d,s);\n lstrcat(d,s);\n strncpy(d,s);\n _tcsncpy(d,s);\n strncat(d,s,10);\n strncat(d,s,sizeof(d)); /* Misuse - this should be flagged as riskier. */\n _tcsncat(d,s" +p249 +sg18 +I3 +sg19 +S' char d[20];' +p250 +sg21 +c__main__ +c_static_array +p251 +sg23 +S'Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120)' +p252 +sg25 +S'Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length' +p253 +sg28 +I45 +sS'extract_lookahead' +p254 +I1 +sg31 +I1043 +sbag1 +(g2 +g3 +Ntp255 +Rp256 +(dp257 +g7 +g8 +sg29 +g30 +sg9 +I1061 +sg10 +S'char' +p258 +sg12 +(lp259 +sg16 +I2 +sg17 +g14 +sg248 +S"char s[20];\n int n;\n\n _mbscpy(d,s); /* like strcpy, this doesn't check for buffer overflow */\n memcpy(d,s); // fail - no size\n memcpy(d, s, sizeof(d)); // pass\n memcpy(& n, s, sizeof( n )); // pass\n memcpy(&n,s,sizeof(s)); // fail - sizeof not of destination\n memcpy(d,s,n); // fail - size unguessable\n CopyMemory(d,s);\n lstrcat(d,s);\n strncpy(d,s);\n _tcsncpy(d,s);\n strncat(d,s,10);\n strncat(d,s,sizeof(d)); /* Misuse - this should be flagged as riskier. */\n _tcsncat(d,s,sizeof(d)); /" +p260 +sg18 +I3 +sg19 +S' char s[20];' +p261 +sg21 +g251 +sg23 +g252 +sg25 +g253 +sg28 +I46 +sg254 +I1 +sg31 +I1057 +sbag1 +(g2 +g3 +Ntp262 +Rp263 +(dp264 +g7 +g8 +sg9 +I1161 +sg10 +S'memcpy' +p265 +sg12 +(lp266 +g14 +aS'd' +p267 +aS's' +p268 +asg16 +I2 +sg17 +g14 +sg18 +I3 +sg19 +S' memcpy(d,s); // fail - no size' +p269 +sg21 +c__main__ +c_memcpy +p270 +sg23 +S'Does not check for buffer overflows when copying to destination (CWE-120)' +p271 +sg25 +S'Make sure destination can always hold the source data' +p272 +sg28 +I50 +sg29 +g30 +sg31 +I1155 +sbag1 +(g2 +g3 +Ntp273 +Rp274 +(dp275 +g7 +g8 +sg9 +I1268 +sg10 +S'memcpy' +p276 +sg12 +(lp277 +g14 +aS'&n' +p278 +aS's' +p279 +aS'sizeof(s)' +p280 +asg16 +I2 +sg17 +g14 +sg18 +I3 +sg19 +S' memcpy(&n,s,sizeof(s)); // fail - sizeof not of destination' +p281 +sg21 +g270 +sg23 +g271 +sg25 +g272 +sg28 +I53 +sg29 +g30 +sg31 +I1262 +sbag1 +(g2 +g3 +Ntp282 +Rp283 +(dp284 +g7 +g8 +sg9 +I1330 +sg10 +S'memcpy' +p285 +sg12 +(lp286 +g14 +aS'd' +p287 +aS's' +p288 +aS'n' +p289 +asg16 +I2 +sg17 +g14 +sg18 +I3 +sg19 +S' memcpy(d,s,n); // fail - size unguessable' +p290 +sg21 +g270 +sg23 +g271 +sg25 +g272 +sg28 +I54 +sg29 +g30 +sg31 +I1324 +sbag1 +(g2 +g3 +Ntp291 +Rp292 +(dp293 +g7 +g8 +sg9 +I1378 +sg10 +S'CopyMemory' +p294 +sg12 +(lp295 +g14 +aS'd' +p296 +aS's' +p297 +asg16 +I2 +sg17 +g14 +sg18 +I3 +sg19 +S' CopyMemory(d,s);' +p298 +sg21 +g270 +sg23 +g271 +sg25 +g272 +sg28 +I55 +sg29 +g30 +sg31 +I1368 +sbag1 +(g2 +g3 +Ntp299 +Rp300 +(dp301 +g7 +g86 +sg9 +I3151 +sg10 +S'fopen' +p302 +sg12 +(lp303 +g14 +aS'"/etc/passwd"' +p304 +aS'"r"' +p305 +asg16 +I2 +sg17 +g14 +sg18 +I7 +sg19 +S' f = fopen("/etc/passwd", "r"); ' +p306 +sg21 +g22 +sg23 +S'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? (CWE-362)' +p307 +sg25 +g14 +sg28 +I101 +sg29 +g30 +sg31 +I3146 +sbag1 +(g2 +g3 +Ntp308 +Rp309 +(dp310 +g7 +g8 +sg9 +I282 +sg10 +S'strcpy' +p311 +sg12 +(lp312 +g14 +aS'a' +p313 +aS'"\\n"' +p314 +asg16 +I1 +sg17 +g14 +sg18 +I2 +sg19 +S' strcpy(a, "\\n"); // Did this work?' +p315 +sg41 +S'Risk is low because the source is a constant character.' +p316 +sg21 +g105 +sg23 +g106 +sg25 +g107 +sg28 +I15 +sg29 +g30 +sg31 +I276 +sbag1 +(g2 +g3 +Ntp317 +Rp318 +(dp319 +g7 +g8 +sg9 +I388 +sg10 +S'sprintf' +p320 +sg12 +(lp321 +g14 +aS's' +p322 +aS'"\\n"' +p323 +asg16 +I1 +sg17 +g14 +sg18 +I2 +sg19 +S' sprintf(s, "\\n");' +p324 +sg41 +S'Risk is low because the source is a constant character.' +p325 +sg21 +g117 +sg23 +g118 +sg25 +g119 +sg28 +I18 +sg29 +g30 +sg31 +I381 +sbag1 +(g2 +g3 +Ntp326 +Rp327 +(dp328 +g7 +g8 +sg9 +I574 +sg10 +S'scanf' +p329 +sg12 +(lp330 +g14 +aS'"%10s"' +p331 +ag158 +asg16 +I1 +sg17 +g14 +sg18 +I2 +sg19 +S' scanf("%10s", s);' +p332 +sg21 +g160 +sg23 +S"It's unclear if the %s limit in the format string is small enough (CWE-120)" +p333 +sg25 +S'Check that the limit is sufficiently small, or use a different input function' +p334 +sg27 +I1 +sg28 +I26 +sg29 +g30 +sg31 +I569 +sbag1 +(g2 +g3 +Ntp335 +Rp336 +(dp337 +g7 +g8 +sg9 +I1410 +sg10 +S'strncpy' +p338 +sg12 +(lp339 +g14 +aS'd' +p340 +aS's' +p341 +asg16 +I1 +sg17 +g14 +sg18 +I3 +sg19 +S' strncpy(d,s);' +p342 +sg21 +g105 +sg23 +S"Easily used incorrectly; doesn't always \\0-terminate or check for invalid pointers [MS-banned] (CWE-120)" +p343 +sg25 +g14 +sg28 +I57 +sg29 +g30 +sg31 +I1403 +sbag1 +(g2 +g3 +Ntp344 +Rp345 +(dp346 +g7 +g8 +sg9 +I1427 +sg10 +S'_tcsncpy' +p347 +sg12 +(lp348 +g14 +aS'd' +p349 +aS's' +p350 +asg16 +I1 +sg17 +g14 +sg18 +I3 +sg19 +S' _tcsncpy(d,s);' +p351 +sg21 +g105 +sg23 +g343 +sg25 +g14 +sg28 +I58 +sg29 +g30 +sg31 +I1419 +sbag1 +(g2 +g3 +Ntp352 +Rp353 +(dp354 +g7 +g8 +sg9 +I1443 +sg10 +S'strncat' +p355 +sg12 +(lp356 +g14 +aS'd' +p357 +aS's' +p358 +aS'10' +p359 +asg16 +I1 +sg17 +g14 +sg18 +I3 +sg19 +S' strncat(d,s,10);' +p360 +sg21 +g43 +sg23 +g44 +sg25 +g45 +sg28 +I59 +sg29 +g30 +sg31 +I1436 +sbag1 +(g2 +g3 +Ntp361 +Rp362 +(dp363 +g7 +g8 +sg9 +I1599 +sg10 +S'strlen' +p364 +sg12 +(lp365 +g14 +aS'd' +p366 +asg16 +I1 +sg17 +g14 +sg18 +I7 +sg19 +S' n = strlen(d);' +p367 +sg21 +g22 +sg23 +S'Does not handle strings that are not \\0-terminated; if given one it may perform an over-read (it could cause a crash if unprotected) (CWE-126)' +p368 +sg25 +g14 +sg28 +I62 +sg29 +g30 +sg31 +I1593 +sbag1 +(g2 +g3 +Ntp369 +Rp370 +(dp371 +g7 +g8 +sg9 +I1918 +sg10 +S'MultiByteToWideChar' +p372 +sg12 +(lp373 +g14 +aS'CP_ACP' +p374 +aS'0' +p375 +aS'szName' +p376 +aS'-1' +p377 +aS'wszUserName' +p378 +aS'sizeof(wszUserName)/sizeof(wszUserName[0])' +p379 +asg16 +I1 +sg17 +g14 +sg18 +I3 +sg19 +S' MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName)/sizeof(wszUserName[0]));' +p380 +sg41 +S'Risk is very low, the length appears to be in characters not bytes.' +p381 +sg21 +g69 +sg23 +g70 +sg25 +g14 +sg28 +I68 +sg29 +g30 +sg31 +I1899 +sbag1 +(g2 +g3 +Ntp382 +Rp383 +(dp384 +g7 +g8 +sg9 +I2045 +sg10 +S'MultiByteToWideChar' +p385 +sg12 +(lp386 +g14 +aS'CP_ACP' +p387 +aS'0' +p388 +aS'szName' +p389 +aS'-1' +p390 +aS'wszUserName' +p391 +aS'sizeof wszUserName /sizeof(wszUserName[0])' +p392 +asg16 +I1 +sg17 +g14 +sg18 +I3 +sg19 +S' MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName /sizeof(wszUserName[0]));' +p393 +sg41 +g381 +sg21 +g69 +sg23 +g70 +sg25 +g14 +sg28 +I70 +sg29 +g30 +sg31 +I2026 +sbag1 +(g2 +g3 +Ntp394 +Rp395 +(dp396 +g7 +g132 +sg9 +I200 +sg10 +S'printf' +p397 +sg12 +(lp398 +g14 +aS'"hello\\n"' +p399 +asg16 +I0 +sg17 +g14 +sg18 +I2 +sg19 +S' printf("hello\\n");' +p400 +sg41 +S'Constant format string, so not considered risky.' +p401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I9 +sg29 +g30 +sg31 +I194 +sbag1 +(g2 +g3 +Ntp402 +Rp403 +(dp404 +g7 +g8 +sg9 +I539 +sg10 +S'scanf' +p405 +sg12 +(lp406 +g14 +aS'"%d"' +p407 +aS'&x' +p408 +asg16 +I0 +sg17 +g14 +sg18 +I2 +sg19 +S' scanf("%d", &x);' +p409 +sg41 +S'No risky scanf format detected.' +p410 +sg21 +g160 +sg23 +g161 +sg25 +g162 +sg27 +I1 +sg28 +I24 +sg29 +g30 +sg31 +I534 +sbag1 +(g2 +g3 +Ntp411 +Rp412 +(dp413 +g7 +g132 +sg9 +I643 +sg10 +S'printf' +p414 +sg12 +(lp415 +g14 +aS'"\\\\"' +p416 +asg16 +I0 +sg17 +g14 +sg18 +I2 +sg19 +S' printf("\\\\");' +p417 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I29 +sg29 +g30 +sg31 +I637 +sbag1 +(g2 +g3 +Ntp418 +Rp419 +(dp420 +g7 +g132 +sg9 +I837 +sg10 +S'syslog' +p421 +sg12 +(lp422 +g14 +aS'LOG_ERR' +p423 +aS'"cannot open config file (%s): %s"' +p424 +aS'filename' +p425 +aS'strerror(errno)' +p426 +asg16 +I0 +sg17 +g14 +sg18 +I2 +sg19 +S' syslog(LOG_ERR,"cannot open config file (%s): %s",filename,strerror(errno))' +p427 +sg41 +g401 +sg21 +g149 +sg178 +I2 +sg23 +g179 +sg25 +g180 +sg28 +I35 +sg29 +g30 +sg31 +I831 +sbag1 +(g2 +g3 +Ntp428 +Rp429 +(dp430 +g7 +g132 +sg9 +I914 +sg10 +S'syslog' +p431 +sg12 +(lp432 +g14 +aS'LOG_CRIT' +p433 +aS'"malloc() failed"' +p434 +asg16 +I0 +sg17 +g14 +sg18 +I2 +sg19 +S' syslog(LOG_CRIT,"malloc() failed");' +p435 +sg41 +g401 +sg21 +g149 +sg178 +I2 +sg23 +g179 +sg25 +g180 +sg28 +I36 +sg29 +g30 +sg31 +I908 +sbag1 +(g2 +g3 +Ntp436 +Rp437 +(dp438 +g7 +g132 +sg9 +I2745 +sg10 +S'printf' +p439 +sg12 +(lp440 +g14 +aS'"%c\\n"' +p441 +aS"'x'" +p442 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", \'x\');' +p443 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I81 +sg29 +g30 +sg31 +I2739 +sbag1 +(g2 +g3 +Ntp444 +Rp445 +(dp446 +g7 +g132 +sg9 +I2768 +sg10 +S'printf' +p447 +sg12 +(lp448 +g14 +aS'"%c\\n"' +p449 +aS'\'"\'' +p450 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", \'"\');' +p451 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I82 +sg29 +g30 +sg31 +I2762 +sbag1 +(g2 +g3 +Ntp452 +Rp453 +(dp454 +g7 +g132 +sg9 +I2791 +sg10 +S'printf' +p455 +sg12 +(lp456 +g14 +aS'"%c\\n"' +p457 +aS'\'\\"\'' +p458 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", \'\\"\');' +p459 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I83 +sg29 +g30 +sg31 +I2785 +sbag1 +(g2 +g3 +Ntp460 +Rp461 +(dp462 +g7 +g132 +sg9 +I2815 +sg10 +S'printf' +p463 +sg12 +(lp464 +g14 +aS'"%c\\n"' +p465 +aS"'\\''" +p466 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", \'\\\'\');' +p467 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I84 +sg29 +g30 +sg31 +I2809 +sbag1 +(g2 +g3 +Ntp468 +Rp469 +(dp470 +g7 +g132 +sg9 +I2839 +sg10 +S'printf' +p471 +sg12 +(lp472 +g14 +aS'"%c\\n"' +p473 +aS"'\\177'" +p474 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", \'\\177\');' +p475 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I85 +sg29 +g30 +sg31 +I2833 +sbag1 +(g2 +g3 +Ntp476 +Rp477 +(dp478 +g7 +g132 +sg9 +I2865 +sg10 +S'printf' +p479 +sg12 +(lp480 +g14 +aS'"%c\\n"' +p481 +aS"'\\xfe'" +p482 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", \'\\xfe\');' +p483 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I86 +sg29 +g30 +sg31 +I2859 +sbag1 +(g2 +g3 +Ntp484 +Rp485 +(dp486 +g7 +g132 +sg9 +I2891 +sg10 +S'printf' +p487 +sg12 +(lp488 +g14 +aS'"%c\\n"' +p489 +aS"'\\xd'" +p490 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", \'\\xd\');' +p491 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I87 +sg29 +g30 +sg31 +I2885 +sbag1 +(g2 +g3 +Ntp492 +Rp493 +(dp494 +g7 +g132 +sg9 +I2916 +sg10 +S'printf' +p495 +sg12 +(lp496 +g14 +aS'"%c\\n"' +p497 +aS"'\\n'" +p498 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", \'\\n\');' +p499 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I88 +sg29 +g30 +sg31 +I2910 +sbag1 +(g2 +g3 +Ntp500 +Rp501 +(dp502 +g7 +g132 +sg9 +I2940 +sg10 +S'printf' +p503 +sg12 +(lp504 +g14 +aS'"%c\\n"' +p505 +aS"'\\\\'" +p506 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", \'\\\\\');' +p507 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I89 +sg29 +g30 +sg31 +I2934 +sbag1 +(g2 +g3 +Ntp508 +Rp509 +(dp510 +g7 +g132 +sg9 +I2964 +sg10 +S'printf' +p511 +sg12 +(lp512 +g14 +aS'"%c\\n"' +p513 +aS'"\'"' +p514 +asg16 +I0 +sg17 +g14 +sg18 +I3 +sg19 +S' printf("%c\\n", "\'");' +p515 +sg41 +g401 +sg21 +g149 +sg23 +g150 +sg25 +g151 +sg28 +I90 +sg29 +g30 +sg31 +I2958 +sbag1 +(g2 +g3 +Ntp516 +Rp517 +(dp518 +g7 +g132 +sg9 +I3289 +sg10 +S'fprintf' +p519 +sg12 +(lp520 +g14 +aS'stderr' +p521 +aS'"Assertion failed.\\n"\\\n "File: %s\\nLine: %d\\n"\\\n "Assertion: %s\\n\\n"' +p522 +aS'__FILE__' +p523 +aS'__LINE__' +p524 +aS'#x' +p525 +asg16 +I0 +sg17 +g14 +sg18 +I2 +sg19 +S' fprintf(stderr,"Assertion failed.\\n"\\' +p526 +sg41 +g401 +sg21 +g149 +sg178 +I2 +sg23 +g150 +sg25 +g151 +sg28 +I109 +sg29 +g30 +sg31 +I3282 +sba. \ No newline at end of file diff --git a/test.c b/test.c new file mode 100644 index 0000000..e51bfef --- /dev/null +++ b/test.c @@ -0,0 +1,121 @@ +/* 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); // fail - no size + memcpy(d, s, sizeof(d)); // pass + memcpy(& n, s, sizeof( n )); // pass + memcpy(&n,s,sizeof(s)); // fail - sizeof not of destination + memcpy(d,s,n); // fail - size unguessable + 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/test.csv b/test.csv new file mode 100755 index 0000000..325967f --- /dev/null +++ b/test.csv @@ -0,0 +1,37 @@ +File,Line,Column,Level,Category,Name,Warning,Suggestion,Note,CWEs,Context +test.c,32,2,5,buffer,gets,"Does not check for buffer overflows (CWE-120, CWE-20)",Use fgets() instead,,"CWE-120, CWE-20", gets(f); +test.c,56,3,5,buffer,strncat,"Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120)","Consider strcat_s, strlcat, snprintf, or automatically resizing strings","Risk is high; the length parameter appears to be a constant, instead of computing the number of characters left.",CWE-120," strncat(d,s,sizeof(d)); /* Misuse - this should be flagged as riskier. */" +test.c,57,3,5,buffer,_tcsncat,"Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120)","Consider strcat_s, strlcat, or automatically resizing strings","Risk is high; the length parameter appears to be a constant, instead of computing the number of characters left.",CWE-120," _tcsncat(d,s,sizeof(d)); /* Misuse - flag as riskier */" +test.c,60,3,5,buffer,MultiByteToWideChar,"Requires maximum length in CHARACTERS, not bytes (CWE-120)",,"Risk is high, it appears that the size is given as bytes, but the function requires size as characters.",CWE-120," MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName));" +test.c,62,3,5,buffer,MultiByteToWideChar,"Requires maximum length in CHARACTERS, not bytes (CWE-120)",,"Risk is high, it appears that the size is given as bytes, but the function requires size as characters.",CWE-120," MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName);" +test.c,73,3,5,misc,SetSecurityDescriptorDacl,"Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732)",,,CWE-732," SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE);" +test.c,73,3,5,misc,SetSecurityDescriptorDacl,"Never create NULL ACLs; an attacker can set it to Everyone (Deny All Access), which would even forbid administrator access (CWE-732)",,,CWE-732," SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE);" +test.c,17,2,4,buffer,strcpy,Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120),"Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused)",,CWE-120," strcpy(b, a);" +test.c,20,2,4,buffer,sprintf,Does not check for buffer overflows (CWE-120),"Use sprintf_s, snprintf, or vsnprintf",,CWE-120," sprintf(s, ""hello %s"", bug);" +test.c,21,2,4,buffer,sprintf,Does not check for buffer overflows (CWE-120),"Use sprintf_s, snprintf, or vsnprintf",,CWE-120," sprintf(s, gettext(""hello %s""), bug);" +test.c,22,2,4,format,sprintf,Potential format string problem (CWE-134),Make format string constant,,CWE-134," sprintf(s, unknown, bug);" +test.c,23,2,4,format,printf,"If format strings can be influenced by an attacker, they can be exploited (CWE-134)",Use a constant for the format specification,,CWE-134," printf(bf, x);" +test.c,25,2,4,buffer,scanf,"The scanf() family's %s operation, without a limit specification, permits buffer overflows (CWE-120, CWE-20)","Specify a limit to %s, or use a different input function",,"CWE-120, CWE-20"," scanf(""%s"", s);" +test.c,27,2,4,buffer,scanf,"The scanf() family's %s operation, without a limit specification, permits buffer overflows (CWE-120, CWE-20)","Specify a limit to %s, or use a different input function",,"CWE-120, CWE-20"," scanf(""%s"", s);" +test.c,38,2,4,format,syslog,"If syslog's format strings can be influenced by an attacker, they can be exploited (CWE-134)",Use a constant format string for syslog,,CWE-134," syslog(LOG_ERR, attacker_string);" +test.c,49,3,4,buffer,_mbscpy,Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120),Consider using a function version that stops copying at the end of the buffer,,CWE-120," _mbscpy(d,s); /* like strcpy, this doesn't check for buffer overflow */" +test.c,52,3,4,buffer,lstrcat,Does not check for buffer overflows when concatenating to destination [MS-banned] (CWE-120),,,CWE-120," lstrcat(d,s);" +test.c,75,3,3,shell,CreateProcess,This causes a new process to execute and is difficult to use safely (CWE-78),"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",,CWE-78," CreateProcess(NULL, ""C:\\Program Files\\GoodGuy\\GoodGuy.exe -x"", """");" +test.c,75,3,3,shell,CreateProcess,This causes a new process to execute and is difficult to use safely (CWE-78),"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",,CWE-78," CreateProcess(NULL, ""C:\\Program Files\\GoodGuy\\GoodGuy.exe -x"", """");" +test.c,91,20,3,buffer,getopt_long,"Some older implementations do not protect against internal buffer overflows (CWE-120, CWE-20)","Check implementation on installation, or limit the size of all string inputs",,"CWE-120, CWE-20"," while ((optc = getopt_long (argc, argv, ""a"",longopts, NULL )) != EOF) {" +test.c,16,2,2,buffer,strcpy,Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120),"Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused)",Risk is low because the source is a constant string.,CWE-120," strcpy(a, gettext(""Hello there"")); // Did this work?" +test.c,19,2,2,buffer,sprintf,Does not check for buffer overflows (CWE-120),"Use sprintf_s, snprintf, or vsnprintf",Risk is low because the source has a constant maximum length.,CWE-120," sprintf(s, ""hello"");" +test.c,45,3,2,buffer,char,"Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120)","Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length",,CWE-119!/CWE-120, char d[20]; +test.c,46,3,2,buffer,char,"Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120)","Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length",,CWE-119!/CWE-120, char s[20]; +test.c,50,3,2,buffer,memcpy,Does not check for buffer overflows when copying to destination (CWE-120),Make sure destination can always hold the source data,,CWE-120," memcpy(d,s);" +test.c,51,3,2,buffer,CopyMemory,Does not check for buffer overflows when copying to destination (CWE-120),Make sure destination can always hold the source data,,CWE-120," CopyMemory(d,s);" +test.c,97,7,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? (CWE-362)",,,CWE-362," f = fopen(""/etc/passwd"", ""r""); " +test.c,15,2,1,buffer,strcpy,Does not check for buffer overflows when copying to destination [MS-banned] (CWE-120),"Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy easily misused)",Risk is low because the source is a constant character.,CWE-120," strcpy(a, ""\n""); // Did this work?" +test.c,18,2,1,buffer,sprintf,Does not check for buffer overflows (CWE-120),"Use sprintf_s, snprintf, or vsnprintf",Risk is low because the source is a constant character.,CWE-120," sprintf(s, ""\n"");" +test.c,26,2,1,buffer,scanf,It's unclear if the %s limit in the format string is small enough (CWE-120),"Check that the limit is sufficiently small, or use a different input function",,CWE-120," scanf(""%10s"", s);" +test.c,53,3,1,buffer,strncpy,Easily used incorrectly; doesn't always \0-terminate or check for invalid pointers [MS-banned] (CWE-120),,,CWE-120," strncpy(d,s);" +test.c,54,3,1,buffer,_tcsncpy,Easily used incorrectly; doesn't always \0-terminate or check for invalid pointers [MS-banned] (CWE-120),,,CWE-120," _tcsncpy(d,s);" +test.c,55,3,1,buffer,strncat,"Easily used incorrectly (e.g., incorrectly computing the correct maximum size to add) [MS-banned] (CWE-120)","Consider strcat_s, strlcat, snprintf, or automatically resizing strings",,CWE-120," strncat(d,s,10);" +test.c,58,7,1,buffer,strlen,Does not handle strings that are not \0-terminated; if given one it may perform an over-read (it could cause a crash if unprotected) (CWE-126),,,CWE-126, n = strlen(d); +test.c,64,3,1,buffer,MultiByteToWideChar,"Requires maximum length in CHARACTERS, not bytes (CWE-120)",,"Risk is very low, the length appears to be in characters not bytes.",CWE-120," MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName)/sizeof(wszUserName[0]));" +test.c,66,3,1,buffer,MultiByteToWideChar,"Requires maximum length in CHARACTERS, not bytes (CWE-120)",,"Risk is very low, the length appears to be in characters not bytes.",CWE-120," MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName /sizeof(wszUserName[0]));" diff --git a/test.patch b/test.patch new file mode 100755 index 0000000..aff1be6 --- /dev/null +++ b/test.patch @@ -0,0 +1,15 @@ +diff --git a/test.c b/test.c +index 97579c0..9ee11a1 100644 +--- a/test.c ++++ b/test.c +@@ -9,6 +9,10 @@ main() { + printf("hello\n"); + } + ++int bad(char *a, char *b) { ++ strcpy(b, a); ++} ++ + /* This is a strcpy test. */ + + int demo(char *a, char *b) { 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 */