|
| 1 | +# MSC33-C: Do not pass invalid data to the asctime() function |
| 2 | + |
| 3 | +This query implements the CERT-C rule MSC33-C: |
| 4 | + |
| 5 | +> Do not pass invalid data to the asctime() function |
| 6 | +
|
| 7 | + |
| 8 | +## Description |
| 9 | + |
| 10 | +The C Standard, 7.27.3.1 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], provides the following sample implementation of the `asctime()` function: |
| 11 | + |
| 12 | +```cpp |
| 13 | +char *asctime(const struct tm *timeptr) { |
| 14 | + static const char wday_name[7][3] = { |
| 15 | + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" |
| 16 | + }; |
| 17 | + static const char mon_name[12][3] = { |
| 18 | + "Jan", "Feb", "Mar", "Apr", "May", "Jun", |
| 19 | + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" |
| 20 | + }; |
| 21 | + static char result[26]; |
| 22 | + sprintf( |
| 23 | + result, |
| 24 | + "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n", |
| 25 | + wday_name[timeptr->tm_wday], |
| 26 | + mon_name[timeptr->tm_mon], |
| 27 | + timeptr->tm_mday, timeptr->tm_hour, |
| 28 | + timeptr->tm_min, timeptr->tm_sec, |
| 29 | + 1900 + timeptr->tm_year |
| 30 | + ); |
| 31 | + return result; |
| 32 | +} |
| 33 | + |
| 34 | +``` |
| 35 | +This function is supposed to output a character string of 26 characters at most, including the terminating null character. If we count the length indicated by the format directives, we arrive at 25. Taking into account the terminating null character, the array size of the string appears sufficient. |
| 36 | +
|
| 37 | +However, this [implementation](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation) assumes that the values of the `struct tm` data are within normal ranges and does nothing to enforce the range limit. If any of the values print more characters than expected, the `sprintf()` function may overflow the `result` array. For example, if `tm_year` has the value `12345,` then 27 characters (including the terminating null character) are printed, resulting in a buffer overflow. |
| 38 | +
|
| 39 | +The* POSIX<sup>®</sup> Base Specifications* \[[IEEE Std 1003.1:2013](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-IEEEStd1003.1-2013)\] says the following about the `asctime()` and `asctime_r()` functions: |
| 40 | +
|
| 41 | +> These functions are included only for compatibility with older implementations. They have undefined behavior if the resulting string would be too long, so the use of these functions should be discouraged. On implementations that do not detect output string length overflow, it is possible to overflow the output buffers in such a way as to cause applications to fail, or possible system security violations. Also, these functions do not support localized date and time formats. To avoid these problems, applications should use `strftime()` to generate strings from broken-down times. |
| 42 | +
|
| 43 | +
|
| 44 | +The C Standard, Annex K, also defines `asctime_s()`, which can be used as a secure substitute for `asctime()`. |
| 45 | +
|
| 46 | +The `asctime()` function appears in the list of obsolescent functions in [MSC24-C. Do not use deprecated or obsolescent functions](https://wiki.sei.cmu.edu/confluence/display/c/MSC24-C.+Do+not+use+deprecated+or+obsolescent+functions). |
| 47 | +
|
| 48 | +## Noncompliant Code Example |
| 49 | +
|
| 50 | +This noncompliant code example invokes the `asctime()` function with potentially unsanitized data: |
| 51 | +
|
| 52 | +```cpp |
| 53 | +#include <time.h> |
| 54 | + |
| 55 | +void func(struct tm *time_tm) { |
| 56 | + char *time = asctime(time_tm); |
| 57 | + /* ... */ |
| 58 | +} |
| 59 | +``` |
| 60 | + |
| 61 | +## Compliant Solution (strftime()) |
| 62 | + |
| 63 | +The `strftime()` function allows the programmer to specify a more rigorous format and also to specify the maximum size of the resulting time string: |
| 64 | + |
| 65 | +```cpp |
| 66 | +#include <time.h> |
| 67 | + |
| 68 | +enum { maxsize = 26 }; |
| 69 | + |
| 70 | +void func(struct tm *time) { |
| 71 | + char s[maxsize]; |
| 72 | + /* Current time representation for locale */ |
| 73 | + const char *format = "%c"; |
| 74 | + |
| 75 | + size_t size = strftime(s, maxsize, format, time); |
| 76 | +} |
| 77 | +``` |
| 78 | +This call has the same effects as `asctime()` but also ensures that no more than `maxsize` characters are printed, preventing buffer overflow. |
| 79 | + |
| 80 | +## Compliant Solution (asctime_s()) |
| 81 | + |
| 82 | +The C Standard, Annex K, defines the `asctime_s()` function, which serves as a close replacement for the `asctime()` function but requires an additional argument that specifies the maximum size of the resulting time string: |
| 83 | + |
| 84 | +```cpp |
| 85 | +#define __STDC_WANT_LIB_EXT1__ 1 |
| 86 | +#include <time.h> |
| 87 | + |
| 88 | +enum { maxsize = 26 }; |
| 89 | + |
| 90 | +void func(struct tm *time_tm) { |
| 91 | + char buffer[maxsize]; |
| 92 | + |
| 93 | + if (asctime_s(buffer, maxsize, &time_tm)) { |
| 94 | + /* Handle error */ |
| 95 | + } |
| 96 | +} |
| 97 | +``` |
| 98 | + |
| 99 | +## Risk Assessment |
| 100 | + |
| 101 | +On [implementations](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation) that do not detect output-string-length overflow, it is possible to overflow the output buffers. |
| 102 | + |
| 103 | +<table> <tbody> <tr> <th> Rule </th> <th> Severity </th> <th> Likelihood </th> <th> Remediation Cost </th> <th> Priority </th> <th> Level </th> </tr> <tr> <td> MSC33-C </td> <td> High </td> <td> Likely </td> <td> Low </td> <td> <strong>P27</strong> </td> <td> <strong>L1</strong> </td> </tr> </tbody> </table> |
| 104 | + |
| 105 | + |
| 106 | +## Automated Detection |
| 107 | + |
| 108 | +<table> <tbody> <tr> <th> Tool </th> <th> Version </th> <th> Checker </th> <th> Description </th> </tr> <tr> <td> <a> Astrée </a> </td> <td> 22.04 </td> <td> </td> <td> Supported, but no explicit checker </td> </tr> <tr> <td> <a> Axivion Bauhaus Suite </a> </td> <td> 7.2.0 </td> <td> <strong>CertC-MSC33</strong> </td> <td> </td> </tr> <tr> <td> <a> CodeSonar </a> </td> <td> 7.2p0 </td> <td> <strong>BADFUNC.TIME_H</strong> </td> <td> Use of <time.h> Time/Date Function </td> </tr> <tr> <td> <a> Helix QAC </a> </td> <td> 2022.4 </td> <td> <strong>C5032</strong> <strong>C++5030</strong> </td> <td> </td> </tr> <tr> <td> <a> Klocwork </a> </td> <td> 2022.4 </td> <td> <strong>CERT.MSC.ASCTIME</strong> </td> <td> </td> </tr> <tr> <td> <a> LDRA tool suite </a> </td> <td> 9.7.1 </td> <td> <strong>44 S</strong> </td> <td> Enhanced Enforcement </td> </tr> <tr> <td> <a> Parasoft C/C++test </a> </td> <td> 2022.2 </td> <td> <strong>CERT_C-MSC33-a</strong> </td> <td> The 'asctime()' and 'asctime_r()' functions should not be used </td> </tr> <tr> <td> <a> PC-lint Plus </a> </td> <td> 1.4 </td> <td> <strong>586</strong> </td> <td> Fully supported </td> </tr> <tr> <td> <a> Polyspace Bug Finder </a> </td> <td> R2022b </td> <td> <a> CERT C: Rule MSC33-C </a> </td> <td> Checks for use of obsolete standard function (rule fully covered) </td> </tr> <tr> <td> <a> PRQA QA-C </a> </td> <td> 9.7 </td> <td> <strong>5032 </strong> </td> <td> </td> </tr> <tr> <td> <a> PRQA QA-C++ </a> </td> <td> 4.4 </td> <td> <strong>5030</strong> </td> <td> </td> </tr> <tr> <td> <a> RuleChecker </a> </td> <td> 22.04 </td> <td> </td> <td> Supported, but no explicit checker </td> </tr> </tbody> </table> |
| 109 | + |
| 110 | + |
| 111 | +## Related Vulnerabilities |
| 112 | + |
| 113 | +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+MSC33-C). |
| 114 | + |
| 115 | +## Related Guidelines |
| 116 | + |
| 117 | +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) |
| 118 | + |
| 119 | +<table> <tbody> <tr> <th> Taxonomy </th> <th> Taxonomy item </th> <th> Relationship </th> </tr> <tr> <td> <a> CERT C Secure Coding Standard </a> </td> <td> <a> MSC24-C. Do not use deprecated or obsolescent functions </a> </td> <td> Prior to 2018-01-12: CERT: Unspecified Relationship </td> </tr> </tbody> </table> |
| 120 | + |
| 121 | + |
| 122 | +## Bibliography |
| 123 | + |
| 124 | +<table> <tbody> <tr> <td> \[ <a> IEEE Std 1003.1:2013 </a> \] </td> <td> XSH, System Interfaces, <code>asctime</code> </td> </tr> <tr> <td> \[ <a> ISO/IEC 9899:2011 </a> \] </td> <td> 7.27.3.1, "The <code>asctime</code> Function" </td> </tr> </tbody> </table> |
| 125 | + |
| 126 | + |
| 127 | +## Implementation notes |
| 128 | + |
| 129 | +None |
| 130 | + |
| 131 | +## References |
| 132 | + |
| 133 | +* CERT-C: [MSC33-C: Do not pass invalid data to the asctime() function](https://wiki.sei.cmu.edu/confluence/display/c) |
0 commit comments