Secure Coding in C and C++, Second Edition

Write secure C and C++ code—and avoid the software defects most likely to cause exploitable vulnerabilities. Secure Coding in C and C++ (2nd Edition) identifies the root causes of today's most widespread software vulnerabilities, shows how they can be exploited, reviews the potential consequences, and presents secure alternatives.

Fully updated for the new C++11 standard, Secure Coding in C and C++, Second Edition presents extensive new coverage of strings, dynamic memory management, integer security, and many other topics—including an entirely new chapter on writing secure concurrent code. It contains hundreds of Windows- and Linux-based examples of secure code, insecure code, and exploits; comprehensive practical guidance for adopting modern security best practices; and important new insights for developing a security mindset that can help you protect software against tomorrow's attacks, not just today's.

This edition also provides unique access to the CERT Online Learning Initiative (OLI) course on secure coding, originally funded by Cisco, Siemens, and other industry leaders to provide internal training to their own mission-critical developers. For every C/C++ developer who wants to write more secure code.

Related Training, Products, and Tools

Secure Coding in C and C++ Training Course
This four-day course provides a detailed explanation of common programming errors in C and C++ and describes how these errors can lead to code that is vulnerable to exploitation. The course concentrates on security issues intrinsic to the C and C++ programming languages and associated libraries. The intent is for this course to be useful to anyone involved in developing secure C and C++ programs regardless of the specific application.

Secure Coding Training Course
An ongoing development effort in collaboration with the Software Engineering Institute's CERT Division, this course focuses on common security issues in C and C++ development. With security expert Robert Seacord serving as lead content author, the course addresses a key need in professional education for software developers. Topics to be covered include the secure and insecure use of integers, arrays, strings, dynamic memory, formatted input/output functions, and file I/O. Continued development is being funded by partnerships with industry.

Source Code Analysis Laboratory (SCALe)
SCALe consists of commercial, open source, and experimental analysis that is used to analyze various code bases, including those from the DoD, energy delivery systems, medical devices, and more. SCALe provides value to the customer, but it also aids research into the effectiveness of coding rules and analysis.

Rosecheckers Tool
The CERT Division's Rosecheckers tool performs static analysis on C/C++ source files. It is designed to enforce the rules in the CERT C Coding standard.

Integer Security Tool
The CERT Division's Secure Coding researchers are working on a number of solutions for addressing the issue of integer security, including our prototype tool and a secure integer library.

Robert C. Seacord is a computer scientist, computer security specialist, and writer. He is the author of books on computer security, legacy system modernization, and component-based software engineering. He has a bachelor's degree in computer science from Rensselaer Polytechnic Institute.

Seacord manages the Secure Coding Initiative at the CERT Division, which is part of Carnegie Mellon University's Software Engineering Institute (SEI) in Pittsburgh, PA. The CERT Division, among other security related activities, regularly analyzes software vulnerability reports and assesses the risk to the internet and other critical infrastructure. Robert is an adjunct professor in the Carnegie Mellon University School of Computer Science and also in the Information Networking Institute.

Robert started programming professionally for IBM in 1982, working in communications and operating system software, processor development, and software engineering. Robert also has worked at the X Consortium, where he developed and maintained code for the Common Desktop Environment and the X Window System.

Current and former members of the CERT staff who contributed to the development of this book are pictured to the right. From left to right: Daniel Plakosh, Archie Andrews, David Svoboda, Dean Sutherland, Brad Rubbo, Jason Rafail, Robert Seacord, and Chad Dougherty.

Foreword

Preface

About the Author

Chapter 1: Running with Scissors

1.1 Gauging the Threat
What Is the Cost?
Who Is the Threat?
Software Security

[Charney 2003]
Charney, S. "Prepared Testimony of Scott Charney," Chief Trustworthy Computing Strategist, Microsoft Corporation, before the Subcommittee on Commerce, Trade and Consumer Protection House Committee on Energy and Commerce. U.S. House of Representatives, Hearing on Cybersecurity and Consumer Data: What's at Risk for the Consumer? November 2003.

[CSIS 2008]
Center for Strategic and International Studies (CSIS). "Securing Cyberspace for the 44th Presidency: A Report of the CSIS Commission on Cybersecurity for the 44th Presidency." Washington, DC: CSIS, 2008.

