VNX-805: Buffer Access with Incorrect Length Value
A C/C++ call writes into a byte buffer with a length that does not come from that buffer. Reported: (1) memcpy, memmove, memset, strncpy, read, recv, pread, fgets, snprintf, vsnprintf or fread (element size 1) into a char/unsigned char/uint8_t/u_char array declared with a numeric size (a literal or a #define of a literal) in the 80 lines above, either in the same function or at file scope, whose length is a larger number or #define, or sizeof() of another, larger array that is not the copy's source (that shape is VNX-806); (2) memcpy, memmove, memset, strncpy, read, recv or pread whose length is a conversion result: a network or text conversion (ntohs, ntohl, be16toh/be32toh/le16toh/le32toh, atoi, atol, atoll, strtol, strtoul, strtoll, strtoull, std::stoi/stol/stoul/stoull) written inline as the length, or a variable (optionally plus, minus or times a constant) assigned from one in the ten lines above, with no clamp on the assignment itself (MIN/min/clamp or a ternary), no comparison of that variable (<, >, MIN/min) between the conversion and the call, and no allocation of the destination sized by it. Not reported: lengths written as sizeof(dst), equal or smaller numeric lengths, non-byte arrays (an int[10] memset by 40 bytes is correct), an array declared in another function (a pointer parameter of the same name), counts whose size cannot be resolved in the file, and comments.
| Field | Value |
|---|---|
| Rule ID | VNX-805 |
| Severity | Medium |
| SARIF level | warning |
| Kind | sast |
| Languages | C, C++ |
| CWE | CWE-805 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:M/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C |
| Tags | buffer-access-incorrect-length-value cwe-805 memory-safety |
| Source | internal/sast/rules/vnx-805.rego |
Overview
VNX-805 maps to CWE-805: Buffer Access with Incorrect Length Value. It reports C and C++ copies and reads into a fixed byte array whose length argument is larger than the array, or comes unchecked from a packet or a string-to-number conversion.
What Gets Flagged
char name[16];
ssize_t n = read(fd, name, 32); /* FLAGGED: 32 > 16 */
#define NAME_LEN 32
#define MAX_INPUT 256
char user[NAME_LEN];
recv(sock, user, MAX_INPUT, 0); /* FLAGGED */
char small[8]; char big[128];
memcpy(small, input, sizeof(big)); /* FLAGGED: size of another buffer */
uint16_t len = ntohs(h->length);
memcpy(payload, pkt + sizeof(*h), len); /* FLAGGED: unchecked wire length */
Not flagged: fgets(line, sizeof(line), stdin), read(fd, b, 32) into char b[64], if (len > sizeof(payload)) return -1; before the copy, memcpy(buf, pkt, MIN(k, sizeof(buf))), memset(vals, 0, 40) on int vals[10].
/* FLAGGED: unchecked conversion as the length, inline or with arithmetic */
std::memcpy(out, src, std::atoi(argv[2]));
vlen = ntohs(t->len);
memcpy(value, t->data, vlen - 4);
Not flagged: size_t n = MIN(ntohs(h->len), cap); followed by memcpy(dst, h->body, n), or a pointer parameter that shares its name with an array declared in an earlier function.
Remediation
- Size every copy by the destination:
sizeof(dst)for arrays, the allocated length for pointers. - Compare an externally supplied length with the destination’s capacity before using it.
- Prefer bounded APIs that take the destination size (
snprintf,strlcpy).
References
Suppressing this rule
Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):
# nosec vnx-805
// nosec vnx-805
Or record an ignore rule: vulnetix ignore add --rule vnx-805 --reason "...". See Suppressing findings.