old-www/HOWTO/Secure-Programs-HOWTO/c-cpp.html

310 lines
8.4 KiB
HTML

<HTML
><HEAD
><TITLE
>C/C++</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.7"><LINK
REL="HOME"
TITLE="Secure Programming for Linux and Unix HOWTO"
HREF="index.html"><LINK
REL="UP"
TITLE="Language-Specific Issues"
HREF="language-specific.html"><LINK
REL="PREVIOUS"
TITLE="Language-Specific Issues"
HREF="language-specific.html"><LINK
REL="NEXT"
TITLE="Perl"
HREF="perl.html"></HEAD
><BODY
CLASS="SECT1"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Secure Programming for Linux and Unix HOWTO</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="language-specific.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Chapter 10. Language-Specific Issues</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="perl.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="C-CPP"
></A
>10.1. C/C++</H1
><P
>It is possible to develop secure code using C or C++, but both
languages include fundamental design decisions that make it
more difficult to write secure code.
C and C++ easily permit buffer overflows, force programmers to do their
own memory management, and are fairly lax in their typing systems.
For systems programs (such as an operating system kernel),
C and C++ are fine choices.
For applications, C and C++ are often over-used.
Strongly consider using an even higher-level language,
at least for the majority of the application.
But clearly, there are many existing programs in C and C++
which won't get completely rewritten, and many developers may choose
to develop in C and C++.</P
><P
>One of the biggest security problems with C and C++ programs is
buffer overflow; see <A
HREF="buffer-overflow.html"
>Chapter 6</A
>
for more information.
C has the additional weakness of not supporting exceptions, which makes
it easy to write programs that ignore critical error situations.</P
><P
>Another problem with C and C++ is that developers have to do their
own memory management (e.g., using malloc(), alloc(), free(), new, and delete),
and failing to do it correctly may result in a security flaw.
The more serious problem is that programs may erroneously
free memory that should not be freed (e.g., because it's already been freed).
This can result in an immediate crash or be exploitable, allowing
an attacker to cause arbitrary code to be executed; see
[Anonymous Phrack 2001].
Some systems (such as many GNU/Linux systems) don't protect
against double-freeing at all by default, and it is not clear that those
systems which attempt to protect themselves are truly unsubvertable.
Although I haven't seen anything written on the subject, I suspect that
using the incorrect call in C++ (e.g., mixing new and malloc()) could
have similar effects.
For example, on March 11, 2002, it was announced that the zlib
library had this problem, affecting the many programs that use it.
Thus, when testing programs on GNU/Linux,
you should set the environment variable
MALLOC_CHECK_ to 1 or 2, and you might consider executing your program
with that environment variable set with 0, 1, 2.
The reason for this variable is explained in GNU/Linux malloc(3) man page:
<A
NAME="AEN1687"
></A
><BLOCKQUOTE
CLASS="BLOCKQUOTE"
><P
>Recent versions of Linux libc (later than 5.4.23) and
GNU libc (2.x) include a malloc implementation which is tunable
via environment variables.
When MALLOC_CHECK_ is set, a special (less efficient) implementation
is used which is designed to be tolerant against simple errors,
such as double calls of free() with the same argument,
or overruns of a single byte (off-by-one bugs).
Not all such errors can be protected against, however, and memory leaks
can result.
If MALLOC_CHECK_ is set to 0, any detected heap corruption
is silently ignored;
if set to 1, a diagnostic is printed on stderr;
if set to 2, abort() is called immediately.
This can be useful because otherwise a crash may happen much later,
and the true cause for the problem is then very hard to track down. </P
></BLOCKQUOTE
>
There are various tools to deal with this, such as
Electric Fence and Valgrind;
see <A
HREF="tools.html"
>Section 11.7</A
> for more information.
If unused memory is not free'd, (e.g., using free()), that unused memory
may accumulate - and if enough unused memory can accumulate, the
program may stop working.
As a result, the unused memory may be exploitable by attackers to
create a denial of service.
It's theoretically possible for attackers to cause memory to be
fragmented and cause a denial of service, but usually this
is a fairly impractical and low-risk attack.</P
><P
>Be as strict as you reasonably can when you declare types.
Where you can, use ``enum'' to define enumerated values (and not
just a ``char'' or ``int'' with special values).
This is particularly useful for values in switch statements, where
the compiler can be used to determine if all legal values have been covered.
Where it's appropriate, use ``unsigned'' types if the value can't be
negative.</P
><P
>One complication in C and C++ is that the character type ``char'' can be
signed or unsigned (depending on the compiler and machine).
When a signed char with its high bit set
is saved in an integer, the result will be a negative number;
in some cases this can be exploitable.
In general, use ``unsigned char'' instead of char or signed char for
buffers, pointers, and casts when
dealing with character data that may have values greater than 127 (0x7f).</P
><P
>C and C++ are by definition rather lax in their type-checking support, but
you can at least increase their level of checking so that some mistakes
can be detected automatically.
Turn on as many compiler warnings as you can and change the code to cleanly
compile with them, and strictly use ANSI prototypes in separate header
(.h) files to ensure that all function calls use the correct types.
For C or C++ compilations using gcc, use at least
the following as compilation flags (which turn on a host of warning messages)
and try to eliminate all warnings (note that -O2 is used since some
warnings can only be detected by the data flow analysis performed at
higher optimization levels):
<TABLE
BORDER="1"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="SCREEN"
>gcc -Wall -Wpointer-arith -Wstrict-prototypes -O2</PRE
></FONT
></TD
></TR
></TABLE
>
You might want ``-W -pedantic'' too.</P
><P
>Many C/C++ compilers can detect inaccurate format strings.
For example,
gcc can warn about inaccurate format strings for functions you create
if you use its __attribute__() facility (a C extension) to mark such functions,
and you can use that facility without making your code non-portable.
Here is an example of what you'd put in your header (.h) file:
<TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
> /* in header.h */
#ifndef __GNUC__
# define __attribute__(x) /*nothing*/
#endif
extern void logprintf(const char *format, ...)
__attribute__((format(printf,1,2)));
extern void logprintva(const char *format, va_list args)
__attribute__((format(printf,1,0)));</PRE
></FONT
></TD
></TR
></TABLE
>
The "format" attribute takes either "printf" or "scanf", and the numbers
that follow are the parameter number of the format string and the first
variadic parameter (respectively). The GNU docs talk about this well.
Note that there are other __attribute__ facilities as well,
such as "noreturn" and "const".</P
><P
>Avoid common errors made by C/C++ developers.
For example, be careful about not using ``='' when you mean ``==''.</P
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="language-specific.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="index.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="perl.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Language-Specific Issues</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="language-specific.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Perl</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>