CWE-823: Out-of-range Pointer
Overview
Out-of-range Pointer occurs when pointer arithmetic or array indexing results in a pointer that references memory outside the intended buffer boundaries. This typically happens through unchecked pointer arithmetic, incorrect loop conditions, or unsafe buffer operations.
Risk
High to Critical: Using out-of-range pointers can cause memory corruption, crashes, information disclosure, or arbitrary code execution. Attackers may exploit this to read sensitive data, overwrite critical memory, or gain control of program execution.
Remediation Steps
Core principle: Never form pointers/addresses from unchecked values; validate ranges and use safe pointer abstractions.
Identify Out-of-Range Pointer Operations
When reviewing security scan results:
- Check pointer arithmetic: Look for
ptr + offset,ptr++,ptr--operations - Review array indexing: Find
array[index]without bounds checks - Check buffer operations: Identify
strcpy,memcpy,strcatwith pointers - Review loops: Find loops that increment pointers beyond bounds
- Check function returns: Look for functions returning pointers to stack variables
Vulnerable patterns:
char buffer[100];
char *ptr = buffer;
ptr += user_input; // No bounds check!
*ptr = 'X'; // May write outside buffer
// Loop overrun
for (int i = 0; i <= n; i++) { // <= instead of <
array[i] = value; // Writes one past end!
}
Add Bounds Checking for Pointer Operations (Primary Defense)
// VULNERABLE - no bounds checking
void process_data(char *buffer, size_t size, int offset) {
char *ptr = buffer + offset; // No validation!
*ptr = 'X'; // May write outside buffer
}
// SECURE - validate bounds
void process_data_safe(char *buffer, size_t size, int offset) {
if (offset < 0 || offset >= size) {
return ERROR_INVALID_OFFSET;
}
char *ptr = buffer + offset;
*ptr = 'X'; // Safe - bounds checked
}
// Better - check before and after arithmetic
void write_at_offset(char *buffer, size_t size, int offset, char value) {
// Check offset is valid
if (offset < 0 || (size_t)offset >= size) {
log_error("Invalid offset: %d, size: %zu", offset, size);
return;
}
char *ptr = buffer + offset;
// Additional check: verify pointer is within bounds
if (ptr < buffer || ptr >= buffer + size) {
log_error("Pointer out of range");
return;
}
*ptr = value;
}
Array iteration with bounds checking:
// VULNERABLE
for (int i = 0; i <= count; i++) { // Off-by-one!
array[i] = value;
}
// SECURE
for (int i = 0; i < count; i++) { // Correct bounds
if (i >= MAX_SIZE) break; // Additional safety check
array[i] = value;
}
Use Safe String and Memory Functions
// VULNERABLE - no bounds checking
char dest[10];
char *src = user_input;
strcpy(dest, src); // Buffer overflow!
strcat(dest, "suffix"); // More overflow!
// SECURE - bounded operations
char dest[10];
strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0'; // Ensure null termination
strncat(dest, "suffix", sizeof(dest) - strlen(dest) - 1);
// Better - use snprintf
snprintf(dest, sizeof(dest), "%s%s", src, "suffix");
// Best - use safer alternatives
#include <string.h>
strlcpy(dest, src, sizeof(dest)); // BSD
strlcat(dest, "suffix", sizeof(dest));
Memory copy with validation:
// VULNERABLE
memcpy(dest, src, user_size); // No bounds check!
// SECURE
if (user_size > dest_size) {
log_error("Copy size exceeds destination");
return ERROR;
}
if (user_size == 0 || user_size > MAX_COPY_SIZE) {
return ERROR;
}
memcpy(dest, src, user_size);
Use Modern C++ Smart Pointers and Containers
// VULNERABLE - manual pointer arithmetic
int* data = new int[size];
for (int i = 0; i < size; i++) {
*(data + i) = value; // Manual pointer arithmetic
}
delete[] data;
// SECURE - use std::vector with bounds checking
#include <vector>
std::vector<int> data(size);
for (size_t i = 0; i < data.size(); i++) {
data.at(i) = value; // Throws exception if out of range
}
// Automatically freed
// Even better - use iterators
for (auto& element : data) {
element = value;
}
// Smart pointers for single objects
std::unique_ptr<Object> obj = std::make_unique<Object>();
obj->method(); // Safe, automatically deleted
// Arrays with bounds checking
std::array<int, 10> fixed_array;
fixed_array.at(5) = 42; // Bounds checked
Enable Compiler Warnings and Runtime Checks
# Compile with warnings
gcc -Wall -Wextra -Wpointer-arith -Warray-bounds \
-D_FORTIFY_SOURCE=2 -O2 \
program.c -o program
# Enable AddressSanitizer during development
gcc -fsanitize=address -g program.c -o program
./program
# Detects out-of-bounds access, use-after-free, etc.
# Enable UndefinedBehaviorSanitizer
gcc -fsanitize=undefined -g program.c -o program
# Stack protector
gcc -fstack-protector-all program.c -o program
Static analysis:
# Use clang static analyzer
clang --analyze program.c
# Use cppcheck
cppcheck --enable=all program.c
# Use Coverity, PVS-Studio, or Veracode Static Analysis
Test with Fuzzing and Memory Sanitizers
// Test harness with bounds checking
void test_pointer_safety() {
char buffer[100];
// Test 1: Valid operations
assert(write_at_offset(buffer, sizeof(buffer), 0, 'X') == SUCCESS);
assert(write_at_offset(buffer, sizeof(buffer), 99, 'Y') == SUCCESS);
// Test 2: Out-of-bounds (should fail gracefully)
assert(write_at_offset(buffer, sizeof(buffer), 100, 'Z') == ERROR);
assert(write_at_offset(buffer, sizeof(buffer), -1, 'A') == ERROR);
// Test 3: Edge cases
assert(write_at_offset(NULL, 0, 0, 'B') == ERROR);
assert(write_at_offset(buffer, 0, 0, 'C') == ERROR);
}
Fuzzing with AFL or libFuzzer:
#ifdef FUZZING
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (size < 4) return 0;
int offset = *(int*)data;
char buffer[100];
// Should not crash on any input
write_at_offset(buffer, sizeof(buffer), offset, 'X');
return 0;
}
#endif
Security Checklist
- All pointer arithmetic has bounds checks
- Array indices validated before access
- Use
at()instead of[]for std::vector in C++ - Replaced strcpy/strcat with strncpy/strncat or snprintf
- Compiled with AddressSanitizer during testing
- Static analysis shows no pointer warnings
- Fuzz testing passed without crashes
- No pointer arithmetic on user-controlled offsets without validation