Secure Coding Guideline, C
This document describes the secure coding guidelines for the C programming language. Some of the guidelines are generic, whereas some of them are specific to the C programming language.
Code Priority Classification
Courtesy: Microsoft SDL documentation.
The source code being developed or reviewed should be classified as below.
Code Priority | Description |
---|---|
Priority 1 |
|
Priority 2 |
|
Priority 3 |
|
C secure coding guidelines
Introduction
C has been intensely criticized as an insecure programming language. Despite the many vulnerabilities attributed to buffer overflows and point manipulation, secure code can still be developed with C.
This document summarizes the common guidelines for C. Further details and other guidelines are available in the CERT C Secure Coding Standard. In addition to this document, you should utilize Klocwork (a static analyzer for which ABB has an enterprise license) to analyze your code. Review the general coding guidelines for aspects such as input validation and resource management.
Avoid Unsafe Methods
Avoid using unsafe methods such as gets()
, strcat()
, and strcpy()
. These methods do not check boundaries when copying data to the destination. As such, it becomes possible to insert arbitrary code into the system.
Header Files
Use parenthesis within macros around parameter names
When defining macros, parenthesis should surround any parameters, except in a list separated by commas. This prevents issues with unexpected operator precedence when such macros are expanded.
(CERT C, PRE-01-C)
Macros should not end with a semi-colon
When a macro ends with a semi-colon, it can lead to an empty statement being produced for the output, affecting the intended output.
(CERT C, PRE-11-C)
Declarations and Initialization
Variable Arguments
When feasible, avoid the use of variable argument functions. If such functions are necessary, ensure the “contract” between caller and callee is maintained.
(CERT C, DCL-10,11)
Declare Zero Parameters Functions with Void
For functions that do not take any parameters, declare these with a “void” parameter. This will force compiler warnings if such a function is called with parameters.
(CERT C, DCL-20)
Expressions
Parenthesis
Use parentheses to ensure proper precedence with operations.
(CERT C, EXP00-C)
Type Sizes
Do not use the size of a pointer to assume that it is the same size as the associated type. Do not assume the size of a structure is the sum of the size of the members.
(CERT C, EXP01-C, EXP-03C)
Pointer Arithmetic
Ensure pointer arithmetic is used properly. Otherwise, the wrong memory address is referenced.
(CERT C, EXP-08-C)
Integers
Define Integer Constants Safely
Integer constants are often used to specify bit-masks and other boundary checks. As the size of integers can vary across platforms, constants should be specified in a platform-independent manner.
(CERT C, INT-17-C)
Floating Point
Understand Floating Point Limitations
Floating-point numbers have finite precision and are prone to errors with rounding. If exact values are needed, then another type should be selected. Additionally, no guarantees on the underlying specifics of the floating-point system exist, so no assumptions should be made on the precision and/or range.
(CERT C, FLP-00-C)
Arrays
Do not use the sizeof
operator to the array pointer
This returns the size of the pointer itself rather than the data structure it references.
(CERT C, ARR-01-C)
Check Array Boundaries
Ensure that you only access legitimate portions of the array. Array indexing starts at zero. This is especially critical when expressions are used to index the array.
Strings
A multitude of security issues has arisen from C’s poor implementation of strings. Issues exist among the representation, management, and manipulation of C-style strings. For representation, the strings are null-terminated. Thus it is necessary to scan the entire string to find the length or last location.
While strings can also be managed by using standard, well-proven functions of malloc()
, free()
, strlen()
, memcpy()
, and snprintf()
, these functions can be difficult to use correctly in practice and have poor abstractions compared to languages such as Java and C#. The edge security team relies on CSA safe string functions. E.g., CSA_StrLen
should be used instead of strlen
, and OSA_snprintf
should be used instead of sprintf
.
Check String Bounds
When implementing strings, use functions that check the string boundaries to overflow issues.
Memory
Memory management is one of the more difficult tasks to correctly implement within C programs. Any time memory is allocated, you must ensure the memory is deallocated when no longer required. Consider using a library to track your memory usage while the application executes. Once the memory is allocated, you will need to initialize it. Once you have freed memory, you should no longer access it.
Input / Output
All open files should be closed when no longer in use. Ensure when opening files specified by a user that the name is valid and isn’t being referenced to a location that should not otherwise be accessed. E.g., using “..” to move up the directory structure to a new file location. When creating an output format string, ensure that it is properly formatted – especially if such a string originated from the user.
Environment
Avoid System()
Where possible, avoid the use of the system()
to call executable programs. Either user existing C functions if possible or exec().
(CERT-C ENV04-C)
Signals
Avoid using signals to implement normal functionality or flow of control. Ensure code accessed within signal handlers is thread-safe, does not access shared memory, and is asynchronous-safe. Many common standard libraries such as free()
and fprintf()
are not appropriate to use within signal handlers.
(CERT-C SIG00-C, CERT-CSIG30-C)
Error Handling:
Return values from all functions should be checked, with the error handling functionality implemented correctly.
Link to common return values: https://wiki.sei.cmu.edu/confluence/display/c/ERR33-C.+Detect+and+handle+standard+library+errors .
(CERT-C, ERR33-C)
Concurrency
Applications often have multiple threads of control. Care must be taken to ensure shared resources such as memory are appropriately protected by synchronization mechanisms to ensure the application stays within a consistent state.
Wikipedia https://en.wikipedia.org/wiki/Synchronization_(computer_science) presents several of the common synchronization methods. These methods are often unique to a particular operating system, although the POSIX Thread library has been established as a standard. A good overview of threads is available at https://hpc-tutorials.llnl.gov/posix/ .