Initial import

git-svn-id: svn+ssh://svn.code.sf.net/p/flawfinder/code/trunk@1 5c01084b-1f27-0410-9f85-80411afe95dc
This commit is contained in:
dwheeler 2007-01-16 02:44:45 +00:00
commit 14c90f7335
25 changed files with 6187 additions and 0 deletions

340
COPYING Normal file
View File

@ -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.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
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.
<signature of Ty Coon>, 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.

529
ChangeLog Normal file
View File

@ -0,0 +1,529 @@
2004-06-15 David A. Wheeler <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* Released version 1.25.
2004-05-30 David A. Wheeler <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* Released version 1.23. Minor bugfixes.
2003-09-27 David A. Wheeler <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <pre>...</pre>.
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 <job, at, webde-ag.de>
* Tiny patch to report the number of lines analyzed and
the analysis speed in lines/second.
2002-07-04 David A. Wheeler <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <job, at, webde-ag.de>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* Released version 0.20.
* Added --version, which prints JUST the version number without
actually analyzing any programs.
2001-11-08 David A. Wheeler <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* Fixed manual page to close the "/*" comment with "*/".
2001-05-29 David A. Wheeler <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* 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 <dwheeler, at, dwheeler.com>
* Initial release of flawfinder version 0.12.

65
INSTALL.txt Normal file
View File

@ -0,0 +1,65 @@
To install flawfinder:
If you use an RPM-based system (e.g., Red Hat) or deb-based system
(e.g., Debian), use their respective RPM or debian installation program
and just install it; then ignore the rest of these instructions.
For a ports-based system where you have a current port, just use that.
Otherwise, you'll need to install from the tarball.
So, here's how to do that.
* Install the "tarball" and uncompress it.
GNU-based systems can run "tar xvzf flawfinder*.tar.gz" to do so,
then "cd" into the directory created. If that doesn't work
(e.g., you have an old tar program), use:
gunzip flawfinder*.tar.gz
tar xvf flawfinder*.tar
cd flawfinder-*
* Decide where you want to put it. Flawfinder normally installs
in /usr/local, with the program in /usr/local/bin and the manual in
/usr/local/man, per GNU conventions. You can override this
using the normal GNU conventions when installing (with "make install")
by setting INSTALL_DIR (defaults to /usr/local),
INSTALL_DIR_BIN for the program location (defaults to INSTALL_DIR/bin), and
INSTALL_DIR_MAN for the manual location (defaults to INSTALL_DIR/man).
* If you're using Cygwin on Windows, you can install it using "make install"
but you need to tell the makefile to use the .py extension
whenever you use make. This will be another make install override.
If you'll just install it, do this:
make PYTHONEXT=.py install
If you don't want to pass the "PYTHONEXT" extension each time,
you can change the file "makefile" to remember this. Just change
the line beginning with "PYTHONEXT=" so that it reads as follows:
PYTHONEXT=.py
* Now install it, giving whatever overrides you need.
In most cases, you'll need to be root, so run this first:
su
Then give the "make install" command appropriate for your system.
For an all-default installation, which is what you need for most cases:
make install
(you need to be root; "make uninstall" reverses it).
To install in /usr (the program in /usr/bin, the manual in /usr/man):
make INSTALL_DIR=/usr install
To put the binaries in /usr/bin, and the manuals in /usr/share/man
(common for Red Hat Linux), do:
make INSTALL_DIR=/usr INSTALL_DIR_MAN=/usr/share/man install
* Windows systems should be able to run this on the command line (cmd.exe)
directly, but I haven't tried that.
* You can also simply run the program in the directory you've unpacked it
into. It's a simple Python program, just type into a command line:
./flawfinder files_or_directory

14
MANIFEST.in Normal file
View File

@ -0,0 +1,14 @@
include COPYING
include README
include announcement
include ChangeLog
include flawfinder.1*
include flawfinder.pdf
include flawfinder.ps
include flawfinder
include makefile
include setup.cfg
include setup.py
include test.c
include test_result

7
README Normal file
View File

@ -0,0 +1,7 @@
This is "flawfinder" by David A. Wheeler, <dwheeler@dwheeler.com>.
It's a simple Python program for scanning source code for security problems.
For more information, see:
http://www.dwheeler.com/flawfinder
See INSTALL for installation instructions.

29
announcement Normal file
View File

@ -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

270
correct-results.html Normal file
View File

@ -0,0 +1,270 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf8">
<title>Flawfinder Results</title>
<meta name="author" content="David A. Wheeler">
<meta name="keywords" lang="en" content="flawfinder results, security scan">
</head>
<body>
<h1>Flawfinder Results</h1>
Here are the security scan results from
<a href="http://www.dwheeler.com/flawfinder">Flawfinder version 1.25</a>,
(C) 2001-2004 <a href="http://www.dwheeler.com">David A. Wheeler</a>.
Number of dangerous functions in C/C++ ruleset: 137
<p>
Examining test.c <br>
Examining test2.c <br>
<ul>
<li>test.c:32: <b> [5] </b> (buffer) <i> gets:
Does not check for buffer overflows. Use fgets() instead. </i>
<pre>
gets(f);
</pre>
<li>test.c:56: <b> [5] </b> (buffer) <i> strncat:
Easily used incorrectly (e.g., incorrectly computing the correct
maximum size to add). Consider strlcat or automatically resizing strings.
Risk is high; the length parameter appears to be a constant, instead of
computing the number of characters left. </i>
<pre>
strncat(d,s,sizeof(d)); /* Misuse - this should be flagged as riskier. */
</pre>
<li>test.c:57: <b> [5] </b> (buffer) <i> _tcsncat:
Easily used incorrectly (e.g., incorrectly computing the correct
maximum size to add). Consider strlcat or automatically resizing strings.
Risk is high; the length parameter appears to be a constant, instead of
computing the number of characters left. </i>
<pre>
_tcsncat(d,s,sizeof(d)); /* Misuse - flag as riskier */
</pre>
<li>test.c:60: <b> [5] </b> (buffer) <i> MultiByteToWideChar:
Requires maximum length in CHARACTERS, not bytes. Risk is high, it
appears that the size is given as bytes, but the function requires size as
characters. </i>
<pre>
MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName));
</pre>
<li>test.c:62: <b> [5] </b> (buffer) <i> MultiByteToWideChar:
Requires maximum length in CHARACTERS, not bytes. Risk is high, it
appears that the size is given as bytes, but the function requires size as
characters. </i>
<pre>
MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName);
</pre>
<li>test.c:73: <b> [5] </b> (misc) <i> SetSecurityDescriptorDacl:
Never create NULL ACLs; an attacker can set it to Everyone (Deny All
Access), which would even forbid administrator access. </i>
<pre>
SetSecurityDescriptorDacl(&amp;sd,TRUE,NULL,FALSE);
</pre>
<li>test.c:73: <b> [5] </b> (misc) <i> SetSecurityDescriptorDacl:
Never create NULL ACLs; an attacker can set it to Everyone (Deny All
Access), which would even forbid administrator access. </i>
<pre>
SetSecurityDescriptorDacl(&amp;sd,TRUE,NULL,FALSE);
</pre>
<li>test.c:17: <b> [4] </b> (buffer) <i> strcpy:
Does not check for buffer overflows when copying to destination.
Consider using strncpy or strlcpy (warning, strncpy is easily misused). </i>
<pre>
strcpy(b, a);
</pre>
<li>test.c:20: <b> [4] </b> (buffer) <i> sprintf:
Does not check for buffer overflows. Use snprintf or vsnprintf. </i>
<pre>
sprintf(s, "hello %s", bug);
</pre>
<li>test.c:21: <b> [4] </b> (buffer) <i> sprintf:
Does not check for buffer overflows. Use snprintf or vsnprintf. </i>
<pre>
sprintf(s, gettext("hello %s"), bug);
</pre>
<li>test.c:22: <b> [4] </b> (format) <i> sprintf:
Potential format string problem. Make format string constant. </i>
<pre>
sprintf(s, unknown, bug);
</pre>
<li>test.c:23: <b> [4] </b> (format) <i> printf:
If format strings can be influenced by an attacker, they can be
exploited. Use a constant for the format specification. </i>
<pre>
printf(bf, x);
</pre>
<li>test.c:25: <b> [4] </b> (buffer) <i> scanf:
The scanf() family's %s operation, without a limit specification,
permits buffer overflows. Specify a limit to %s, or use a different input
function. </i>
<pre>
scanf("%s", s);
</pre>
<li>test.c:27: <b> [4] </b> (buffer) <i> scanf:
The scanf() family's %s operation, without a limit specification,
permits buffer overflows. Specify a limit to %s, or use a different input
function. </i>
<pre>
scanf("%s", s);
</pre>
<li>test.c:38: <b> [4] </b> (format) <i> syslog:
If syslog's format strings can be influenced by an attacker, they can
be exploited. Use a constant format string for syslog. </i>
<pre>
syslog(LOG_ERR, attacker_string);
</pre>
<li>test.c:49: <b> [4] </b> (buffer) <i> _mbscpy:
Does not check for buffer overflows when copying to destination.
Consider using a function version that stops copying at the end of the
buffer. </i>
<pre>
_mbscpy(d,s); /* like strcpy, this doesn't check for buffer overflow */
</pre>
<li>test.c:52: <b> [4] </b> (buffer) <i> lstrcat:
Does not check for buffer overflows when concatenating to destination. </i>
<pre>
lstrcat(d,s);
</pre>
<li>test.c:75: <b> [3] </b> (shell) <i> CreateProcess:
This causes a new process to execute and is difficult to use safely.
Specify the application path in the first argument, NOT as part of the
second, or embedded spaces could allow an attacker to force a different
program to run. </i>
<pre>
CreateProcess(NULL, "C:\\Program Files\\GoodGuy\\GoodGuy.exe -x", "");
</pre>
<li>test.c:75: <b> [3] </b> (shell) <i> CreateProcess:
This causes a new process to execute and is difficult to use safely.
Specify the application path in the first argument, NOT as part of the
second, or embedded spaces could allow an attacker to force a different
program to run. </i>
<pre>
CreateProcess(NULL, "C:\\Program Files\\GoodGuy\\GoodGuy.exe -x", "");
</pre>
<li>test.c:91: <b> [3] </b> (buffer) <i> getopt_long:
Some older implementations do not protect against internal buffer
overflows . Check implementation on installation, or limit the size of all
string inputs. </i>
<pre>
while ((optc = getopt_long (argc, argv, "a",longopts, NULL )) != EOF) {
</pre>
<li>test.c:16: <b> [2] </b> (buffer) <i> strcpy:
Does not check for buffer overflows when copying to destination.
Consider using strncpy or strlcpy (warning, strncpy is easily misused). Risk
is low because the source is a constant string. </i>
<pre>
strcpy(a, gettext("Hello there")); // Did this work?
</pre>
<li>test.c:19: <b> [2] </b> (buffer) <i> sprintf:
Does not check for buffer overflows. Use snprintf or vsnprintf. Risk
is low because the source has a constant maximum length. </i>
<pre>
sprintf(s, "hello");
</pre>
<li>test.c:45: <b> [2] </b> (buffer) <i> char:
Statically-sized arrays can be overflowed. Perform bounds checking,
use functions that limit length, or ensure that the size is larger than
the maximum possible length. </i>
<pre>
char d[20];
</pre>
<li>test.c:46: <b> [2] </b> (buffer) <i> char:
Statically-sized arrays can be overflowed. Perform bounds checking,
use functions that limit length, or ensure that the size is larger than
the maximum possible length. </i>
<pre>
char s[20];
</pre>
<li>test.c:50: <b> [2] </b> (buffer) <i> memcpy:
Does not check for buffer overflows when copying to destination. Make
sure destination can always hold the source data. </i>
<pre>
memcpy(d,s);
</pre>
<li>test.c:51: <b> [2] </b> (buffer) <i> CopyMemory:
Does not check for buffer overflows when copying to destination. Make
sure destination can always hold the source data. </i>
<pre>
CopyMemory(d,s);
</pre>
<li>test.c:97: <b> [2] </b> (misc) <i> 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?. </i>
<pre>
f = fopen("/etc/passwd", "r");
</pre>
<li>test.c:15: <b> [1] </b> (buffer) <i> strcpy:
Does not check for buffer overflows when copying to destination.
Consider using strncpy or strlcpy (warning, strncpy is easily misused). Risk
is low because the source is a constant character. </i>
<pre>
strcpy(a, "\n"); // Did this work?
</pre>
<li>test.c:18: <b> [1] </b> (buffer) <i> sprintf:
Does not check for buffer overflows. Use snprintf or vsnprintf. Risk
is low because the source is a constant character. </i>
<pre>
sprintf(s, "\n");
</pre>
<li>test.c:26: <b> [1] </b> (buffer) <i> scanf:
it's unclear if the %s limit in the format string is small enough.
Check that the limit is sufficiently small, or use a different input
function. </i>
<pre>
scanf("%10s", s);
</pre>
<li>test.c:53: <b> [1] </b> (buffer) <i> strncpy:
Easily used incorrectly; doesn't always \0-terminate or check for
invalid pointers. </i>
<pre>
strncpy(d,s);
</pre>
<li>test.c:54: <b> [1] </b> (buffer) <i> _tcsncpy:
Easily used incorrectly; doesn't always \0-terminate or check for
invalid pointers. </i>
<pre>
_tcsncpy(d,s);
</pre>
<li>test.c:55: <b> [1] </b> (buffer) <i> strncat:
Easily used incorrectly (e.g., incorrectly computing the correct
maximum size to add). Consider strlcat or automatically resizing strings. </i>
<pre>
strncat(d,s,10);
</pre>
<li>test.c:58: <b> [1] </b> (buffer) <i> strlen:
Does not handle strings that are not \0-terminated (it could cause a
crash if unprotected). </i>
<pre>
n = strlen(d);
</pre>
<li>test.c:64: <b> [1] </b> (buffer) <i> MultiByteToWideChar:
Requires maximum length in CHARACTERS, not bytes. Risk is very low,
the length appears to be in characters not bytes. </i>
<pre>
MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName)/sizeof(wszUserName[0]));
</pre>
<li>test.c:66: <b> [1] </b> (buffer) <i> MultiByteToWideChar:
Requires maximum length in CHARACTERS, not bytes. Risk is very low,
the length appears to be in characters not bytes. </i>
<pre>
MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName /sizeof(wszUserName[0]));
</pre>
</ul>
<p>
Hits = 36
<br>
Lines analyzed = 118
<br>
Physical Source Lines of Code (SLOC) = 80
<br>
Hits @ level = [0] 0 [1] 9 [2] 7 [3] 3 [4] 10 [5] 7 <br>
Hits @ level+ = [0+] 36 [1+] 36 [2+] 27 [3+] 20 [4+] 17 [5+] 7 <br>
Hits/KSLOC @ level+ = [0+] 450 [1+] 450 [2+] 338 [3+] 250 [4+] 213 [5+] 88 <br>
Suppressed hits = 2 (use --neverignore to show them)
<br>
Minimum risk level = 1
<br>
Not every hit is necessarily a security vulnerability.
<br>
There may be other security vulnerabilities; review your code!
</body>
</html>

