C99 provides the following definition sample implementation of the asctime() function in Section 7.23.3.1:
...
This function is supposed to output a character string of 26 positions at most, including the terminating zero. If we count the length indicated by the format directives we arrive at 25:
o 3 for the day of the week +
o 1 space +
o 3 for the month +
o 3 for the day in the month +
o 1 space +
o 8 for the hour in hh:mm:ss format +
o 1 space +
o 4 for the year +
o 1 newline.
It makes 25 characters, and taking . Taking into account the terminating zero, the calculation array size of the string appears sufficient is not.
The sprintf() call has undefined behavior if the value of timeptr->tm_year is outside the range -2899, 8099 and consequently the year being represented falls outside the range -999, 9999.
.
However, this implementation assumes that the values of the struct tm data in timeptr are within normal ranges, and does nothing to enforce this. If any of the values print more characters than expected, the sprintf() function may overflow the result array. For instance, if tm_year has the value 12345, then 27 characters (including the terminating null character) are printedThe problem is that the format %d of the printf specification doesn't allow for a maximum size. When you write %.3d it means that at least 3 characters will be output, but it could be much more if, for instance, the input is bigger than 999. In that case, the buffer allocated for asctime is too small to contain the printf result, resulting in a buffer overflow.
The asctime() function primarily exists for compatibility with older implementations. Also, The the asctime() function does not support localized date and time formats. To avoid these problems, applications should use strftime() to generate strings from broken-down times. The POSIX standard developers decided to mark the asctime() function obsolescent even though they are in C99 because of the possibility of buffer overflow.
C99 also provides the strftime() function which can be used to avoid these problems.
...
Avoid using the asctime() function with unsanitized data.
| Code Block | ||
|---|---|---|
| ||
struct tm time_tm; /* initialize time_tm */ char *time = asctime(&time_tm); |
Compliant Solution
You can sanitize the data before invoking asctime().
| Code Block | ||
|---|---|---|
| ||
int validate_tm(struct tm* time) { if (time->tm_sec < 0 || time->tm_sec >= 60) return 0; /* Seconds [0,60] */ time.tmif (time->tm_min < 0 || time->tm_min >= 59; /* Minutes [0,59] */ time.tm_hour = 23; /* Hour [0,23] */ time.tm_mday = 31; /* Day of month [1,31] */ time.tm_mon = 0; /* Month of year [0,11] */ time.tm_year = 8100; /* Years since 1900 */ time.tm_wday = 0; /* Day of week [0,6] (Sunday =0) */ time.tm_yday = 365; /* Day of year [0,365] */ time.tm_isdst = -1; /* Daylight Savings flag */ 60) return 0; if (time->tm_hour < 0 || time->tm_hour >= 24) return 0; if (time->tm_mday <= 0 || time->tm_mday > 31) return 0; if (time->tm_mon < 0 || time->tm_mon >= 12) return 0; /* While other years are legit, they may overflow asctime()'s buffer */ if (time->tm_year < -999 || time->tm_year > 9999) return 0; if (time->tm_wday < 0 || time->tm_wday >= 7) return 0; if (time->tm_yday < 0 || time->tm_yday >= 366) return 0; return 1; } struct tm time_tm; /* initialize time_tm */ if (!validate_tm(&time_tm)) { /* handle error */ } char *time = asctime(&time_tm); |
Compliant Solution
Use the The strftime() function allows you to specify a more rigorous format, and also to specify the maximum size of the resulting time string.
| Code Block | ||
|---|---|---|
| ||
char *s=struct tm time; const size_t maxsize = 26; /* or maximum size of time string */; char s[maxsize]; const char *format = "%c"; /* current time representation for locale */ const struct tm *timeptr; size_t size = strftime(s, maxsize, format, timeptr); |
While this call has the same effects as asctime(), it ensures that no more than maxsize chars are printed, preventing buffer overflow.
Risk Assessment
On implementations that do not detect output string length overflow, it is possible to overflow the output buffers resulting in a vulnerability.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
STR30 MSC33-C | high | high | low | P9 | L2 |
Automated Detection
...
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Other Languages
This rule appears in the C++ Secure Coding Standard as STR30-CPP. Do not attempt to modify string literals.
References
| Wiki Markup |
|---|
\[[ISO/IEC 9899:1999|AA. C References#ISO/IEC 9899-1999]\] Section 7.23.3.1, "The asctime function" and Section 7.23.3.5, "The strftime function" |
...