[Netzer 1990]
Netzer, R. and B. Miller. "On the Complexity of Event Ordering for Shared-Memory Parallel Program Executions." In Proceedings of the 1990 International Conference on Parallel Processing, Pennsylvania State University, University Park, PA, August 1–17, 1990, pp. 93–97. University Park: Pennsylvania State University Press, 1990.

[Pethia 2003a]
Pethia, R. D. "Cyber Security—Growing Risk from Growing Vulnerability." Testimony before the House Select Committee on Homeland Security Subcommittee on Cybersecurity, Science, and Research and Development. Hearing on Overview of the Cyber Problem—A Nation Dependent and Dealing with Risk, 2003.

[Pethia 2003b]
Pethia, R. D. "Viruses and Worms: What Can We Do about Them?" Testimony before the House Committee on Technology, Information Policy, Intergovernmental Relations and the Census. Hearing on Worm and Virus Defense: How Can We Protect the Nation's Computers From These Threats?, 2003.

[Thomas 2002]
Thomas, D. "Cyber Terrorism and Critical Infrastructure Protection." Testimony Before the Committee on House Government Reform Subcommittee on Government Efficiency, Financial Management and Intergovernmental Relations. July 24, 2002.

[Yu 2009]
Yu, F., T. Bultan, and O. H. Ibarra. "Symbolic String Verification: Combining String Analysis and Size Analysis." In Proceedings of the 15th International Conference on Tools and Algorithms for the Construction and Analysis of Systems: Held as Part of the Joint European Conferences on Theory and Practice of Software, York, UK, March 22–29, 2009. Series Lecture Notes in Computer Science. Berlin: Springer-Verlag, 2009.

Please contact us to submit your comments and corrections to the author.

Location

Currently Reads

Should Read

Ch. 1, p. 7, Table 1.1 (first section)

Type of Cybercrime

Global Estimate ($million)

Reference Period

Cost of Genuine Cybercrime
Online banking fraud

320

2007

Phishing

70

2010

Malware
(consumer)

300

2010

Malware
(businesses)

1,000

2010

Bank
technology
countermeasures

97

2008-10

Fake antivirus

22

2010

Copyright-infringing software

150

2011

Copyright-infringing music, etc.

288

2010

Patent-infringing pharmaceutical

10

2011

Stranded traveler scam

200

2011

Fake escrow scam

1,000a

2011

Advance-fee fraud

2011

Type of Cybercrime

Global Estimate ($million)

Reference Period

Cost of Genuine Cybercrime

Online banking fraud

Phishing

320

2007

Malware
(consumer)

70

2010

Malware
(businesses)

300

2010

Bank
technology
countermeasures

1,000

2010

Fake antivirus

97

2008-10

Copyright-infringing software

22

2010

Copyright-infringing music, etc.

150

2011

Patent-infringing pharmaceutical

288

2010

Stranded traveler scam

10

2011

Fake escrow scam

200

2011

Advance-fee fraud

1,000a

2011

Ch. 1, p. 12 (last para)

Therefore, software components cannot have vulnerabilities because they are not executable outside of the context of a program.

However, it is worthwhile to manage security flows in components as vulnerabilities because these components may be reused by many programs.

Reading data from unbounded sources (such as stdin()) creates an interesting problem for a programmer

Reading data from unbounded sources (such as stdin) creates an interesting problem for a programmer.

Ch. 2, p. 46 (para. 4)

The extraction operation can be limited to a specified number of characters (thereby avoiding the possibility of an out-of-bound s write) if the field width inherited member (ios_base::width) is set to a value greater than 0. In this case, the extraction ends one character before the count of characters extracted reaches the value of field width, leaving space for the ending null character. After a call to this extraction operation, the value of the field width is reset to 0.

The lea instruction computes the effective address of the second operand (the source operand) and stores it in the first operand (destination operand).

The lea instruction computes the effective address of the source operand and stores it in the destination operand.

Ch. 2, p. 66

int $0x50

int $0x80

Ch. 2, p. 68

int $80

int $0x80

Ch. 2, p. 73

C11 Annex K bounds-checking interfaces are primarily designed to be safer replacements for existing functions. For example, C11 Annex K defines the strcpy_s(), strcat_s(), strncpy_s(), and strncat_s() functions as replacements for strcpy(), strcat(), strncpy(), and strncat(), respectively, suitable in situations when the length of the source string is not known or guaranteed to be less than the known size of the destination buffer.