139
correct-results.txt Normal file
View File

@ -0,0 +1,139 @@
Flawfinder version 1.25, (C) 2001-2004 David A. Wheeler.
Number of dangerous functions in C/C++ ruleset: 137
Examining test.c
Examining test2.c
test.c:32: [5] (buffer) gets:
Does not check for buffer overflows. Use fgets() instead.
test.c:56: [5] (buffer) strncat:
Easily used incorrectly (e.g., incorrectly computing the correct
maximum size to add). Consider strlcat or automatically resizing strings.
Risk is high; the length parameter appears to be a constant, instead of
computing the number of characters left.
test.c:57: [5] (buffer) _tcsncat:
Easily used incorrectly (e.g., incorrectly computing the correct
maximum size to add). Consider strlcat or automatically resizing strings.
Risk is high; the length parameter appears to be a constant, instead of
computing the number of characters left.
test.c:60: [5] (buffer) MultiByteToWideChar:
Requires maximum length in CHARACTERS, not bytes. Risk is high, it
appears that the size is given as bytes, but the function requires size as
characters.
test.c:62: [5] (buffer) MultiByteToWideChar:
Requires maximum length in CHARACTERS, not bytes. Risk is high, it
appears that the size is given as bytes, but the function requires size as
characters.
test.c:73: [5] (misc) SetSecurityDescriptorDacl:
Never create NULL ACLs; an attacker can set it to Everyone (Deny All
Access), which would even forbid administrator access.
test.c:73: [5] (misc) SetSecurityDescriptorDacl:
Never create NULL ACLs; an attacker can set it to Everyone (Deny All
Access), which would even forbid administrator access.
test.c:17: [4] (buffer) strcpy:
Does not check for buffer overflows when copying to destination.
Consider using strncpy or strlcpy (warning, strncpy is easily misused).
test.c:20: [4] (buffer) sprintf:
Does not check for buffer overflows. Use snprintf or vsnprintf.
test.c:21: [4] (buffer) sprintf:
Does not check for buffer overflows. Use snprintf or vsnprintf.
test.c:22: [4] (format) sprintf:
Potential format string problem. Make format string constant.
test.c:23: [4] (format) printf:
If format strings can be influenced by an attacker, they can be
exploited. Use a constant for the format specification.
test.c:25: [4] (buffer) scanf:
The scanf() family's %s operation, without a limit specification,
permits buffer overflows. Specify a limit to %s, or use a different input
function.
test.c:27: [4] (buffer) scanf:
The scanf() family's %s operation, without a limit specification,
permits buffer overflows. Specify a limit to %s, or use a different input
function.
test.c:38: [4] (format) syslog:
If syslog's format strings can be influenced by an attacker, they can
be exploited. Use a constant format string for syslog.
test.c:49: [4] (buffer) _mbscpy:
Does not check for buffer overflows when copying to destination.
Consider using a function version that stops copying at the end of the
buffer.
test.c:52: [4] (buffer) lstrcat:
Does not check for buffer overflows when concatenating to destination.
test.c:75: [3] (shell) CreateProcess:
This causes a new process to execute and is difficult to use safely.
Specify the application path in the first argument, NOT as part of the
second, or embedded spaces could allow an attacker to force a different
program to run.
test.c:75: [3] (shell) CreateProcess:
This causes a new process to execute and is difficult to use safely.
Specify the application path in the first argument, NOT as part of the
second, or embedded spaces could allow an attacker to force a different
program to run.
test.c:91: [3] (buffer) getopt_long:
Some older implementations do not protect against internal buffer
overflows . Check implementation on installation, or limit the size of all
string inputs.
test.c:16: [2] (buffer) strcpy:
Does not check for buffer overflows when copying to destination.
Consider using strncpy or strlcpy (warning, strncpy is easily misused). Risk
is low because the source is a constant string.
test.c:19: [2] (buffer) sprintf:
Does not check for buffer overflows. Use snprintf or vsnprintf. Risk
is low because the source has a constant maximum length.
test.c:45: [2] (buffer) char:
Statically-sized arrays can be overflowed. Perform bounds checking,
use functions that limit length, or ensure that the size is larger than
the maximum possible length.
test.c:46: [2] (buffer) char:
Statically-sized arrays can be overflowed. Perform bounds checking,
use functions that limit length, or ensure that the size is larger than
the maximum possible length.
test.c:50: [2] (buffer) memcpy:
Does not check for buffer overflows when copying to destination. Make
sure destination can always hold the source data.
test.c:51: [2] (buffer) CopyMemory:
Does not check for buffer overflows when copying to destination. Make
sure destination can always hold the source data.
test.c:97: [2] (misc) fopen:
Check when opening files - can an attacker redirect it (via symlinks),
force the opening of special file type (e.g., device files), move
things around to create a race condition, control its ancestors, or change
its contents?.
test.c:15: [1] (buffer) strcpy:
Does not check for buffer overflows when copying to destination.
Consider using strncpy or strlcpy (warning, strncpy is easily misused). Risk
is low because the source is a constant character.
test.c:18: [1] (buffer) sprintf:
Does not check for buffer overflows. Use snprintf or vsnprintf. Risk
is low because the source is a constant character.
test.c:26: [1] (buffer) scanf:
it's unclear if the %s limit in the format string is small enough.
Check that the limit is sufficiently small, or use a different input
function.
test.c:53: [1] (buffer) strncpy:
Easily used incorrectly; doesn't always \0-terminate or check for
invalid pointers.
test.c:54: [1] (buffer) _tcsncpy:
Easily used incorrectly; doesn't always \0-terminate or check for
invalid pointers.
test.c:55: [1] (buffer) strncat:
Easily used incorrectly (e.g., incorrectly computing the correct
maximum size to add). Consider strlcat or automatically resizing strings.
test.c:58: [1] (buffer) strlen:
Does not handle strings that are not \0-terminated (it could cause a
crash if unprotected).
test.c:64: [1] (buffer) MultiByteToWideChar:
Requires maximum length in CHARACTERS, not bytes. Risk is very low,
the length appears to be in characters not bytes.
test.c:66: [1] (buffer) MultiByteToWideChar:
Requires maximum length in CHARACTERS, not bytes. Risk is very low,
the length appears to be in characters not bytes.
Hits = 36
Lines analyzed = 118
Physical Source Lines of Code (SLOC) = 80
Hits @ level = [0] 0 [1] 9 [2] 7 [3] 3 [4] 10 [5] 7
Hits @ level+ = [0+] 36 [1+] 36 [2+] 27 [3+] 20 [4+] 17 [5+] 7
Hits/KSLOC @ level+ = [0+] 450 [1+] 450 [2+] 338 [3+] 250 [4+] 213 [5+] 88
Suppressed hits = 2 (use --neverignore to show them)
Minimum risk level = 1
Not every hit is necessarily a security vulnerability.
There may be other security vulnerabilities; review your code!

