Security Standards
CERT C
The CERT C Coding Standard is a secure coding standard developed by a community of experts on the wiki. The CERT C Coding Standard consists of over one hundred rules and an even larger set of recommendations. The most important distinction between a rule and a recommendation is:
- A violation of a rule is likely to result in code that is less safe, reliable, and/or secure.
- Application of a recommendation is likely to result in code that is safer, more reliable and/or more secure.
The CERT C Coding Standard does not attempt to impose coding style. The current CERT C Coding Standard was developed specifically for C11, however, the vast majority of the rules and recommendations are applicable to older versions of C (ie. C99).
The most up-to-date set of CERT C Coding Standard rules (along with explanations, examples, etc) can be found here: https://www.securecoding.cert.org/confluence/display/c/2+Rules.
CERT has performed a useful risk assessment of each of the C Coding Standard rules. Each rule is assigned a priority based on three factors: the severity of the impact a violation of the rule can lead to, the likelihood of the rule being violated and the remediation cost of correcting the violation. The following is a list of the CERT C Coding Standard rules ordered most severe to least severe. The list also includes the priority value of each rule but does not include the likelihood or remediation cost as these are essentially captured by the priority level. As stated earlier the list is ordered by severity rather than priority because severity is deemed most important in the context of security.
Rule Number | Description | Severity | Priority |
---|---|---|---|
STR38-C | Do not confuse narrow and wide character strings and functions | 3 | 27 |
MSC33-C | Do not pass invalid data to the asctime() function | 3 | 27 |
EXP34-C | Do not deference null pointers | 3 | 18 |
ARR38-C | Guarantee that library functions do not form invalid pointers | 3 | 18 |
STR31-C | Guarantee that storage for strings has sufficient space for character data and the null terminator | 3 | 18 |
MEM30-C | Do not access freed memory | 3 | 18 |
MEM34-C | Only free memory allocated dynamically | 3 | 18 |
FIO30-C | Exclude user input from format strings | 3 | 18 |
SIG30-C | Call only asynchronous-safe functions within signal handlers | 3 | 18 |
ERR33-C | Detect and handle standard library errors | 3 | 18 |
POS35-C | Avoid race conditions while checking for the existence of a symbolic link | 3 | 18 |
POS37-C | Ensure that privilege relinquishment is successful | 3 | 18 |
POS54-C | Detect and handle POSIX library errors | 3 | 18 |
EXP33-C | Do not read uninitialized memory | 3 | 12 |
STR32-C | Do not pass a non-null-terminated character sequence to a library function that expects a string | 3 | 12 |
FIO34-C | Distinguish between characters read from a file and EOF or WEOF | 3 | 12 |
FIO37-C | Do not assume that fgets() or fgetws() returns a nonempty string when successful | 3 | 12 |
ENV33-C | Do not call system() | 3 | 12 |
POS30-C | Use the readlink() function properly | 3 | 12 |
POS36-C | Observe correct revocation order while relinquishing privileges | 3 | 12 |
INT30-C | Ensure that unsigned integer operations do not wrap | 3 | 9 |
INT32-C | Ensure that operations on signed integers do not result in overflow | 3 | 9 |
ARR30-C | Do not form or use out-of-bounds pointers or array subscripts | 3 | 9 |
SIG31-C | Do not access shared objects in signal handlers | 3 | 9 |
MSC37-C | Ensure that control never reaches the end of a non-void function | 3 | 9 |
DCL30-C | Declare objects with appropriate storage durations | 3 | 6 |
INT31-C | Ensure that integer conversions do not result in lost or misinterpreted data | 3 | 6 |
ARR32-C | Ensure size arguments for variable length arrays are in a valid range | 3 | 6 |
ARR39-C | Do not add or subtract a scaled integer to a pointer | 3 | 6 |
MEM35-C | Allocate sufficient memory for an object | 3 | 6 |
FIO45-C | Avoid TOCTOU race conditions while accessing files | 3 | 6 |
FIO47-C | Use valid format strings | 3 | 6 |
POS34-C | Do not call putenv() with a pointer to an automatic variable as the argument | 3 | 6 |
MSC32-C | Properly seed pseudorandom number generators | 2 | 18 |
POS39-C | Use the correct byte ordering when transferring data between systems | 2 | 18 |
ENV32-C | All exit handlers must return normally | 2 | 12 |
POS47-C | Do not use threads that can be canceled asynchronously | 2 | 12 |
DCL36-C | Do not declare an indentifier with conflicting linkage classifications | 2 | 8 |
EXP30-C | Do not depend on the order of evaluation for side effects | 2 | 8 |
EXP42-C | Do not comprare padding data | 2 | 8 |
FLP32-C | Prevent or detect domain and range errors in math functions | 2 | 8 |
ARR36-C | Do not subtract or compare two pointers that do not refer to the same array | 2 | 8 |
ARR37-C | Do not add or subtract an integer to a pointer to a non-array object | 2 | 8 |
STR34-C | Cast characters to unsigned char before converting to larger integer sizes | 2 | 8 |
MEM31-C | Free dynamically allocated memory when no longer needed | 2 | 8 |
ERR30-C | Set errno to zero before calling a library function known to set errno, and check errno only after the function returns a value indicating failure | 2 | 8 |
CON32-C | Prevent data races when accessing bit-fields from multiple threads | 2 | 8 |
CON40-C | Do not refer to an atomic variable twice in an expression | 2 | 8 |
POS49-C | When data must be accessed by multiple threads, provide a mutex and guarantee no adjacent data is also accessed | 2 | 8 |
EXP47-C | Do not call va_arg with an argument of the incorrect type | 2 | 6 |
MSC30-C | Do not use the rand() function for generating pseudorandom numbers | 2 | 6 |
DCL41-C | Do not declare variables inside a switch statement before the first case label | 2 | 4 |
EXP37-C | Call functions with the correct number and type of arguments | 2 | 4 |
EXP43-C | Avoid undefined behaviour when using restict-qualified pointers | 2 | 4 |
FIO32-C | Do not perform operations on devices that are only appropriate for files | 2 | 4 |
FIO42-C | Close files when they are no longer needed | 2 | 4 |
FIO44-C | Only use values for fsetpos() that are returned from fgetpos() | 2 | 4 |
FIO46-C | Do not access a closed file | 2 | 4 |
ERR34-C | Detect errors when converting a string to a number | 2 | 4 |
CON30-C | Clean up thread-specific storage | 2 | 4 |
CON31-C | Do not destroy a mutex while it is locked | 2 | 4 |
CON33-C | Avoid race conditions when using library functions | 2 | 4 |
CON34-C | Declare objects shared between threads with appropriate storage durations | 2 | 4 |
CON43-C | Do not allow data races in multithreaded code | 2 | 4 |
POS38-C | Beware of race conditions when using fork and file descriptors | 2 | 4 |
POS48-C | Do not unlock or destroy another POSIX thread's mutex | 2 | 4 |
POS50-C | Declare objects shared between POSIX threads with appropriate storage durations | 2 | 4 |
POS53-C | Do not use more than one mutex for concurrent waiting operations on a condition variable | 2 | 4 |
EXP39-C | Do not access a variable through a pointer of an incompatible type | 2 | 2 |
EXP46-C | Do not use a bitwise operator with a Boolean-like operand | 1 | 9 |
STR30-C | Do not attempt to modify string literals | 1 | 9 |
EXP32-C | Do not access a volatile object through a nonvolatile reference | 1 | 6 |
EXP45-C | Do not perform assignments in selection statements | 1 | 6 |
INT33-C | Ensure that division and remainder operations do not result in divide-by-zero errors | 1 | 6 |
FLP30-C | Do not use floating-point variables as loop counters | 1 | 6 |
FIO39-C | Do not alternately input and output from a stream without an intervening flush or positioning call | 1 | 6 |
CON37-C | Do not call signal() in a multithreaded program | 1 | 6 |
CON39-C | Do not join or detach a thread that was previously joined or detached | 1 | 6 |
POS33-C | Do not use vfork() | 1 | 6 |
POS44-C | Do not use signals to terminate threads | 1 | 6 |
EXP35-C | Do not modify objects with temporary lifetime | 1 | 4 |
EXP36-C | Do not cast pointer into more strictly aligned pointer types | 1 | 4 |
FIO38-C | Do not copy a FILE object | 1 | 4 |
FIO40-C | Reset strings on fgets() or fgetws() failure | 1 | 4 |
ENV30-C | Do not modify the object referenced by the return value of certain functions | 1 | 4 |
ENV31-C | Do not rely on an environment pointer following an operation that may invalidate it | 1 | 4 |
ENV34-C | Do not store pointers returned by certain functions | 1 | 4 |
CON35-C | Avoid deadlock by locking in a predefined order | 1 | 4 |
POS51-C | Avoid deadlock with POSIX threads by locking in predefined order | 1 | 4 |
PRE31-C | Avoid side effects in arguments to unsafe macros | 1 | 3 |
DCL31-C | Declare identifiers before using them | 1 | 3 |
DCL37-C | Do not declare or define a reserved identifier | 1 | 3 |
DCL38-C | Use the correct syntax when declaring a flexible array member | 1 | 3 |
EXP44-C | Do not rely on side effects in operands to sizeof, _Alignof, or _Generic | 1 | 3 |
FLP34-C | Ensure that floating-point conversions are within range of the new type | 1 | 3 |
STR37-C | Arguments to character-handling functions must be representable as an unsigned char | 1 | 3 |
MEM33-C | Allocate and copy structures containing a flexible array member dynamically | 1 | 3 |
SIG34-C | Do not call signal() from within interruptible signal handlers | 1 | 3 |
ERR32-C | Do not rely on indeterminate values of errno | 1 | 3 |
MSC39-C | Do not call va_arg() on a va_list that has an indeterminate value | 1 | 3 |
PRE30-C | Do not create a universal character name through concatenation | 1 | 2 |
PRE32-C | Do not use preprocessor directives in invocations of function-like macros | 1 | 2 |
DCL40-C | Do not create incompatible declarations of the same function or object | 1 | 2 |
EXP40-C | Do not modify constant objects | 1 | 2 |
INT34-C | Do not shift an expression by a negative number of bits or by greater than or equal to the number of bits that exist in the operand | 1 | 2 |
INT35-C | Use correct integer precisions | 1 | 2 |
INT36-C | Converting a pointer to integer or integer to pointer | 1 | 2 |
FLP36-C | Preserve precision when converting integral values to floating-point type | 1 | 2 |
FLP37-C | Do not use object representations to compare floating-point values | 1 | 2 |
MEM36-C | Do not modify the alignment of objects by calling realloc() | 1 | 2 |
FIO41-C | Do not call getc(), putc(), getwc(), or putwc() with a stream argument that has side effects | 1 | 2 |
CON36-C | Wrap functions that can spuriously wake up in a loop | 1 | 2 |
CON38-C | Preserve thread safety and liveness when using condition variables | 1 | 2 |
CON41-C | Wrap functions that can fail spuriously in a loop | 1 | 2 |
MSC38-C | Do not treat a predefined identifier as an object if it might only be implemented as a macro | 1 | 2 |
MSC40-C | Do not violate constraints | 1 | 2 |
POS52-C | Do not perform operations that can block while holding a POSIX lock | 1 | 2 |
DCL39-C | Avoid information leakage in structure padding | 1 | 1 |
SIG35-C | Do not return from a computational exception signal handler | 1 | 1 |
This coding standard adopts all of the CERT C Coding Standard rules, with the exception of rules specific to Windows (rules with numbers WINxx-C). Conformance to all of the CERT C Coding Standard rules is necessary to conform to this coding standard.
- Note
- Conformance to the CERT C Coding Standard recommendations is not strictly required at this time but is highly recommended. Requirement to conform to certain CERT C Coding Standard recommendations may be added in the future.
Function Black List
Some C library functions are dangerous because they do not perform bounds checking or do not report error conditions. The following is a list of forbidden functions that must never be used.
Forbidden Functions | Safer Alternatives | Reason |
---|---|---|
sprintf | snprintf | Does not check buffer. |
vsprintf | vsnprintf | Does not check buffer size. |
gets | fgets | Does not check buffer size. |
strcpy | le_utf8_Copy, strncpy | Does not check buffer size. |
strcat | le_utf8_Append, strncat | Does not check buffer size. |
atoi | le_utf8_ParseInt, strtol | Does not detect errors. |
atol | strtol | Does not detect errors. |
atoll | strtoll | Does not detect errors. |
atof | strtod, strtof, strtold | Does not detect errors. |
signal | sigaction | Inconsistent behavior, Undefined behavior in multi-threaded programs. |
asctime | strftime | Does not check buffer size. |
asctime_r | strftime | Does not check buffer size. |
rewind | fseek | Does not detect errors. |
setbuf | setvbuf | Does not detect errors. |
setbuffer | setvbuf | Does not detect errors. |
setlinebuf | setvbuf | Does not detect errors. |
Compiler Warnings
All compiler warnings must be resolved. To enforce this the -Werror
GCC option must be used. In addition the following GCC options should be used to prevent questionable coding practice: -Werror
, -Wall
, -Wcast-align
, -Wstrict-prototypes
.
Copyright (C) Sierra Wireless Inc.