C11 Annex K bounds-checking interfaces are primarily designed to be safer replacements for existing functions. For example, C11 Annex K defines the strcpy_s(), strcat_s(), strncpy_s(), and strncat_s() functions as replacements for strcpy(), strcat(), strncpy(), and strncat(). The replacement functions are suitable in situations when the length of the source string is not known. The "replaced" functions remain suitable in situations when the length of the source string is guaranteed to be less than the known size of the destination buffer.

Ch. 2, p. 78 (last line)

The program in Example 2.8 opens a stream to write to memory on line 6.

The program in Example 2.8 opens a stream to write to memory on line 8.

Ch. 2, p. 81

Invalidating String Object References

Demote to level 3 heading

Ch. 2, p. 83

Other Common Mistakes in basic_string Usage

Demote to level 3 heading

Ch. 2, p. 85

It is possible to use fgets() to securely process input lines that are too long to store in the destination array, but this is not recommended for performance reasons.

It is possible to use fgets() to securely process input lines that are too long to store in the destination array.

Ch. 2, p. 91 (Example 2.15)

Example 2.15 shows the Open Watcom implementation of the strcp_s() function. The runtime-constraint error checks are followed by comments.

Example 2.14 shows the Open Watcom implementation of the strcp_s() function. The runtime-constraint error checks are followed by comments.

Ch. 2, p. 92

The strcat_s() function returns 0 on success. However, the destination string is set to the null string and a nonzero value is returned if either the source or destination pointer is NULL or if the maximum length of the destination buffer is equal to 0 or greater than RSIZE_MAX.

The strcat_s() function returns 0 on success. A runtime-constraint violation occurs if the source or destination string is a null pointer, copying takes place between overlapping objects, the maximum length of the destination buffer is equal to 0 or greater than RSIZE_MAX, the destination string is not properly null-terminated, or there is insufficient space remaining in the destination string to copy the source string. If there is a runtime-constraint violation, and the destination string is not a null pointer and the maximum length of the destination buffer is equal to 0 or greater than RSIZE_MAX, then the destination string is set to the null string.

Ch. 2, p. 101

That the function returns the number of elements in the array when no terminating null character is found causes many calculations to be more straightforward.

Many expressions are made less complicated because the function returns the number of elements in the array when no terminating null character is found.

Libsafe and Libverify. Libsafe, available from Avaya Labs Research, is a dynamic library for limiting the impact of buffer overflows on the stack. The library intercepts and checks the bounds of arguments to C library functions that are susceptible to buffer overflow. The library makes sure that frame pointers and return addresses cannot be overwritten by an intercepted function. The Libverify library, also described by Baratloo and colleagues [Baratloo 2000], implements a return address verification scheme similar to Libsafe's but does not require recompilation of source code, which allows it to be used with existing binaries.

Introducing a randomly sized gap of space upon allocation of stack memory makes it more difficult for an attacker to locate a return value on the stack and costs no more than one page of real memory.

Introducing a randomly sized gap of space upon allocation of stack memory makes it more difficult for an attacker to locate a returnaddress on the stack and costs no more than one page of real memory.

Ch. 3, p. 122 (list item 2)

2. For a loop limited by upper bound, a loop limited by Hi, or a loop limited by null terminator, the buffer must be at a lower memory address than the target function or object pointer. For a loop limited by lower bound or a loop limited by Lo, the buffer must be at a lower memory address than the target function or object pointer.

2. For a loop limited by upper bound, a loop limited by Hi, or a loop limited by null terminator, the buffer must be at a lower memory address than the target function or object pointer. For a loop limited by lower bound or a loop limited by Lo, the buffer must be at a higher memory address than the target function or object pointer.

Ch. 3, p. 128, fn 3

IA-32

x86-32

Ch. 3, p. 137 (last para)

EXCEPTION_HANDLER

EXCEPTION_REGISTRATION

Ch. 3, p. 139 (table 3.1)

ebp cbp

ebp of caller

Ch. 3, p. 141

However, this inverse relationship between encode_pointer and decode_pointer()

However, this inverse relationship between encode_pointer() and decode_pointer()