114
flaw-defect-report Normal file
View File

@ -0,0 +1,114 @@
From - Sun Nov 4 11:39:04 2001
X-UIDL: 4bd5a7eeb0e24a21ff091e0d7f4cec01
X-Mozilla-Status: 0001
X-Mozilla-Status2: 00000000
Return-Path: <laz@clustermonkey.org>
Received: from cs.ida.org by fricka.csed.ida.org (SMI-8.6/SMI-SVR4)
id WAA06993; Fri, 2 Nov 2001 22:22:00 -0500
Received: from mailhost.nl (webframe.nl [212.204.207.201])
by cs.ida.org (Switch-2.2.0/Switch-2.2.0) with SMTP id fA33Lxp18254
for <dwheeler@ida.org>; Fri, 2 Nov 2001 22:21:59 -0500 (EST)
Received: from x-o.clustermonkey.org (postfix@x-o.clustermonkey.org [64.242.77.225])
by mailhost.nl (8.9.3/8.9.3) with ESMTP id EAA12369
for <dwheeler@dwheeler.com>; Sat, 3 Nov 2001 04:21:56 +0100
Received: by x-o.clustermonkey.org (Postfix, from userid 1000)
id 6B96B61E92B; Fri, 2 Nov 2001 22:21:54 -0500 (EST)
Date: Fri, 2 Nov 2001 22:21:54 -0500
From: Adam Lazur <zal@debian.org>
To: "David A. Wheeler" <dwheeler@dwheeler.com>
Subject: [arthur@tiefighter.et.tudelft.nl: Bug#118025: flawfinder does not detect multiline strings right]
Message-ID: <20011102222154.B24827@clustermonkey.org>
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="rwEMma7ioTxnRzrJ"
Content-Disposition: inline
User-Agent: Mutt/1.3.23i
X-UIDL: 4bd5a7eeb0e24a21ff091e0d7f4cec01
--rwEMma7ioTxnRzrJ
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Attached is the first bug report from the Debian package of flawfinder.
Replies can be sent to 118025@bugs.debian.org and they will be appended
to the bug's history and also sent to the bug submitter. The bug history
can be found at: http://bugs.debian.org/118025
--
Adam Lazur, Cluster Monkey
--rwEMma7ioTxnRzrJ
Content-Type: message/rfc822
Content-Disposition: inline
X-Envelope-From: debbugs@master.debian.org Fri Nov 2 10:09:37 2001
Return-Path: <debbugs@master.debian.org>
Delivered-To: laz@clustermonkey.org
Received: from master.debian.org (unknown [216.234.231.5])
by x-o.clustermonkey.org (Postfix) with ESMTP id 981EF61E913
for <adam@lazur.org>; Fri, 2 Nov 2001 10:09:37 -0500 (EST)
Received: from debbugs by master.debian.org with local (Exim 3.12 1 (Debian))
id 15zfqY-0007Zt-00; Fri, 02 Nov 2001 09:03:02 -0600
Subject: Bug#118025: flawfinder does not detect multiline strings right
Reply-To: arthur@tiefighter.et.tudelft.nl, 118025@bugs.debian.org
Resent-From: arthur@tiefighter.et.tudelft.nl
Resent-To: debian-bugs-dist@lists.debian.org
Resent-Cc: Adam Lazur <zal@debian.org>
Resent-Date: Fri, 02 Nov 2001 15:03:02 GMT
Resent-Message-ID: <handler.118025.B.100471287428113@bugs.debian.org>
X-Debian-PR-Message: report 118025
X-Debian-PR-Package: flawfinder
X-Loop: owner@bugs.debian.org
Received: via spool by submit@bugs.debian.org id=B.100471287428113
(code B ref -1); Fri, 02 Nov 2001 15:03:02 GMT
From: arthur@tiefighter.et.tudelft.nl
X-Authentication-Warning: ch.twi.tudelft.nl: arthur owned process doing -bs
Date: Fri, 2 Nov 2001 15:54:02 +0100 (CET)
X-Sender: arthur@ch.twi.tudelft.nl
To: submit@bugs.debian.org
Message-ID: <Pine.LNX.4.21.0111021507380.11135-100000@ch.twi.tudelft.nl>
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
Delivered-To: submit@bugs.debian.org
Resent-Sender: Debian BTS <debbugs@master.debian.org>
Package: flawfinder
Version: 0.17-1
Severity: normal
Does strange things with respect to strings that are spread over multiple
lines.
Sample code:
1: static void a()
2: {
3: printf(_("a"));
4: printf(_("b"
5: "c"));
6: printf("a");
7: printf("b"
8: "c");
9: }
Flawfinder output (partial):
/tmp/tst.c:4 [4] (format) printf: if format strings can be influenced by an attacker, they can be exploited. Use a constant for the format specification.
One would expect flawfinder either to report lines 3 and 4 as possible
security riscs or lines 4 and 7. This is not expected behaviour.
On a sindenote a disclaimer may be in order about the accuracy of the
results. All things flawfinder reported on my code were no security
threats.
-- arthur - arthur@tiefighter.et.tudelft.nl - http://tiefighter.et.tudelft.nl/~arthur --
--rwEMma7ioTxnRzrJ--

1664
flawfinder Executable file

File diff suppressed because it is too large Load Diff

737
flawfinder.1 Normal file
View File

@ -0,0 +1,737 @@
'\"
.\" (C) Copyright 2001 David A. Wheeler (dwheeler@dwheeler.com)
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program; if not, write to the Free Software
.\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
.\"
.\"
.\"
.\" Man page created 17 May 2001 by David A. Wheeler (dwheeler@dwheeler.com)
.\"
.TH FLAWFINDER 1 "30 May 2004" "Flawfinder" "Flawfinder"
.SH NAME
flawfinder \- find potential security flaws ("hits") in source code
.SH SYNOPSIS
.B flawfinder
.\" Documentation:
.RB [ \-\-help ]
.RB [ \-\-version ]
.\" Selecting Hits:
.RB [ \-\-allowlink ]
.RB [ \-\-inputs | \-I ]
[ \fB\-\-minlevel=\fR\fIX\fR | \fB-m\fR \fIX\fR ]
.RB [ \-\-falsepositive | \-F ]
.RB [ \-\-neverignore | \-n ]
.\" Selecting Output Format:
.RB [ \-\-context | \-c ]
.RB [ \-\-columns | \-C ]
.RB [ \-\-dataonly | \-D ]
.RB [ \-\-html ]
.RB [ \-\-immediate | -i ]
.RB [ \-\-singleline | \-S ]
.RB [ \-\-omittime ]
.RB [ \-\-quiet | \-Q ]
.\" Managing hit list.
[ \fB\-\-loadhitlist=\fR\fIF\fR ]
[ \fB\-\-savehitlist=\fR\fIF\fR ]
[ \fB\-\-diffhitlist=\fR\fIF\fR ]
.RB [ \-\- ]
.I [ source code file or source root directory ]+
.SH DESCRIPTION
.PP
Flawfinder searches through C/C++ source code looking for
potential security flaws.
To run flawfinder, simply give flawfinder a list of directories or files.
For each directory given, all files that have C/C++ filename extensions
in that directory (and its subdirectories, recursively) will be examined.
Thus, for most projects, simply give flawfinder the name of the source
code's topmost directory (use ``.'' for the current directory),
and flawfinder will examine all of the project's C/C++ source code.
.PP
Flawfinder will produce a list of ``hits'' (potential
security flaws), sorted by risk; the riskiest hits are shown first.
The risk level is shown inside square brackets and
varies from 0, very little risk, to 5, great risk.
This risk level depends not only on the function, but on the values of the
parameters of the function.
For example, constant strings are often less risky than fully variable
strings in many contexts, and in those contexts the hit will have a
lower risk level.
Flawfinder knows about gettext (a common library for internationalized
programs) and will treat constant strings
passed through gettext as though they were constant strings; this reduces
the number of false hits in internationalized programs.
Flawfinder will do the same sort of thing with _T() and _TEXT(),
common Microsoft macros for handling internationalized programs
.\" For more info, see: http://www.rpi.edu/~pudeyo/articles/unicode.html
Flawfinder correctly ignores most text inside comments and strings.
Normally flawfinder shows all hits with a risk level of at least 1,
but you can use the \-\-minlevel option
to show only hits with higher risk levels if you wish.
.PP
Not every hit is actually a security vulnerability,
and not every security vulnerability is necessarily found.
Nevertheless, flawfinder can be an aid in finding and removing
security vulnerabilities.
A common way to use flawfinder is to first
apply flawfinder to a set of source code and examine the
highest-risk items.
Then, use \-\-inputs to examine the input locations, and check to
make sure that only legal and safe input values are
accepted from untrusted users.
.PP
Once you've audited a program, you can mark source code lines that
are actually fine but cause spurious warnings so that flawfinder will
stop complaining about them.
To mark a line so that these warnings are suppressed,
put a specially-formatted comment either on the same
line (after the source code) or all by itself in the previous line.
The comment must have one of the two following formats:
.IP \(bu
// Flawfinder: ignore
.IP \(bu
/* Flawfinder: ignore */
.PP
Note that, for compatibility's sake, you can replace "Flawfinder:" with
"ITS4:" or "RATS:" in these specially-formatted comments.
Since it's possible that such lines are wrong, you can use the
``\-\-neverignore'' option, which causes flawfinder to never ignore any line
no matter what the comments say.
Thus, responses that would otherwise be ignored would be included
(or, more confusingly, \-\-neverignore ignores the ignores).
This comment syntax is actually a more general syntax for special directives
to flawfinder, but currently only ignoring lines is supported.
.PP
Flawfinder uses an internal database called the ``ruleset'';
the ruleset identifies functions that are common causes of security flaws.
The standard ruleset includes a large number of different potential
problems, including both general issues that can impact any
C/C++ program, as well as a number of specific Unix-like and Windows
functions that are especially problematic.
As noted above, every potential security flaw found in a given source code file
(matching an entry in the ruleset)
is called a ``hit,'' and the set of hits found during any particular
run of the program is called the ``hitlist.''
Hitlists can be saved (using \-\-savehitlist), reloaded back for redisplay
(using \-\-loadhitlist), and you can show only the hits that are different
from another run (using \-\-diffhitlist).
.PP
Any filename given on the command line will be examined (even if
it doesn't have a usual C/C++ filename extension); thus you can force
flawfinder to examine any specific files you desire.
While searching directories recursively, flawfinder only opens and
examines regular files that have C/C++ filename extensions.
Flawfinder presumes that, files are C/C++ files if they have the extensions
".c", ".h", ".ec", ".ecp", ".pgc", ".C", ".cpp",
".CPP", ".cxx", ".cc", ".CC", ".pcc", ".hpp", or ".H".
The filename ``\-'' means the standard input.
To prevent security problems,
special files (such as device special files and named pipes) are
always skipped, and by default symbolic links are skipped,
.PP
After the list of hits is a brief summary of the results
(use -D to remove this information).
It will show the number of hits, lines analyzed (as reported by wc \-l),
and the physical source lines of code (SLOC) analyzed.
A physical SLOC is a non-blank, non-comment line.
It will then show the number of hits at each level; note that there will
never be a hit at a level lower than minlevel (1 by default).
Thus, "[0] 0 [1] 9" means that at level 0 there were 0 hits reported,
and at level 1 there were 9 hits reported.
It will next show the number of hits at a given level or larger
(so level 3+ has the sum of the number of hits at level 3, 4, and 5).
Thus, an entry of "[0+] 37" shows that at level 0 or higher there were
37 hits (the 0+ entry will always be the same as the "hits" number above).
Hits per KSLOC is next shown; this is each of the "level or higher"
values multiplied by 1000 and divided by the physical SLOC.
If symlinks were skipped, the count of those is reported.
If hits were suppressed (using the "ignore" directive
in source code comments as described above), the number suppressed is reported.
The minimum risk level to be included in the report
is displayed; by default this is 1 (use \-\-minlevel to change this).
The summary ends with important reminders:
Not every hit is necessarily a security vulnerability, and
there may be other security vulnerabilities not reported by the tool.
.PP
Flawfinder intentionally works similarly to another program, ITS4, which is not
fully open source software (as defined in the Open Source Definition)
nor free software (as defined by the Free Software Foundation).
The author of Flawfinder has never seen ITS4's source code.
.SH "BRIEF TUTORIAL"
Here's a brief example of how flawfinder might be used.
Imagine that you have the C/C++ source code for some program named xyzzy
(which you may or may not have written), and you're
searching for security vulnerabilities (so you can fix them before
customers encounter the vulnerabilities).
For this tutorial, I'll assume that you're using a Unix-like system,
such as Linux, OpenBSD, or MacOS X.
.PP
If the source code is in a subdirectory named xyzzy, you would probably
start by opening a text window and using flawfinder's default settings, to
analyze the program and report a prioritized list of potential
security vulnerabilities (the ``less'' just makes sure the results
stay on the screen):
.RS
flawfinder xyzzy | less
.RE
.PP
At this point, you will a large number of entries;
each entry begins with a filename, a colon, a line number, a
risk level in brackets (where 5 is the most risky), a category,
the name of the function, and
a description of why flawfinder thinks the line is a vulnerability.
Flawfinder normally sorts by risk level, showing the riskiest items
first; if you have limited time, it's probably best to start working on
the riskiest items and continue until you run out of time.
If you want to limit the display to risks with only
a certain risk level or higher, use
the \-\-minlevel option.
If you're getting an extraordinary number of false positives because
variable names look like dangerous function names, use the \-F option
to remove reports about them.
If you don't understand the error message, please see documents such as the
.UR "http://www.dwheeler.com/secure-programs"
.I "Writing Secure Programs for Linux and Unix HOWTO"
.UE
at
http://www.dwheeler.com/secure-programs
which provides more information on writing secure programs.
.PP
Once you identify the problem and understand it, you can fix it.
Occasionally you may want to re-do the analysis, both because the
line numbers will change \fIand\fP to make sure that the new code
doesn't introduce yet a different vulnerability.
.PP
If you've determined that some line isn't really a problem, and
you're sure of it, you can insert just before or on the offending
line a comment like
.RS
/* Flawfinder: ignore */
.RE
to keep them from showing up in the output.
.PP
Once you've done that, you should go back and search for the
program's inputs, to make sure that the program strongly filters
any of its untrusted inputs.
Flawfinder can identify many program inputs by using the \-\-inputs
option, like this:
.RS
flawfinder \-\-inputs xyzzy
.RE
.PP
Flawfinder can integrate well with text editors and
integrated development environments; see the examples for
more information.
.PP
Flawfinder includes many other options, including ones to
create HTML versions of the output (useful for prettier displays).
The next section describes those options in more detail.
.SH OPTIONS
Flawfinder has a number of options, which can be grouped into options that
control its own documentation,
select which hits to display,
select the output format,
and perform hitlist management.
.SS "Documentation"
.TP 12
.BI \-\-help
.\" Leave -h and -? undocumented... they also invoke help, but it's
.\" easier just to document the single help option.
Show usage (help) information.
.TP
.BI \-\-version
Shows (just) the version number and exits.
.SS "Selecting Hits to Display"
.TP 12
.BI \-\-allowlink
Allow the use of symbolic links; normally symbolic links are skipped.
Don't use this option if you're analyzing code by others;
attackers could do many things to cause problems for an analysis
with this option enabled.
For example, an attacker
could insert symbolic links to files such as /etc/passwd
(leaking information about the file) or create a circular loop,
which would cause flawfinder to run ``forever''.
Another problem with enabling this option is that
if the same file is referenced multiple times using symbolic links,
it will be analyzed multiple times (and thus reported multiple times).
Note that flawfinder already includes some protection against symbolic links
to special file types such as device file types (e.g., /dev/zero or
C:\\mystuff\\com1).
Note that for flawfinder version 1.01 and before, this was the default.
.TP
.BI "\-\-inputs"
.TP
.BI \-I
Show only functions that obtain data from outside the program;
this also sets minlevel to 0.
.TP
\fB\-\-minlevel=\fIX\fR
.TP
.BI -m " X"
Set minimum risk level to X for inclusion in hitlist.
This can be from 0 (``no risk'') to 5 (``maximum risk'');
the default is 1.
.TP
.BI "\-\-falsepositive"
.TP
.BI \-F
Do not include hits that are likely to be false positives.
Currently, this means that function names are ignored if they're
not followed by "(", and that declarations of character arrays aren't
noted.
Thus, if you have use a variable named "access" everywhere, this will
eliminate references to this ordinary variable.
This isn't the default, because this also increases the likelihood
of missing important hits; in particular, function names in #define
clauses and calls through function pointers will be missed.
.TP
.BI \-\-neverignore
.TP
.BI -n
Never ignore security issues, even if they have an ``ignore'' directive
in a comment.
.SS "Selecting Output Format"
.TP 12
.BI \-\-columns
.TP
.BI \-C
Show the column number (as well as the file name and line number)
of each hit; this is shown after the line number by adding a colon
and the column number in the line (the first character in a line is
column number 1).
This is useful for editors that can jump to specific columns, or
for integrating with other tools (such as those to further filter out
false positives).
.TP
.BI \-\-context
.TP
.BI \-c
Show context, i.e., the line having the "hit"/potential flaw.
By default the line is shown immediately after the warning.
.TP
.BI "\-\-dataonly"
.TP
.BI \-D
Don't display the header and footer.
Use this along with \-\-quiet to see just the data itself.
.TP
.BI \-\-html
Format the output as HTML instead of as simple text.
.TP
.BI "\-\-immediate"
.TP
.BI -i
Immediately display hits (don't just wait until the end).
.TP
.BI "\-\-singleline"
.TP
.BI -S
Display as single line of text output for each hit.
Useful for interacting with compilation tools.
.TP
.BI "\-\-omittime"
Omit timing information.
This is useful for regression tests of flawfinder itself, so that
the output doesn't vary depending on how long the analysis takes.
.TP
.BI "\-\-quiet"
.TP
.BI \-Q
Don't display status information (i.e., which files are being examined)
while the analysis is going on.
.SS "Hitlist Management"
.\" This isn't sorted as usual, because logically saving comes
.\" before loading and differencing.
.TP 12
\fB\-\-savehitlist=\fR\fIF\fR
Save all resulting hits (the "hitlist") to F.
.TP
\fB\-\-loadhitlist=\fR\fIF\fR
Load the hitlist from F instead of analyzing source programs.
.TP
\fB\-\-diffhitlist=\fR\fIF\fR
Show only hits (loaded or analyzed) not in F.
F was presumably created previously using \-\-savehitlist.
If the \-\-loadhitlist option is not provided, this will show the hits in
the analyzed source code files that were not previously stored in F.
If used along with \-\-loadhitlist, this will show the hits in the
loaded hitlist not in F.
The difference algorithm is conservative;
hits are only considered the ``same'' if they have the same
filename, line number, column position, function name, and risk level.
.SH EXAMPLES
Here are various examples of how to invoke flawfinder.
The first examples show various simple command-line options.
Flawfinder is designed to work well with text editors and
integrated development environments, so the next sections
show how to integrate flawfinder into vim and emacs.
.SS "Simple command-line options"
.TP 12
.B "flawfinder /usr/src/linux-2.4.12"
Examine all the C/C++ files in the directory
/usr/src/linux-2.4.12 and all its subdirectories (recursively),
reporting on all hits found.
.TP
.B "flawfinder \-\-minlevel=4 ."
Examine all the C/C++ files in the current directory
and its subdirectories (recursively);
only report vulnerabilities level 4 and up (the two highest risk levels).
.TP
.B "flawfinder \-\-inputs mydir"
Examine all the C/C++ files in mydir
and its subdirectories (recursively), and report functions
that take inputs (so that you can ensure that they filter the
inputs appropriately).
.TP
.B "flawfinder \-\-neverignore mydir"
Examine all the C/C++ files in the directory mydir and its subdirectories,
including even the hits marked for ignoring in the code comments.
.TP
.B "flawfinder -QD mydir"
Examine mydir and report only the actual results
(removing the header and footer of the output).
This form is useful
if the output will be piped into other tools for further analysis.
The \-C (\-\-columns) and \-S (\-\-singleline)
options can also be useful if you're piping the data
into other tools.
.TP
.B "flawfinder \-\-quiet \-\-html \-\-context mydir > results.html"
Examine all the C/C++ files in the directory mydir and its subdirectories,
and produce an HTML formatted version of the results.
Source code management systems (such as SourceForge and Savannah)
might use a command like this.
.TP
.B "flawfinder \-\-quiet \-\-savehitlist saved.hits *.[ch]"
Examine all .c and .h files in the current directory.
Don't report on the status of processing, and save the resulting hitlist
(the set of all hits) in the file saved.hits.
.TP
.B "flawfinder \-\-diffhitlist saved.hits *.[ch]"
Examine all .c and .h files in the current directory, and show any
hits that weren't already in the file saved.hits.
This can be used to show only the ``new'' vulnerabilities in a
modified program, if saved.hits was created from the
older version of the program being analyzed.
.SS "Invoking from vim"
.PP
The text editor
vim includes a "quickfix" mechanism that works well with flawfinder,
so that you can easily view the warning messages and jump to
the relevant source code.
.PP
First, you need to invoke flawfinder to create a list of hits, and
there are two ways to do this.
The first way is to start flawfinder first, and then (using its output)
invoke vim.
The second way is to start (or continue to run) vim, and then invoke
flawfinder (typically from inside vim).
.PP
For the first way, run flawfinder and store its output in some
FLAWFILE (say "flawfile"),
then invoke vim using its -q option, like this: "vim -q flawfile".
The second way (starting flawfinder after starting vim) can be done
a legion of ways.
One is to invoke flawfinder using a shell command,
":!flawfinder-command > FLAWFILE", then follow that with the command
":cf FLAWFILE".
Another way is to store the flawfinder command in your makefile
(as, say, a pseudocommand like "flaw"), and then run
":make flaw".
.PP
In all these cases you need a command for flawfinder to run.
A plausible command, which places each hit in its own line (-S) and
removes headers and footers that would confuse it, is:
.PP
.B "flawfinder \-SQD ."
.PP
You can now use various editing commands to view the results.
The command ":cn" displays the next hit; ":cN" displays the
previous hit, and ":cr" rewinds back to the first hit.
":copen" will open a window to show the current list of hits, called
the "quickfix window"; ":cclose" will close the quickfix window.
If the buffer in the used window has changed, and the error is in
another file, jumping to the error will fail.
You have to make sure the window contains a buffer which can be abandoned
before trying to jump to a new file, say by saving the file;
this prevents accidental data loss.
.SS "Invoking from emacs"
The text editor / operating system
emacs includes "grep mode" and "compile mode" mechanisms
that work well with flawfinder, making it easy to
view warning messages, jump to the relevant source code, and fix
any problems you find.
.PP
First, you need to invoke flawfinder to create a list of warning messages.
You can use "grep mode" or "compile mode" to create this list.
Often "grep mode" is more convenient;
it leaves compile mode untouched so you can easily recompile
once you've changed something.
However, if you want to jump to the exact column position of a hit,
compile mode may be more convenient because emacs can use
the column output of flawfinder to directly jump to the right location
without any special configuration.
.PP
To use grep mode,
enter the command "M-x grep"
and then enter the needed flawfinder command.
To use compile mode, enter the command
"M-x compile" and enter the needed flawfinder command.
This is a meta-key command, so you'll need to use the meta key for your
keyboard (this is usually the ESC key).
As with all emacs commands, you'll need to press RETURN after
typing "grep" or "compile".
So on many systems, the grep mode is invoked by typing
ESC x g r e p RETURN.
.PP
You then need to enter a command, removing whatever was there before if
necessary.
A plausible command is:
.PP
.B "flawfinder \-SQDC ."
.PP
This command makes every hit report a single line,
which is much easier for tools to handle.
The quiet and dataonly options remove the other status information not needed
for use inside emacs.
The trailing period means that the current directory and all descendents
are searched for C/C++ code, and analyzed for flaws.
.PP
Once you've invoked flawfinder, you can use emacs to jump around
in its results.
The command C-x \`
(Control-x backtick)
visits the source code location for the next warning message.
C-u C-x \` (control-u control-x backtick)
restarts from the beginning.
You can visit the source for any particular error message by moving
to that hit message in the *compilation* buffer or *grep* buffer
and typing the return key.
(Technical note: in the compilation buffer, this invokes
compile-goto-error).
You can also click the Mouse-2 button on the error message
(when using the mouse you don't need to switch to the *compilation* buffer
first).
.PP
If you want to use grep mode to jump to specific columns of a hit,
you'll need to specially configure emacs to do this.
To do this, modify the emacs variable "grep-regexp-alist".
This variable tells Emacs how to
parse output of a "grep" command, similar to the
variable "compilation-error-regexp-alist" which lists various formats
of compilation error messages.
.SH SECURITY
You should always analyze a \fIcopy\fP of the source program being analyzed,
not a directory that can be modified by a developer while flawfinder
is performing the analysis.
This is \fIespecially\fP true if you don't necessily trust a
developer of the program being analyzed.
If an attacker has control over the files while you're analyzing them,
the attacker could move files around or change their contents to
prevent the exposure of a security problem (or create the impression
of a problem where there is none).
If you're worried about malicious programmers you should do this anyway,
because after analysis you'll need to verify that the code eventually run
is the code you analyzed.
Also, do not use the \-\-allowlink option in such cases;
attackers could create malicious symbolic links to files outside of their
source code area (such as /etc/passwd).
.PP
Source code management systems (like SourceForge and Savannah)
definitely fall into this category; if you're maintaining one of those
systems, first copy or extract the files into a separate directory
(that can't be controlled by attackers)
before running flawfinder or any other code analysis tool.
.PP
Note that flawfinder only opens regular files, directories, and
(if requested) symbolic links; it will never open other kinds of files,
even if a symbolic link is made to them.
This counters attackers who insert unusual file types into the
source code.
However, this only works if the filesystem being analyzed can't
be modified by an attacker during the analysis, as recommended above.
This protection also doesn't work on Cygwin platforms, unfortunately.
.PP
Cygwin systems (Unix emulation on top of Windows)
have an additional problem if flawfinder is used to analyze
programs the analyzer cannot trust
due to a design flaw in Windows (that it inherits from MS-DOS).
On Windows and MS-DOS, certain filenames (e.g., ``com1'') are
automatically treated by the operating system as the names of peripherals,
and this is true even when a full pathname is given.
Yes, Windows and MS-DOS really are designed this badly.
Flawfinder deals with this by checking what a filesystem object is,
and then only opening directories and regular files
(and symlinks if enabled).
Unfortunately, this doesn't work on Cygwin; on at least some versions
of Cygwin on some versions of Windows,
merely trying to determine if a file is a device type
can cause the program to hang.
A workaround is to delete or rename any filenames that are interpreted
as device names before performing the analysis.
These so-called ``reserved names'' are CON, PRN, AUX, CLOCK$, NUL,
COM1-COM9, and LPT1-LPT9, optionally followed by an extension
(e.g., ``com1.txt''), in any directory, and in any case
(Windows is case-insensitive).
.\" See 'Writing Secure Code' by Howard and LeBlanc, pg. 223
.SH BUGS
Flawfinder is currently limited to C/C++.
It's designed so that adding support for other languages should be easy.
.PP
Flawfinder can be fooled by user-defined functions or method names that
happen to be the same as those defined as ``hits'' in its database,
and will often trigger on definitions (as well as uses) of functions
with the same name.
This is because flawfinder is based on text pattern matching, which is
part of its fundamental design and not easily changed.
This isn't as much of a problem for C code, but it can be more of a problem
for some C++ code which heavily uses classes and namespaces.
On the positive side, flawfinder doesn't get confused by many
complicated preprocessor sequences that other tools sometimes choke on.
Also, having the same name as a common library routine name can
indicate that the developer is simply rewriting a common library routine,
say for portability's sake.
Thus, there are reasonable odds that
these rewritten routines will be vulnerable to the same kinds of misuse.
The \-\-falsepositive option can help somewhat.
If this is a serious problem, feel free to modify the program, or process
the flawfinder output through other tools to remove the false positives.
.PP
Preprocessor commands embedded in the middle of a parameter list
of a call can cause problems in parsing, in particular, if a string
is opened and then closed multiple times using an #ifdef .. #else
construct, flawfinder gets confused.
Such constructs are bad style, and will confuse many other tools too.
If you must analyze such files, rewrite those lines.
Thankfully, these are quite rare.
.PP
The routine to detect statically defined character arrays uses
simple text matching; some complicated expresions can cause it to
trigger or not trigger unexpectedly.
.PP
Flawfinder looks for specific patterns known to be common mistakes.
Flawfinder (or any tool like it) is not a good tool for finding intentionally
malicious code (e.g., Trojan horses); malicious programmers can easily
insert code that would not be detected by this kind of tool.
.PP
Flawfinder looks for specific patterns known to be common mistakes
in application code.
Thus, it is likely to be less effective
analyzing programs that aren't application-layer code
(e.g., kernel code or self-hosting code).
The techniques may still be useful; feel free to replace the database
if your situation is significantly different from normal.
.PP
Flawfinder's output format (filename:linenumber, followed optionally
by a :columnnumber) can be misunderstood if any source files have
very weird filenames.
Filenames embedding a newline/linefeed character will cause odd breaks,
and filenames including colon (:) are likely to be misunderstood.
This is especially important if flawfinder's output is being used
by other tools, such as filters or text editors.
If you're looking at new code, examine the files for such characters.
It's incredibly unwise to have such filenames anyway;
many tools can't handle such filenames at all.
Newline and linefeed are often used as internal data delimeters.
The colon is often used as special characters in filesystems:
MacOS uses it as a directory separator, Windows/MS-DOS uses it
to identify drive letters, Windows/MS-DOS inconsistently uses it
to identify special devices like CON:, and applications on many platforms
use the colon to identify URIs/URLs.
Filenames including spaces and/or tabs don't cause problems for flawfinder,
though note that other tools might have problems with them.
.PP
In general, flawfinder attempts to err on the side of caution; it tends
to report hits, so that they can be examined further, instead of silently
ignoring them.
Thus, flawfinder prefers to have false positives (reports that
turn out to not be problems) rather than false negatives
(failure to report on a security vulnerability).
But this is a generality; flawfinder uses simplistic heuristics and
simply can't get everything "right".
.PP
Security vulnerabilities might not be identified as such by flawfinder,
and conversely, some hits aren't really security vulnerabilities.
This is true for all static security scanners, especially those like
flawfinder that use a simple pattern-based approach to identifying problems.
Still, it can serve as a useful aid for humans, helping to identify
useful places to examine further, and that's the point of this tool.
.SH "SEE ALSO"
See the flawfinder website at http://www.dwheeler.com/flawfinder.
You should also see the
.I "Secure Programming for Unix and Linux HOWTO"
at
http://www.dwheeler.com/secure-programs.
.SH AUTHOR
David A. Wheeler (dwheeler@dwheeler.com).

BIN
flawfinder.1.gz Normal file

Binary file not shown.

BIN
flawfinder.pdf Normal file

Binary file not shown.

1464
flawfinder.ps Normal file

File diff suppressed because it is too large Load Diff

46
flawfinder.spec Normal file
View File

@ -0,0 +1,46 @@
Name: flawfinder
Summary: Examines C/C++ source code for security flaws
Version: 1.26
Release: 1
License: GPL
Group: Development/Tools
URL: http://www.dwheeler.com/flawfinder/
Source: http://www.dwheeler.com/flawfinder/%{name}-%{version}.tar.gz
Packager: David A. Wheeler <dwheeler@dwheeler.com>
Requires: python
BuildArch: noarch
BuildRoot: %{_tmppath}/%{name}-%{version}-root
%description
Flawfinder scans through C/C++ source code,
identifying lines ("hits") with potential security flaws.
By default it reports hits sorted by severity, with the riskiest lines first.
Flawfinder is released under the GNU Public License (GPL).
%prep
%setup -q
%build
make
%install
[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT"
install -m755 -D flawfinder ${RPM_BUILD_ROOT}%{_bindir}/flawfinder
install -m644 -D flawfinder.1 ${RPM_BUILD_ROOT}%{_mandir}/man1/flawfinder.1
%clean
[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT"
%files
%defattr(-,root,root)
%doc README ChangeLog COPYING flawfinder.ps
%{_bindir}/*
%{_mandir}/man1/*
%changelog
* Sat Feb 1 2003 Jose Pedro Oliveira <jpo@di.uminho.pt>
- changed build architecture to noarch
- replaced hardcoded directories by rpm macros
- removed several rpmlint warnings/errors
# vim:set ai ts=4 sw=4:

26
flawtest.c Normal file
View File

@ -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]));
}

9
junk.c Normal file
View File

@ -0,0 +1,9 @@
#include <stdio.h>
main() {
char abuf[1000];
FILE *FR = stdin;
fscanf(FR, "%2000s", abuf);
printf("Result = %s\n", abuf);
}

150
makefile Normal file
View File

@ -0,0 +1,150 @@
# Flawfinder. Released under the General Public License (GPL).
# (C) 2001 David A. Wheeler.
# To change version number, edit this here, the beginning of the
# "flawfinder" script, flawfinder.spec, setup.py, and index.html.
# Then "make test-is-correct" to get the updated version number.
# To distribute, "make distribute && su && make rpm".
# Then use make my_install to install to website image.
# Eventually switch to using DistUtils to autogenerate.
NAME=flawfinder
VERSION=1.26
RPM_VERSION=1
VERSIONEDNAME=$(NAME)-$(VERSION)
ARCH=noarch
SAMPLE_DIR=/usr/src/linux-2.2.16
INSTALL_DIR=/usr/local
INSTALL_DIR_BIN=$(INSTALL_DIR)/bin
INSTALL_DIR_MAN=$(INSTALL_DIR)/man/man1
# For Cygwin on Windows, set PYTHONEXT=.py
# (EXE=.exe would be needed on some systems, but not for flawfinder)
EXE=
PYTHONEXT=
# EXE=.exe
# PYTHONEXT=.py
# The rpm build command. "rpmbuild" for rpm version 4.1+
# (e.g., in Red Hat Linux 8), "rpm" for older versions.
RPMBUILD=rpmbuild
all: flawfinder.pdf flawfinder.1.gz
chmod -R a+rX *
# This installer doesn't install the compiled Python bytecode.
# It doesn't take long to compile the short Python code, so
# it doesn't save much time, and having the source code available
# makes it easier to see what it does. It also avoids the
# (admittedly rare) problem of bad date/timestamps causing the
# compiled code to override later uncompiled Python code.
# Note that this uses the "-p" option of mkdir; some very old Unixes
# might not support this option, but it's a really common option
# and required by SUSv3 (and probably earlier, I haven't checked).
install:
-mkdir -p $(INSTALL_DIR_BIN)
cp flawfinder$(PYTHONEXT) $(INSTALL_DIR_BIN)/flawfinder$(PYTHONEXT)
-mkdir -p $(INSTALL_DIR_MAN)
cp flawfinder.1 $(INSTALL_DIR_MAN)/flawfinder.1
uninstall:
rm $(INSTALL_DIR_BIN)/flawfinder$(PYTHONEXT)
rm $(INSTALL_DIR_MAN)/flawfinder.1
flawfinder.1.gz: flawfinder.1
gzip -c9 < flawfinder.1 > flawfinder.1.gz
flawfinder.ps: flawfinder.1
man -t ./flawfinder.1 > flawfinder.ps
flawfinder.pdf: flawfinder.ps
ps2pdf flawfinder.ps flawfinder.pdf
clean:
rm -f *.pyc
rm -f flawfinder-$(VERSION).tar.gz
rm -f *.tar
distribute: clean flawfinder.pdf flawfinder.ps
chmod -R a+rX *
mkdir ,1
cp -p [a-zA-Z]* ,1
rm -f ,1/*.tar.gz
rm -f ,1/*.rpm
# We don't need both "flawfinder" and "flawfinder.py":
rm -f ,1/flawfinder.py
mv ,1 flawfinder-$(VERSION)
# Nobody else needs "update" either.
rm -f ,1/update
# Don't include (out of date) index.html
rm -f ,1/index.html
tar cvfz flawfinder-$(VERSION).tar.gz flawfinder-$(VERSION)
chown --reference=. flawfinder-$(VERSION).tar.gz
rm -fr flawfinder-$(VERSION)
time:
echo "Timing the program. First, time taken:"
time ./flawfinder $(SAMPLE_DIR)/*/*.[ch] > /dev/null
echo "Lines examined:"
wc -l $(SAMPLE_DIR)/*/*.[ch] | tail -2
test: flawfinder test.c test2.c
# Omit time report so that results are always the same textually.
./flawfinder --omittime test.c test2.c > test-results.txt
./flawfinder --omittime --html --context test.c test2.c > test-results.html
less test-results.txt
check:
diff -u correct-results.txt test-results.txt
test-is-correct: test-results.txt
mv test-results.txt correct-results.txt
mv test-results.html correct-results.html
profile:
/usr/lib/python1.5/profile.py ./flawfinder > profile-results $(SAMPLE_DIR)/*/*.[ch] > profile-results
rpm: distribute
chmod -R a+rX *
cp $(VERSIONEDNAME).tar.gz /usr/src/redhat/SOURCES
cp flawfinder.spec /usr/src/redhat/SPECS
cd /usr/src/redhat/SPECS
$(RPMBUILD) -ba flawfinder.spec
chmod a+r /usr/src/redhat/RPMS/$(ARCH)/$(VERSIONEDNAME)-$(RPM_VERSION)*.rpm
chmod a+r /usr/src/redhat/SRPMS/$(VERSIONEDNAME)-$(RPM_VERSION)*.src.rpm
# cp -p /usr/src/redhat/RPMS/$(ARCH)/$(VERSIONEDNAME)-$(RPM_VERSION)*.rpm .
# cp -p /usr/src/redhat/RPMS/$(ARCH)/$(VERSIONEDNAME)-$(RPM_VERSION)*.rpm $(VERSIONEDNAME)-$(RPM_VERSION).noarch.rpm
cp -p /usr/src/redhat/RPMS/$(ARCH)/$(VERSIONEDNAME)-$(RPM_VERSION)*.rpm .
cp -p /usr/src/redhat/SRPMS/$(VERSIONEDNAME)-$(RPM_VERSION)*.src.rpm .
chown --reference=README *.rpm
# Install, for testing. Ignore the "not installed" message here,
# unless you already installed it; we're just removing any old copies:
-rpm -e flawfinder
rpm -ivh /usr/src/redhat/RPMS/$(ARCH)/$(VERSIONEDNAME)-$(RPM_VERSION)*.rpm
echo "Use rpm -e $(NAME) to remove the package"
chown --reference=. *.rpm
my_install: flawfinder.pdf flawfinder.ps
cp -p $(VERSIONEDNAME)-$(RPM_VERSION).$(ARCH).rpm \
$(VERSIONEDNAME)-$(RPM_VERSION).src.rpm \
$(VERSIONEDNAME).tar.gz \
flawfinder makefile \
flawfinder.pdf flawfinder.ps ChangeLog \
test.c test2.c test-results.txt test-results.html \
/home/dwheeler/dwheeler.com/flawfinder
.PHONY: install clean test check profile test-is-correct rpm uninstall distribute
# When I switch to using "DistUtils", I may need to move the MANIFEST.in
# file into a subdirectory (named flawfinder-versionnumber).
# I can then create all the distribution files by just typing:
# python setup.py bdist_rpm

7
setup.cfg Normal file
View File

@ -0,0 +1,7 @@
[bdist_rpm]
release = 1
doc_files = ChangeLog
README
COPYING
flawfinder.ps
flawfinder.pdf

41
setup.py Normal file
View File

@ -0,0 +1,41 @@
#!/usr/bin/env python
# This is the setup.py script for "flawfinder" by David A. Wheeler.
# My thanks to Jon Nelson, who created the initial setup.py script.
# Template for creating your own setup.py. See the USAGE file in
# the Distutils source distribution for descriptions of all the
# options shown below. Brief instructions on what to do:
# - set the other metadata: version, description, author, author_email
# and url. All of these except 'description' are required, although
# you may supply 'maintainer' and 'maintainer_email' in place of (or in
# addition to) 'author' and 'author_email' as appropriate.
# - fill in or delete the 'packages', 'package_dir', 'py_modules',
# and 'ext_modules' options as appropriate -- see USAGE for details
# - delete this comment and change '__revision__' to whatever is
# appropriate for your revision control system of choice (just make
# sure it stores the revision number for your distribution's setup.py
# script, *not* the examples/template_setup.py file from Distutils!)
"""Setup script for the flawfinder tool."""
from distutils.core import setup
import commands
setup (# Distribution meta-data
name = "flawfinder",
version = "1.26",
description = "a program that examines source code looking for security weaknesses",
author = "David A. Wheeler",
author_email = "dwheeler@dwheeler.com",
license = 'GPL',
long_description = """Flawfinder is a program that can scan
C/C++ source code and identify out potential security flaws,
ranking them by likely severity.
It is released under the GNU GPL license.""",
url = "http://www.dwheeler.com/flawfinder/",
scripts = [ 'flawfinder' ],
data_files = [ ('share/man/man1', [ 'flawfinder.1.gz' ]) ],
py_modules = [ ],
)

9
sloctest.c Normal file
View File

@ -0,0 +1,9 @@
/* This is a test. Should produce 6 SLOC.
*/
#include <stdio.h>
#define HI 10
main() {
a = 1; /* hi */
"hi"
}

270
test-results.html Normal file
View File

@ -0,0 +1,270 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf8">
<title>Flawfinder Results</title>
<meta name="author" content="David A. Wheeler">
<meta name="keywords" lang="en" content="flawfinder results, security scan">
</head>
<body>
<h1>Flawfinder Results</h1>
Here are the security scan results from
<a href="http://www.dwheeler.com/flawfinder">Flawfinder version 1.25</a>,
(C) 2001-2004 <a href="http://www.dwheeler.com">David A. Wheeler</a>.
Number of dangerous functions in C/C++ ruleset: 158
<p>
Examining test.c <br>
Examining test2.c <br>
<ul>
<li>test.c:32: <b> [5] </b> (buffer) <i> gets:
Does not check for buffer overflows. Use fgets() instead. </i>
<pre>
gets(f);
</pre>
<li>test.c:56: <b> [5] </b> (buffer) <i> strncat:
Easily used incorrectly (e.g., incorrectly computing the correct
maximum size to add). Consider strlcat or automatically resizing strings.
Risk is high; the length parameter appears to be a constant, instead of
computing the number of characters left. </i>
<pre>
strncat(d,s,sizeof(d)); /* Misuse - this should be flagged as riskier. */
</pre>
<li>test.c:57: <b> [5] </b> (buffer) <i> _tcsncat:
Easily used incorrectly (e.g., incorrectly computing the correct
maximum size to add). Consider strlcat or automatically resizing strings.
Risk is high; the length parameter appears to be a constant, instead of
computing the number of characters left. </i>
<pre>
_tcsncat(d,s,sizeof(d)); /* Misuse - flag as riskier */
</pre>
<li>test.c:60: <b> [5] </b> (buffer) <i> MultiByteToWideChar:
Requires maximum length in CHARACTERS, not bytes. Risk is high, it
appears that the size is given as bytes, but the function requires size as
characters. </i>
<pre>
MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName));
</pre>
<li>test.c:62: <b> [5] </b> (buffer) <i> MultiByteToWideChar:
Requires maximum length in CHARACTERS, not bytes. Risk is high, it
appears that the size is given as bytes, but the function requires size as
characters. </i>
<pre>
MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName);
</pre>
<li>test.c:73: <b> [5] </b> (misc) <i> SetSecurityDescriptorDacl:
Never create NULL ACLs; an attacker can set it to Everyone (Deny All
Access), which would even forbid administrator access. </i>
<pre>
SetSecurityDescriptorDacl(&amp;sd,TRUE,NULL,FALSE);
</pre>
<li>test.c:73: <b> [5] </b> (misc) <i> SetSecurityDescriptorDacl:
Never create NULL ACLs; an attacker can set it to Everyone (Deny All
Access), which would even forbid administrator access. </i>
<pre>
SetSecurityDescriptorDacl(&amp;sd,TRUE,NULL,FALSE);
</pre>
<li>test.c:17: <b> [4] </b> (buffer) <i> strcpy:
Does not check for buffer overflows when copying to destination.
Consider using strncpy or strlcpy (warning, strncpy is easily misused). </i>
<pre>
strcpy(b, a);
</pre>
<li>test.c:20: <b> [4] </b> (buffer) <i> sprintf:
Does not check for buffer overflows. Use snprintf or vsnprintf. </i>
<pre>
sprintf(s, "hello %s", bug);
</pre>
<li>test.c:21: <b> [4] </b> (buffer) <i> sprintf:
Does not check for buffer overflows. Use snprintf or vsnprintf. </i>
<pre>
sprintf(s, gettext("hello %s"), bug);
</pre>
<li>test.c:22: <b> [4] </b> (format) <i> sprintf:
Potential format string problem. Make format string constant. </i>
<pre>
sprintf(s, unknown, bug);
</pre>
<li>test.c:23: <b> [4] </b> (format) <i> printf:
If format strings can be influenced by an attacker, they can be
exploited. Use a constant for the format specification. </i>
<pre>
printf(bf, x);
</pre>
<li>test.c:25: <b> [4] </b> (buffer) <i> scanf:
The scanf() family's %s operation, without a limit specification,
permits buffer overflows. Specify a limit to %s, or use a different input
function. </i>
<pre>
scanf("%s", s);
</pre>
<li>test.c:27: <b> [4] </b> (buffer) <i> scanf:
The scanf() family's %s operation, without a limit specification,
permits buffer overflows. Specify a limit to %s, or use a different input
function. </i>
<pre>
scanf("%s", s);
</pre>
<li>test.c:38: <b> [4] </b> (format) <i> syslog:
If syslog's format strings can be influenced by an attacker, they can
be exploited. Use a constant format string for syslog. </i>
<pre>
syslog(LOG_ERR, attacker_string);
</pre>
<li>test.c:49: <b> [4] </b> (buffer) <i> _mbscpy:
Does not check for buffer overflows when copying to destination.
Consider using a function version that stops copying at the end of the
buffer. </i>
<pre>
_mbscpy(d,s); /* like strcpy, this doesn't check for buffer overflow */
</pre>
<li>test.c:52: <b> [4] </b> (buffer) <i> lstrcat:
Does not check for buffer overflows when concatenating to destination. </i>
<pre>
lstrcat(d,s);
</pre>
<li>test.c:75: <b> [3] </b> (shell) <i> CreateProcess:
This causes a new process to execute and is difficult to use safely.
Specify the application path in the first argument, NOT as part of the
second, or embedded spaces could allow an attacker to force a different
program to run. </i>
<pre>
CreateProcess(NULL, "C:\\Program Files\\GoodGuy\\GoodGuy.exe -x", "");
</pre>
<li>test.c:75: <b> [3] </b> (shell) <i> CreateProcess:
This causes a new process to execute and is difficult to use safely.
Specify the application path in the first argument, NOT as part of the
second, or embedded spaces could allow an attacker to force a different
program to run. </i>
<pre>
CreateProcess(NULL, "C:\\Program Files\\GoodGuy\\GoodGuy.exe -x", "");
</pre>
<li>test.c:91: <b> [3] </b> (buffer) <i> getopt_long:
Some older implementations do not protect against internal buffer
overflows . Check implementation on installation, or limit the size of all
string inputs. </i>
<pre>
while ((optc = getopt_long (argc, argv, "a",longopts, NULL )) != EOF) {
</pre>
<li>test.c:16: <b> [2] </b> (buffer) <i> strcpy:
Does not check for buffer overflows when copying to destination.
Consider using strncpy or strlcpy (warning, strncpy is easily misused). Risk
is low because the source is a constant string. </i>
<pre>
strcpy(a, gettext("Hello there")); // Did this work?
</pre>
<li>test.c:19: <b> [2] </b> (buffer) <i> sprintf:
Does not check for buffer overflows. Use snprintf or vsnprintf. Risk
is low because the source has a constant maximum length. </i>
<pre>
sprintf(s, "hello");
</pre>
<li>test.c:45: <b> [2] </b> (buffer) <i> char:
Statically-sized arrays can be overflowed. Perform bounds checking,
use functions that limit length, or ensure that the size is larger than
the maximum possible length. </i>
<pre>
char d[20];
</pre>
<li>test.c:46: <b> [2] </b> (buffer) <i> char:
Statically-sized arrays can be overflowed. Perform bounds checking,
use functions that limit length, or ensure that the size is larger than
the maximum possible length. </i>
<pre>
char s[20];
</pre>
<li>test.c:50: <b> [2] </b> (buffer) <i> memcpy:
Does not check for buffer overflows when copying to destination. Make
sure destination can always hold the source data. </i>
<pre>
memcpy(d,s);
</pre>
<li>test.c:51: <b> [2] </b> (buffer) <i> CopyMemory:
Does not check for buffer overflows when copying to destination. Make
sure destination can always hold the source data. </i>
<pre>
CopyMemory(d,s);
</pre>
<li>test.c:97: <b> [2] </b> (misc) <i> 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?. </i>
<pre>
f = fopen("/etc/passwd", "r");
</pre>
<li>test.c:15: <b> [1] </b> (buffer) <i> strcpy:
Does not check for buffer overflows when copying to destination.
Consider using strncpy or strlcpy (warning, strncpy is easily misused). Risk
is low because the source is a constant character. </i>
<pre>
strcpy(a, "\n"); // Did this work?
</pre>
<li>test.c:18: <b> [1] </b> (buffer) <i> sprintf:
Does not check for buffer overflows. Use snprintf or vsnprintf. Risk
is low because the source is a constant character. </i>
<pre>
sprintf(s, "\n");
</pre>
<li>test.c:26: <b> [1] </b> (buffer) <i> scanf:
it's unclear if the %s limit in the format string is small enough.
Check that the limit is sufficiently small, or use a different input
function. </i>
<pre>
scanf("%10s", s);
</pre>
<li>test.c:53: <b> [1] </b> (buffer) <i> strncpy:
Easily used incorrectly; doesn't always \0-terminate or check for
invalid pointers. </i>
<pre>
strncpy(d,s);
</pre>
<li>test.c:54: <b> [1] </b> (buffer) <i> _tcsncpy:
Easily used incorrectly; doesn't always \0-terminate or check for
invalid pointers. </i>
<pre>
_tcsncpy(d,s);
</pre>
<li>test.c:55: <b> [1] </b> (buffer) <i> strncat:
Easily used incorrectly (e.g., incorrectly computing the correct
maximum size to add). Consider strlcat or automatically resizing strings. </i>
<pre>
strncat(d,s,10);
</pre>
<li>test.c:58: <b> [1] </b> (buffer) <i> strlen:
Does not handle strings that are not \0-terminated (it could cause a
crash if unprotected). </i>
<pre>
n = strlen(d);
</pre>
<li>test.c:64: <b> [1] </b> (buffer) <i> MultiByteToWideChar:
Requires maximum length in CHARACTERS, not bytes. Risk is very low,
the length appears to be in characters not bytes. </i>
<pre>
MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName)/sizeof(wszUserName[0]));
</pre>
<li>test.c:66: <b> [1] </b> (buffer) <i> MultiByteToWideChar:
Requires maximum length in CHARACTERS, not bytes. Risk is very low,
the length appears to be in characters not bytes. </i>
<pre>
MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName /sizeof(wszUserName[0]));
</pre>
</ul>
<p>
Hits = 36
<br>
Lines analyzed = 118
<br>
Physical Source Lines of Code (SLOC) = 80
<br>
Hits@level = [0] 0 [1] 9 [2] 7 [3] 3 [4] 10 [5] 7 <br>
Hits@level+ = [0+] 36 [1+] 36 [2+] 27 [3+] 20 [4+] 17 [5+] 7 <br>
Hits/KSLOC@level+ = [0+] 450 [1+] 450 [2+] 337.5 [3+] 250 [4+] 212.5 [5+] 87.5 <br>
Suppressed hits = 2 (use --neverignore to show them)
<br>
Minimum risk level = 1
<br>
Not every hit is necessarily a security vulnerability.
<br>
There may be other security vulnerabilities; review your code!
</body>
</html>

139
test-results.txt Normal file
View File

@ -0,0 +1,139 @@
Flawfinder version 1.25, (C) 2001-2004 David A. Wheeler.
Number of dangerous functions in C/C++ ruleset: 158
Examining test.c
Examining test2.c
test.c:32: [5] (buffer) gets:
Does not check for buffer overflows. Use fgets() instead.
test.c:56: [5] (buffer) strncat:
Easily used incorrectly (e.g., incorrectly computing the correct
maximum size to add). Consider strlcat or automatically resizing strings.
Risk is high; the length parameter appears to be a constant, instead of
computing the number of characters left.
test.c:57: [5] (buffer) _tcsncat:
Easily used incorrectly (e.g., incorrectly computing the correct
maximum size to add). Consider strlcat or automatically resizing strings.
Risk is high; the length parameter appears to be a constant, instead of
computing the number of characters left.
test.c:60: [5] (buffer) MultiByteToWideChar:
Requires maximum length in CHARACTERS, not bytes. Risk is high, it
appears that the size is given as bytes, but the function requires size as
characters.
test.c:62: [5] (buffer) MultiByteToWideChar:
Requires maximum length in CHARACTERS, not bytes. Risk is high, it
appears that the size is given as bytes, but the function requires size as
characters.
test.c:73: [5] (misc) SetSecurityDescriptorDacl:
Never create NULL ACLs; an attacker can set it to Everyone (Deny All
Access), which would even forbid administrator access.
test.c:73: [5] (misc) SetSecurityDescriptorDacl:
Never create NULL ACLs; an attacker can set it to Everyone (Deny All
Access), which would even forbid administrator access.
test.c:17: [4] (buffer) strcpy:
Does not check for buffer overflows when copying to destination.
Consider using strncpy or strlcpy (warning, strncpy is easily misused).
test.c:20: [4] (buffer) sprintf:
Does not check for buffer overflows. Use snprintf or vsnprintf.
test.c:21: [4] (buffer) sprintf:
Does not check for buffer overflows. Use snprintf or vsnprintf.
test.c:22: [4] (format) sprintf:
Potential format string problem. Make format string constant.
test.c:23: [4] (format) printf:
If format strings can be influenced by an attacker, they can be
exploited. Use a constant for the format specification.
test.c:25: [4] (buffer) scanf:
The scanf() family's %s operation, without a limit specification,
permits buffer overflows. Specify a limit to %s, or use a different input
function.
test.c:27: [4] (buffer) scanf:
The scanf() family's %s operation, without a limit specification,
permits buffer overflows. Specify a limit to %s, or use a different input
function.
test.c:38: [4] (format) syslog:
If syslog's format strings can be influenced by an attacker, they can
be exploited. Use a constant format string for syslog.
test.c:49: [4] (buffer) _mbscpy:
Does not check for buffer overflows when copying to destination.
Consider using a function version that stops copying at the end of the
buffer.
test.c:52: [4] (buffer) lstrcat:
Does not check for buffer overflows when concatenating to destination.
test.c:75: [3] (shell) CreateProcess:
This causes a new process to execute and is difficult to use safely.
Specify the application path in the first argument, NOT as part of the
second, or embedded spaces could allow an attacker to force a different
program to run.
test.c:75: [3] (shell) CreateProcess:
This causes a new process to execute and is difficult to use safely.
Specify the application path in the first argument, NOT as part of the
second, or embedded spaces could allow an attacker to force a different
program to run.
test.c:91: [3] (buffer) getopt_long:
Some older implementations do not protect against internal buffer
overflows . Check implementation on installation, or limit the size of all
string inputs.
test.c:16: [2] (buffer) strcpy:
Does not check for buffer overflows when copying to destination.
Consider using strncpy or strlcpy (warning, strncpy is easily misused). Risk
is low because the source is a constant string.
test.c:19: [2] (buffer) sprintf:
Does not check for buffer overflows. Use snprintf or vsnprintf. Risk
is low because the source has a constant maximum length.
test.c:45: [2] (buffer) char:
Statically-sized arrays can be overflowed. Perform bounds checking,
use functions that limit length, or ensure that the size is larger than
the maximum possible length.
test.c:46: [2] (buffer) char:
Statically-sized arrays can be overflowed. Perform bounds checking,
use functions that limit length, or ensure that the size is larger than
the maximum possible length.
test.c:50: [2] (buffer) memcpy:
Does not check for buffer overflows when copying to destination. Make
sure destination can always hold the source data.
test.c:51: [2] (buffer) CopyMemory:
Does not check for buffer overflows when copying to destination. Make
sure destination can always hold the source data.
test.c:97: [2] (misc) fopen:
Check when opening files - can an attacker redirect it (via symlinks),
force the opening of special file type (e.g., device files), move
things around to create a race condition, control its ancestors, or change
its contents?.
test.c:15: [1] (buffer) strcpy:
Does not check for buffer overflows when copying to destination.
Consider using strncpy or strlcpy (warning, strncpy is easily misused). Risk
is low because the source is a constant character.
test.c:18: [1] (buffer) sprintf:
Does not check for buffer overflows. Use snprintf or vsnprintf. Risk
is low because the source is a constant character.
test.c:26: [1] (buffer) scanf:
it's unclear if the %s limit in the format string is small enough.
Check that the limit is sufficiently small, or use a different input
function.
test.c:53: [1] (buffer) strncpy:
Easily used incorrectly; doesn't always \0-terminate or check for
invalid pointers.
test.c:54: [1] (buffer) _tcsncpy:
Easily used incorrectly; doesn't always \0-terminate or check for
invalid pointers.
test.c:55: [1] (buffer) strncat:
Easily used incorrectly (e.g., incorrectly computing the correct
maximum size to add). Consider strlcat or automatically resizing strings.
test.c:58: [1] (buffer) strlen:
Does not handle strings that are not \0-terminated (it could cause a
crash if unprotected).
test.c:64: [1] (buffer) MultiByteToWideChar:
Requires maximum length in CHARACTERS, not bytes. Risk is very low,
the length appears to be in characters not bytes.
test.c:66: [1] (buffer) MultiByteToWideChar:
Requires maximum length in CHARACTERS, not bytes. Risk is very low,
the length appears to be in characters not bytes.
Hits = 36
Lines analyzed = 118
Physical Source Lines of Code (SLOC) = 80
Hits@level = [0] 0 [1] 9 [2] 7 [3] 3 [4] 10 [5] 7
Hits@level+ = [0+] 36 [1+] 36 [2+] 27 [3+] 20 [4+] 17 [5+] 7
Hits/KSLOC@level+ = [0+] 450 [1+] 450 [2+] 337.5 [3+] 250 [4+] 212.5 [5+] 87.5
Suppressed hits = 2 (use --neverignore to show them)
Minimum risk level = 1
Not every hit is necessarily a security vulnerability.
There may be other security vulnerabilities; review your code!

117
test.c Normal file
View File

@ -0,0 +1,117 @@
/* Test flawfinder. This program won't compile or run; that's not necessary
for this to be a useful test. */
#include <stdio.h>
#define hello(x) goodbye(x)
#define WOKKA "stuff"
main() {
printf("hello\n");
}
/* This is a strcpy test. */
int demo(char *a, char *b) {
strcpy(a, "\n"); // Did this work?
strcpy(a, gettext("Hello there")); // Did this work?
strcpy(b, a);
sprintf(s, "\n");
sprintf(s, "hello");
sprintf(s, "hello %s", bug);
sprintf(s, gettext("hello %s"), bug);
sprintf(s, unknown, bug);
printf(bf, x);
scanf("%d", &x);
scanf("%s", s);
scanf("%10s", s);
scanf("%s", s);
gets(f); // Flawfinder: ignore
printf("\\");
/* Flawfinder: ignore */
gets(f);
gets(f);
/* These are okay, but flawfinder version < 0.20 incorrectly used
the first parameter as the parameter for the format string */
syslog(LOG_ERR,"cannot open config file (%s): %s",filename,strerror(errno))
syslog(LOG_CRIT,"malloc() failed");
/* But this one SHOULD trigger a warning. */
syslog(LOG_ERR, attacker_string);
}
demo2() {
char d[20];
char s[20];
int n;
_mbscpy(d,s); /* like strcpy, this doesn't check for buffer overflow */
memcpy(d,s);
CopyMemory(d,s);
lstrcat(d,s);
strncpy(d,s);
_tcsncpy(d,s);
strncat(d,s,10);
strncat(d,s,sizeof(d)); /* Misuse - this should be flagged as riskier. */
_tcsncat(d,s,sizeof(d)); /* Misuse - flag as riskier */
n = strlen(d);
/* This is wrong, and should be flagged as risky: */
MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName));
/* This is also wrong, and should be flagged as risky: */
MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName);
/* This is much better: */
MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof(wszUserName)/sizeof(wszUserName[0]));
/* This is much better: */
MultiByteToWideChar(CP_ACP,0,szName,-1,wszUserName,sizeof wszUserName /sizeof(wszUserName[0]));
/* This is an example of bad code - the third paramer is NULL, so it creates
a NULL ACL. Note that Flawfinder can't detect when a
SECURITY_DESCRIPTOR structure is manually created with a NULL value
as the ACL; doing so would require a tool that handles C/C++
and knows about types more that flawfinder currently does.
Anyway, this needs to be detected: */
SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE);
/* This one is a bad idea - first param shouldn't be NULL */
CreateProcess(NULL, "C:\\Program Files\\GoodGuy\\GoodGuy.exe -x", "");
/* Test interaction of quote characters */
printf("%c\n", 'x');
printf("%c\n", '"');
printf("%c\n", '\"');
printf("%c\n", '\'');
printf("%c\n", '\177');
printf("%c\n", '\xfe');
printf("%c\n", '\xd');
printf("%c\n", '\n');
printf("%c\n", '\\');
printf("%c\n", "'");
}
int getopt_example(int argc,char *argv[]) {
while ((optc = getopt_long (argc, argv, "a",longopts, NULL )) != EOF) {
}
}
int testfile() {
FILE *f;
f = fopen("/etc/passwd", "r");
fclose(f);
}
/* Regression test: handle \\\n after end of string */
#define assert(x) {\
if (!(x)) {\
fprintf(stderr,"Assertion failed.\n"\
"File: %s\nLine: %d\n"\
"Assertion: %s\n\n"\
,__FILE__,__LINE__,#x);\
exit(1);\
};\
}
int accesstest() {
int access = 0; /* Not a function call. Should be caught by the
false positive test, and NOT labelled as a problem. */
}

1
test2.c Normal file
View File

@ -0,0 +1 @@
/* Here's a file with no contents to try */