CWE-469 happens when a product subtracts one pointer from another to determine a size, but the calculation can be wrong if the pointers do not live in the same memory chunk.
It affects C and C++ code, and it appears most naturally in data structures built from separately allocated nodes.
How it happens
Pointer subtraction is only well defined for two pointers into the same array or block. Linked list nodes are typically allocated one at a time and can be anywhere. MITRE's example computes list length that way:
struct node {
int data;
struct node* next;
};
// Returns the number of nodes in a linked list from
// the given pointer to the head of the list.
int size(struct node* head) {
struct node* current = head;
struct node* tail;
while (current != NULL) {
tail = current;
current = current->next;
}
return tail - head;
}
The function finds the last node, then subtracts head from tail. MITRE points out there is no guarantee the pointers exist in the same memory area, so the result can be incorrect and allow other unintended behavior.
What an attacker gains
MITRE's list is long: access control, integrity, confidentiality and availability impact, through modifying memory and reading memory, and potentially arbitrary code execution with the privileges of the vulnerable program. A wrong size used in a copy or an allocation is what turns this into memory corruption.
How to find it
MITRE lists:
- Fuzzing, which runs many varied inputs against the code and can expose crashes, memory corruption or resource consumption, producing repeatable test cases. Rated highly effective.
- Automated static analysis (SAST), rated highly effective, which models data flow and control flow to find vulnerable patterns.
A quick code search for pointer minus pointer expressions that feed a length or count is also worth doing.
How to fix it
MITRE's recommended solution: save an index variable. Rather than subtract pointers from one another, use an index variable of the same size as the pointers in question, walk from one pointer to the other with it, and calculate the difference. Always validate this number.
For the list example, a counter is all that is needed:
int size(struct node* head) {
struct node* current = head;
int count = 0;
while (current != NULL) {
count++;
current = current->next;
}
return count;
}
Quick check
When is pointer subtraction safe?
When both pointers point into the same array or memory chunk. Separately allocated list nodes give no such guarantee.