Skip to main content

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 PriorityDescription
Priority 1
  • All Internet or network-facing code.
  • Code in the Trusted Computing Base (TCB) (for example, code executing in kernel mode).
  • Code running under root account.
  • Code running as an elevated user
  • Any code that handles secret data, such as encryption keys and passwords.
  • All code-supporting functionality is exposed on the maximum attack surface
Priority 2
  • Code that runs under a non-root account
Priority 3
  • Test scripts, automation scripts

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/ .

Owner: Software Development Team