Ch. 4, p. 156 (para. 2)

A write from or read to

A write to or read from

Ch. 4, p. 158 (para. 3)

This technique might also be used to probe error recovery code for double-free vulnerabilities and other security flaws.

There are, however, well-known techniques that are not difficult to adapt to exploit common programming flaws in dynamic memory management. Buffer overflows, for example, can be used to corrupt data structures used by the memory manager to execute arbitrary code. Both the unlink and frontlink techniques described in this section can be used for this purpose.

There are, however, well-known techniques that are not difficult to adapt to exploit common programming flaws in dynamic memory management. Buffer overflows, for example, can be used to corrupt data structures used by the memory manager to execute arbitrary code. Both the unlink technique and the frontlink technique described in the next section can be used for this purpose.

Ch. 4, p. 191 (para.2)

The most difficult part of this exploit is determining the size of the first chunk so that the boundary tag for the second argument can be precisely overwritten.

The most difficult part of this exploit is determining the size of the first chunk so that the boundary tag for the second chunk can be precisely overwritten.

Ch. 5, p. 227 (para. 5)

C requires that unsigned integer types represent values using a pure binary system with no offset. This means that the value of the binary number is

C requires that unsigned integer types represent values using a pure binary system with no offset. This means that the value of the binary number is

Ch. 5, p. 230

If you have counted 32,768 events, you probably do not expect the code to act as if no events occurred after the next event is registered.

If you have counted 32,767 events, you probably do not expect the code to act as if no events occurred after the next event is registered.

Ch. 5, p. 332 (para. 1)

Wide-character formatted output functions are susceptible to format string and buffer overflow vulnerabilities in a similar manner to narrow formatted output functions, even in the extraordinary case where Unicode strings are converted from ASCII.

Delete "extraordinary"

Ch. 5, p. 332 (para. 2)

For example, multibyte-character strings are terminated by a byte with all bits set to 0, called the null character, making it impossible to embed a null byte in the middle of a string.

For example, narrow strings are terminated by a byte with all bits set to 0, called the null character, making it impossible to embed a null byte in the middle of a string.

Ch. 5, p. 233

Starting from the rightmost bit int, the binary representation and increment i from 0 to N, the weight of each bit is 2i, except for the leftmost bit, whose weight is −2i.

Starting from the rightmost bit in the binary representation and incrementingi from 0 to N, the weight of each bit is 2i, except for the leftmost bit, whose weight is −2i.

Ch. 5, p. 253

For example, for an implementation in which the width of int is greater than the width of short, the following code has implementation-defined behavior or may raise an implementation-defined signal:

For example, for an implementation in which the width of long int is greater than the width of signed char, the following code has implementation-defined behavior or may raise an implementation-defined signal:

Ch. 5, p. 253

The following code can be used, for example, to convert from a signed int to a signed char:

The following code can be used, for example, to convert from a signed long int to a signed char:

Ch.5, p. 255

If the value is negative, the resulting unsigned value is evaluated as a large signed integer.

If the value is negative, the resulting unsigned value is evaluated as having a large positive integer.

Ch. 5, p. 255

Table 5.9, Row for "char to unsigned long" conversion, Method column:

Sign-extend to unsigned long; convert long to unsigned long

Table 5.9, Row for "char to unsigned long" conversion, Method column:

Sign-extend to long; convert long to unsigned long

Ch. 5, p. 255

Table 5.9, From column in all four instances: char

Table 5.9, From column in all four instances: signed char

Ch. 5, p. 261

Consequently, the result of any integer operation can be represented in any type with a width greater than the width of the larger addend.

Consequently, the result of any integer addition can be represented in any type with a width greater than the width of the larger addend.

Ch. 5, p. 270 (para. 2)

Ch. 5, p. 281

E1/2E2

E1/2E2

Ch. 5, p. 282

Another way to mitigate buffer overflows in these situations is to use snprintf() in preference to sprintf(), which will truncate the string to the destination size.

Another way to mitigate buffer overflows in these situations is to use snprintf() in preference to sprintf(), which will discard output characters beyond the n-1st character written to the array before appending a null character.

However, without operator overriding, it is necessary to nest function calls to replace normal inline arithmetic operations.

