...
The gets_s()
function reads, at most, one less than the number of characters specified from the stream pointed to by stdin
into an array.
The C Standard, Annex K 3.5.4.1 paragraph 4 [ISO/IEC 9899:20112024], states
No additional characters are read after a new-line character (which is discarded) or after end-of-file. The discarded new-line character does not count towards number of characters read. A null character is written immediately after the last character read into the array.
...
In this compliant solution, characters are no longer copied to buf
once index == BUFFERSIZE - 1
, leaving room to null-terminate the string. The loop continues to read characters until the end of the line, the end of the file, or an error is encountered. When chars_read > index
truncated == true
, the input string has been truncated.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> enum { BUFFERSIZE = 32 }; void func(void) { char buf[BUFFERSIZE]; int ch; size_t index = 0; size_t chars_readbool truncated = 0false; while ((ch = getchar()) != '\n' && ch != EOF) { if (index < sizeof(buf) - 1) { buf[index++] = (char)ch; } else { chars_read++;truncated = true; } } buf[index] = '\0'; /* Terminate string */ if (ch == EOF) { /* Handle EOF or error */ } if (chars_read > indextruncated) { /* Handle truncation */ } } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> void func(const char *name) { char filename[128]; sprintf(filename, "%.123s.txt", name); } |
Compliant Solution (snprintf()
)
A more general solution is to use the snprintf()
functionYou can also use *
to indicate that the precision should be provided as a variadic argument:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> void func(const char *name) { char filename[128]; snprintfsprintf(filename, "%.*s.txt", sizeof(filename), "%s.txt" - 5, name); } |
Risk Assessment
Compliant Solution (snprintf()
)
A more general solution is to use the snprintf()
function, which also truncates name
if it will not fit in the filename
.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h>
void func(const char *name) {
char filename[128];
int result = snprintf(filename, sizeof(filename), "%s.txt", name);
if (result != strlen(filename) {
/* truncation occurred */
}
}
|
Risk Assessment
Copying string data to a buffer that is too small to hold that data results in a buffer overflow. Attackers can exploit Copying string data to a buffer that is too small to hold that data results in a buffer overflow. Attackers can exploit this condition to execute arbitrary code with the permissions of the vulnerable process.
...
Tool | Version | Checker | Description | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Astrée |
| Supported Astrée reports all buffer overflows resulting from copying data to a buffer that is not large enough to hold that data. | |||||||||||||||||||||||||||
Axivion Bauhaus Suite |
| Astrée_V |
|
Detects calls to unsafe string function that may cause buffer overflow
Detects potential buffer overruns, including those caused by unsafe usage of fscanf()
Include Page | ||||
---|---|---|---|---|
|
LANG.MEM.BO
LANG.MEM.TO
MISC.MEM.NTERM
BADFUNC.BO.*
Buffer overrun
Type overrun
No space for null terminator
A collection of warning classes that report uses of library functions prone to internal buffer overflows
Can detect violations of the rule. However, it is unable to handle cases involving strcpy_s()
or manual string copies such as the one in the first example
Include Page | ||||
---|---|---|---|---|
|
STRING_OVERFLOW
BUFFER_SIZE
OVERRUN
STRING_SIZE
Fully implemented
5.0
NNTS.MIGHT
NNTS.MUST
SV.STRBO.BOUND_COPY.OVERFLOW
SV.STRBO.BOUND_COPY.UNTERM
SV.STRBO.BOUND_SPRINTF
SV.STRBO.UNBOUND_COPY
SV.STRBO.UNBOUND_SPRINTF
489 S, 109 D, 66 X, 70 X, 71 X
Partially implemented
_SIZE
OVERRUN
STRING_SIZE
Fully implemented
5.0
Include Page | ||||
---|---|---|---|---|
|
C2840, C5009, C5038
C++0145, C++5009, C++5038
DF2840, DF2841, DF2842, DF2843, DF2845, DF2846, DF2847, DF2848, DF2930, DF2931, DF2932, DF2933, DF2935, DF2936, DF2937, DF2938
Include Page | ||||
---|---|---|---|---|
|
SV.FMT_STR.BAD_SCAN_FORMAT
SV.UNBOUND_STRING_INPUT.FUNC
Include Page | ||||
---|---|---|---|---|
|
489 S, 109 D, 66 X, 70 X, 71 X
Partially implemented
Include Page | ||||
---|---|---|---|---|
|
CERT_C-STR31-a
CERT_C-STR31-b
CERT_C-STR31-c
CERT_C-STR31-d
CERT_C-STR31-e
Avoid accessing arrays out of bounds
Avoid overflow when writing to a buffer
Prevent buffer overflows from tainted data
Avoid buffer write overflow from tainted data
Avoid using unsafe string functions which may cause buffer overflows
Include Page | ||||
---|---|---|---|---|
|
421, 498
Partially supported
Include Page | ||||
---|---|---|---|---|
|
Checks for:
- Use of dangerous standard function
- Missing null in string array
- Buffer overflow from incorrect string format specifier
- Destination buffer overflow in string manipulation
- Insufficient destination buffer size
Rule partially covered.
CERT_C-STR31-a
CERT_C-STR31-b
CERT_C-STR31-c
CERT_C-STR31-d
CERT_C-STR31-e
Avoid accessing arrays out of bounds
Avoid overflow when writing to a buffer
Prevent buffer overflows from tainted data
Avoid buffer write overflow from tainted data
Avoid using unsafe string functions which may cause buffer overflows
Buffer overflow from incorrect string format specifier
Destination buffer overflow in string manipulation
Invalid use of standard library string routine
Array index outside bounds during array access
String format specifier causes buffer argument of standard library functions to overflow
Function writes to buffer at offset greater than buffer size
Standard library string function called with invalid arguments
String does not terminate with null character
Pointer dereferenced outside its bounds
Argument is from an unsecure source and may be NULL or not NULL-terminated
Dangerous functions cause possible buffer overflow in destination buffer
Include Page | ||||
---|---|---|---|---|
|
Include Page | ||
---|---|---|
|
|
Include Page | ||||
---|---|---|---|---|
|
Exhaustively verified (see one compliant and one non-compliant example).
Related Vulnerabilities
CVE-2009-1252 results from a violation of this rule. The Network Time Protocol daemon (NTPd), before versions 4.2.4p7 and 4.2.5p74, contained calls to sprintf
that allow an attacker to execute arbitrary code by overflowing a character array [xorl 2009].
CVE-2009-0587 results from a violation of this rule. Before version 2.24.5, Evolution Data Server performed unchecked arithmetic operations on the length of a user-input string and used the value to allocate space for a new buffer. An attacker could thereby execute arbitrary code by inputting a long string, resulting in incorrect allocation and buffer overflow [xorl 2009arithmetic operations on the length of a user-input string and used the value to allocate space for a new buffer. An attacker could thereby execute arbitrary code by inputting a long string, resulting in incorrect allocation and buffer overflow [xorl 2009].
CVE-2021-3156 results from a violation of this rule in versions of Sudo before 1.9.5p2. Due to inconsistencies on whether backslashes are escaped, vulnerable versions of Sudo enabled a user to create a heap-based buffer overflow and exploit it to execute arbitrary code. [BC].
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
...
Taxonomy | Taxonomy item | Relationship |
---|---|---|
CERT C Secure Coding Standard | STR03-C. Do not inadvertently truncate a string | Prior to 2018-01-12: CERT: Unspecified Relationship |
CERT C Secure Coding Standard | STR07-C. Use the bounds-checking interfaces for remediation of existing string manipulation code MSC24-C. Do not use deprecated or obsolescent functions MEM00-C. Allocate and free memory in the same module, at the same level of abstraction FIO34-C. Distinguish between characters read from a file and EOF or WEOF | Prior to 2018-01-12: CERT: Unspecified Relationship |
ISO/IEC TR 24772:2013 | String Termination [CJM] | Prior to 2018-01-12: CERT: Unspecified Relationship |
ISO/IEC TR 24772:2013 | Buffer Boundary Violation (Buffer Overflow) [HCB] | Prior to 2018-01-12: CERT: Unspecified Relationship |
ISO/IEC TR 24772:2013 | Unchecked Array Copying [XYW] | Prior to 2018-01-12: CERT: Unspecified Relationship |
ISO/IEC TS 17961:2013 | Using a tainted value to write to an object using a formatted input or output function [taintformatio] | Prior to 2018-01-12: CERT: Unspecified Relationship |
ISO/IEC TS 17961:2013 | Tainted strings are passed to a string copying function [taintstrcpy] | Prior to 2018-01-12: CERT: Unspecified Relationship |
CWE 2.11 | CWE-119, Improper Restriction of Operations within the Bounds of a Memory Buffer | 2017-05-18: CERT: Rule subset of CWE |
CWE 2.11 | CWE-120, Buffer Copy without Checking Size of Input ("Classic Buffer Overflow") | 2017-05-15: CERT: Exact |
CWE 2.11 | CWE-123, Write-what-where Condition | 2017-06-12: CERT: Partial overlap |
CWE 2.11 | CWE-125, Out-of-bounds Read | 2017-05-18: CERT: Partial overlap |
CWE 2.11 | CWE-676, Off-by-one Error | 2017-05-18: CERT: Partial overlap |
...
Independent( ARR30-C, ARR38-C, EXP39-C, INT30-C)
STR31-C = Subset( Union( ARR30-C, ARR38-C))
STR32-C = Subset( ARR38-C)
...
Independent(ARR30-C, ARR38-C)
STR31-C = Subset( Union( ARR30-C, ARR38-C))
STR32-C = Subset( ARR38-C)
...
Independent( ARR30-C, ARR38-C, ARR32-C, INT30-C, INT31-C, EXP39-C, EXP33-C, FIO37-C)
STR31-C = Subset( Union( ARR30-C, ARR38-C))
STR32-C = Subset( ARR38-C)
...
[Dowd 2006] | Chapter 7, "Program Building Blocks" ("Loop Constructs," pp. 327–336) |
[Drepper 2006] | Section 2.1.1, "Respecting Memory Bounds" |
[ISO/IEC 9899:20112024] | K.3.5.4.1, "The gets_s Function" |
[Lai 2006] | |
[NIST 2006] | SAMATE Reference Dataset Test Case ID 000-000-088 |
[Seacord 2013b] | Chapter 2, "Strings" |
[xorl 2009] | FreeBSD-SA-09:11: NTPd Remote Stack Based Buffer Overflows |
[BC] | New Linux SUDO flaw lets local users gain root privileges |
...