From ac998c7c23375ba2037ed2ef7f24e57e945da22a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Mayoral=20Vilches?= Date: Thu, 16 Jan 2020 17:51:33 +0100 Subject: [PATCH] Initial content --- CONTRIBUTING.md | 144 +++ COPYING | 340 ++++++ ChangeLog | 707 +++++++++++ INSTALL.md | 131 ++ MANIFEST.in | 14 + README.md | 79 ++ announcement | 29 + buggy-latin1.c | 8 + buggy.c | 5 + correct-results-004.txt | 7 + correct-results-005.txt | 1 + correct-results-006.txt | 7 + correct-results-008.txt | 17 + correct-results.csv | 39 + correct-results.html | 344 ++++++ correct-results.txt | 163 +++ cwe.l | 29 + flawfinder | 2236 ++++++++++++++++++++++++++++++++++ flawfinder.1 | 1268 +++++++++++++++++++ flawfinder.1.gz | Bin 0 -> 19342 bytes flawfinder.pdf | Bin 0 -> 85608 bytes flawfinder.ps | Bin 0 -> 104962 bytes flawfinder.spec | 47 + flawfinder.yapf | 0 flawtest.c | 26 + junk.c | 10 + makefile | 271 +++++ no-ending-newline.c | 32 + pylintrc | 436 +++++++ release_process.md | 87 ++ setup.cfg | 13 + setup.py | 47 + sloctest.c | 9 + test-diff-005.patch | 13 + test-junk-006.txt | 38 + test-junk-008.txt | 38 + test-patched.c | 121 ++ test-preproc.c | 1515 +++++++++++++++++++++++ test-results-004.txt | 7 + test-results-005.txt | 1 + test-results-006.txt | 7 + test-results-008.txt | 17 + test-results.csv | 39 + test-results.html | 344 ++++++ test-results.txt | 163 +++ test-saved-hitlist-006.txt | 2368 ++++++++++++++++++++++++++++++++++++ test-saved-hitlist-008.txt | 2368 ++++++++++++++++++++++++++++++++++++ test.c | 121 ++ test.csv | 37 + test.patch | 15 + test2.c | 1 + 51 files changed, 13759 insertions(+) create mode 100644 CONTRIBUTING.md create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL.md create mode 100644 MANIFEST.in create mode 100644 README.md create mode 100644 announcement create mode 100755 buggy-latin1.c create mode 100755 buggy.c create mode 100755 correct-results-004.txt create mode 100755 correct-results-005.txt create mode 100755 correct-results-006.txt create mode 100644 correct-results-008.txt create mode 100755 correct-results.csv create mode 100755 correct-results.html create mode 100755 correct-results.txt create mode 100644 cwe.l create mode 100755 flawfinder create mode 100644 flawfinder.1 create mode 100755 flawfinder.1.gz create mode 100755 flawfinder.pdf create mode 100755 flawfinder.ps create mode 100644 flawfinder.spec create mode 100755 flawfinder.yapf create mode 100644 flawtest.c create mode 100644 junk.c create mode 100644 makefile create mode 100644 no-ending-newline.c create mode 100644 pylintrc create mode 100644 release_process.md create mode 100644 setup.cfg create mode 100644 setup.py create mode 100644 sloctest.c create mode 100644 test-diff-005.patch create mode 100755 test-junk-006.txt create mode 100644 test-junk-008.txt create mode 100644 test-patched.c create mode 100755 test-preproc.c create mode 100755 test-results-004.txt create mode 100755 test-results-005.txt create mode 100755 test-results-006.txt create mode 100644 test-results-008.txt create mode 100755 test-results.csv create mode 100755 test-results.html create mode 100755 test-results.txt create mode 100755 test-saved-hitlist-006.txt create mode 100644 test-saved-hitlist-008.txt create mode 100644 test.c create mode 100755 test.csv create mode 100755 test.patch create mode 100644 test2.c 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 0000000000000000000000000000000000000000..ff1ac9e73396053da6f0caafcef2f8a6f4107872 GIT binary patch literal 19342 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 N{C`*&HfaIU006W(H-!KI literal 0 HcmV?d00001 diff --git a/flawfinder.pdf b/flawfinder.pdf new file mode 100755 index 0000000000000000000000000000000000000000..3ae63102f95b8d85137b2fa5339342fbb5b96db1 GIT binary patch literal 85608 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 @#R=Mo@t@AjaIpIh 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 literal 0 HcmV?d00001 diff --git a/flawfinder.ps b/flawfinder.ps new file mode 100755 index 0000000000000000000000000000000000000000..c4ae95a7aa914b937dae7feeebdeede813ea460c GIT binary patch literal 104962 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 z 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 */