However, without operator overloading, it is necessary to nest function calls to replace normal inline arithmetic operations.

Ch. 6, p. 320

Example 6.5 Stretchable Buffer

Example 6.5 Buffer Expansion

Ch. 5, p. 327

printf("\xdc\xf5\x42\x01%08x.%08x.%08x%n");

Delete the two decimals:
printf("\xdc\xf5\x42\x01%08x%08x%08x%n");

Ch. 5. p. 332 (para. 1)

Wide-character formatted output functions are susceptible to format string and buffer overflow vulnerabilities in a similar manner to narrow formatted output functions, even in the extraordinary case where Unicode strings are converted from ASCII.

Delete "extraordinary"

Ch. 5. p. 332 (para. 2)

For example, multibyte-character strings are terminated by a byte with all bits set to 0, called the null character, making it impossible to embed a null byte in the middle of a string.

For example, narrow strings are terminated by a byte with all bits set to 0, called the null character, making it impossible to embed a null byte in the middle of a string.

If the platform were to write a 16-bit short int, it might do so by writing first the upper 8 bits in one instruction and then the lower 8 bits in a second instruction. If two threads simultaneously perform a write to the same short int, it might receive the lower 8 bytes from one thread but the upper 8 bytes from the other thread.

If the platform were to write a 16-bit short int, it might do so by writing first the upper 8 bits in one instruction and then the lower 8 bits in a second instruction. If two threads simultaneously perform a write to the same short int, it might receive the lower 8 bits from one thread but the upper 8 bits from the other thread.

Ch. 7, p. 371

The specific order of the operations is irrelevant.

Delete sentence.

Ch. 7, p. 386 (para. 3)

Each thread must acquire both locks before accessing the value. If one thread acquires lock 0 first, and a second thread acquires lock 1, the program will deadlock.

Each thread must acquire all locks before accessing the value. If thread 0, for example, has acquired a lock required by thread 1, and thread 1 has acquired a lock required by thread 0, the program will deadlock.

Potential consequences include reading a privileged file (information disclosure), truncating a file, appending to a file, or changing file permissions.

Ch. 8, p. 432

On Windows systems, drive letters may also be provided (for example, C: ), as may other special file names, such as "..."—which is equivalent to "../..".

On Windows systems, drive letters may also be provided (for example, C: ), as may other special file names.

Ch. 8, p. 445, code line 3

(!S_ISREG(stbl.st_mode)) &&

(S_ISREG(stbl.st_mode)) &&

Ch. 8, p. 447 (para. 1)

Both the initial stat() and the O_NONBLOCK are needed. Dropping the stat() and just relying on O_NONBLOCK is insufficient.

Both the initial lstat() and the O_NONBLOCK are needed. Dropping the lstat() and just relying on O_NONBLOCK is insufficient

Ch. 8, p. 453 (para. 3)

To eliminate any potential race condition, both the test to determine if the file exists, and the open operation, must both be performed automatically.

To eliminate any potential race condition, both the test to determine if the file exists and the open operation must be performed atomically.

Ch. 8, p. 455 (para. 2)

Presumably the flawed thinking behind this code is that if a file can be opened for reading, it must exist.

Presumably the flawed thinking behind this code is that if a file cannot be opened for reading, it must not exist.

Ch. 8, p. 455 (Ex. 8.14)

09 ifstream fi(file_name);// attempt to open as input file

Insert space between ; and //

Ch. 8, p. 471 (para. 2)

This section surveys three categories of race condition tools, offering a brief representative examination of tools and some key characteristics.

Race conditions have been studied extensively, and a number of tools have been developed to detect race conditions in C and C++ programs. This section describes the use of both static and dynamic analysis to discover race conditions.

Ch. 8, p. 471 (para. 3)

The tool parses the source code (or, in some cases, the binary executable), sometimes relying on user-supplied search information and criteria.

The tool parses the source code (or, in some cases, the binary executable) to build an abstract syntax tree (AST) and other graphs, depending on the analysis being performed.

Ch. 9, p. 517 (para. 2)

Periodically measuring the attack surface allows developers to determine if the attack surface is growing or shrinking and, in the latter case, evaluate if this growth is necessary.

Periodically measuring the attack surface allows developers to determine if the attack surface is growing or shrinking and, in the former case, evaluate if this growth is necessary.