Bug classes

C/C++ bug classes #

Below is a list of common vulnerability types for C/C++ programs. This list does not include comprehensive details; rather, it is intended to be broad and high level. Use it as a starting point during security reviews of C/C++ programs.

  • Buffer overflow and underflow, spatial safety
  • Use after free, temporal safety
    • Use after free
      • Example: Two shared_ptrs point to the same object, and one of them decrements its reference count (refcount) to 0 and frees the object. See this blog post for reference.
    • Use after scope, dangling pointers
      • Example: Heap structures owning pointers to stack variables
    • Use after return
      • Example: With return string("").c_str(), the string’s internal buffer is destroyed on return.
    • Use after close
      • Example: A file’s descriptor is saved in process memory, the file is closed, and then another file is assigned to the same descriptor. See this CTF challenge.
    • Use after move
    • Double free
    • Misuse of smart pointers. See this example CTF writeup.
    • Lambda capture issues
    • Arbitrary pointer free
      • Example: An attacker can call free on a pointer to memory that was not dynamically allocated or on data that is not a pointer.
    • Incorrect refcounts
      • Example: A refcount is incremented when it should not be, or an object is not freed when its refcount drops to zero.
    • Partial free
      • Example: A struct’s field is freed but the struct is not, or vice versa.
    • Misuse of memory-allocating library functions
      • Example: OpenSSL’s BN_CTX_start is called without a corresponding call to BN_CTX_end. See this blog post for reference.
  • Integer overflow, numeric errors
    • Arithmetic overflows
      • Results of computations do not fit in intermediate or final types.
    • Widthness overflows
      • Data is assigned to a too-small type.
    • Signedness bugs
      • Data is transformed in unexpected ways when its type’s sign changes.
    • Implicit conversions
      • The type of a variable changes unexpectedly.
    • Negative assignment overflow
      • abs(INT_MIN) == INT_MIN == -2147483648
      • int a = -b (if b = INT_MIN, then a = b)
    • Integer cut
      • Example: The code reads rax, compares only eax, and then uses rax.
    • Rounding errors
    • Float imprecision
      • Example: Direct comparison of floats without an epsilon
  • Type confusion, type safety issues
    • Type confusion when casting
    • Type confusion when deserializing
    • Type confusion when dereferencing pointers (pointer to pointer instead of pointer)
    • Void pointers
    • Type safety issues related to unions
    • Object slicing
  • Variadic function misuse
    • Format string bugs
      • User input is used as the format string.
    • Type mismatch bugs
      • A format string specifier does not match the type of the provided argument.
  • String issues
    • Lack of null termination
    • Issues related to locale-dependent string operations
      • When the execution environment may impact the logic of the code in unexpected ways
    • Problems related to encoding and normalization (UTF-8, UTF-16, Unicode, etc.)
    • Byte size not equal to character size
  • Use of uninitialized data
  • Null pointer dereferences
  • Unhandled errors
    • Return values not checked
    • Return values incorrectly compared
      • Example: When a function returns 1 on success and 0 or negative on failure, but the code includes an if (retval != 0) check
    • Exception handling issues
  • Memory leaks
    • Uninitialized memory exposure
      • Example: Via padding in structures
    • Exposure of pointers
  • Initialization order bugs
  • Race conditions
    • Time-of-check to time-of-use (TOCTOU)
    • double fetch
    • Over- or under-locking
    • (Non-)thread-safe and signal-safe APIs
  • Filesystem-related issues
    • Issues with softlinks/symlinks
    • Disk synchronization issues (fsyncing/flushing of data)
    • Mishandling of unquoted paths (which may contain whitespace characters)
    • Missing path separators (e.g., C:\app\files vs C:\app\files\ versus C:\app\files_sensitive)
    • Case sensitivity and normalization issues
    • Predictable temporary files
  • Iterator invalidation (see Trail of Bits’ blog post for reference)
    • Accidental deletion of a list item while iterating over it
  • Usage of error-prone functions
  • Denial of service
    • High resource usage
    • Leaks of resources, file descriptors, or memory
    • Passing containers (e.g., vector) via value instead of via reference
    • Dangling references (e.g., after move or in lambda captures)
  • Undefined behavior
    • Invalid alignment
    • Strict aliasing violation
    • Signed integer overflow
    • Shift by negative integer
    • Shift by >= the type’s width
    • And so many others…
  • Compiler-introduced bugs
    • Removal of security checks due to assumptions around undefined behavior
    • Removal of data zeroization function calls
    • Issues resulting from optimization of constant-time constructions
    • Removal of debug assertions in production builds
  • Operator precedence issues
  • Problems with time
  • Access control issues
    • Invalid dropping of privileges (see the USENIX Association’s paper for information on setuid bugs)
    • Untrusted data used in privileged context (e.g., usermode data used inside the kernel with these sensitive x86 instructions: out, wrmsr, rdmsr, xsetbv, and mov to the control register)
  • Invalid regular expressions (regexes)
    • ReDoS attacks possible
    • Multi-line (newline) bypasses
  • Lack of exploit mitigations
This content is licensed under a Creative Commons Attribution 4.0 International license.