CWE-127, Buffer Under-read, happens when the product reads from a buffer using indexes or pointers that reference memory locations prior to the targeted buffer. It is the backward cousin of the over-read in CWE-126, and a child of CWE-125.
MITRE lists C and C++ as the affected platforms. If your code walks backwards through strings or arrays, or computes indexes by subtraction, it is worth checking.
How it happens
An index or pointer moves below the start. This is common when scanning backwards for a character, such as trimming trailing whitespace or finding the last path separator, and the code does not stop at the beginning.
MITRE's observed example is CVE-2021-40985, a buffer under-read in an HTML conversion package that allows a crash.
// Vulnerable: no lower bound when searching backwards for '/'
const char *basename_of(const char *path) {
const char *p = path + strlen(path);
while (*p != '/') {
p--; // runs before path if there is no slash
}
return p + 1;
}
// Fixed: stop at the start of the string
const char *basename_of(const char *path) {
const char *p = path + strlen(path);
while (p > path && p[-1] != '/') {
p--;
}
return p;
}
What an attacker gains
MITRE lists two consequences: reading memory, and bypassing protection mechanisms. By reading out-of-bounds memory, an attacker might get secret values such as memory addresses, which can help bypass protections like ASLR and improve the reliability of exploiting a separate bug for code execution. As the observed CVE shows, a crash is also a realistic result.
How to find it
- Static analysis. SAST can find some instances by analyzing source or compiled code.
- Runtime checks. Build with AddressSanitizer for C and C++ so reads before a buffer fail loudly. MITRE notes crafted inputs are still needed to reach the vulnerable code, so include edge cases: empty strings, strings with no separator, and strings made only of the character you search for.
How to fix it
The record has no mitigation list. These steps follow from the causes.
- Check the lower bound on every loop that moves backwards.
- Prefer library functions such as
strrchrover hand-written reverse scans. - Be careful with unsigned subtraction. A value that goes below zero wraps to a huge number.
- Add tests for empty and degenerate inputs, and run them under ASan.
Quick check
Where do under-reads usually appear?
In code that scans or trims backwards, where the loop stops on a character it expects to find but the input does not contain it.