You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 32 Next »

Subclause 7.27.3.1 of the C Standard [ISO/IEC 9899:2011] provides the following sample implementation of the asctime() function:

char *asctime(const struct tm *timeptr)
{
  static const char wday_name[7][3] = {
    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  };
  static const char mon_name[12][3] = {
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  };
  static char result[26];
  sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
    wday_name[timeptr->tm_wday],
    mon_name[timeptr->tm_mon],
    timeptr->tm_mday, timeptr->tm_hour,
    timeptr->tm_min, timeptr->tm_sec,
    1900 + timeptr->tm_year);
  return result;
}

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.

However, this implementation assumes that the values of the struct tm data in timeptr 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 instance, if tm_year has the value 12345, then 27 characters (including the terminating null character) are printed, resulting in a buffer overflow.

The asctime() function primarily exists for compatibility with older implementations. Also, the asctime() function does not support localized date and time formats. The POSIX standard developers decided to mark the asctime() function obsolescent even though it is in the C Standard because of the possibility of buffer overflow.

C also provides the strftime() function, and Annex K provides asctime_s(), which can be used to avoid these problems.

Noncompliant Code Example

Avoid using the asctime() function with unsanitized data:

#include <time.h>
 
void func(void) {
  struct tm time_tm;
  /* Initialize time_tm */
  char *time = asctime(&time_tm);
}

Noncompliant Code Example (asctime())

You can sanitize the data before invoking asctime():

#include <time.h>
 
int validate_tm(struct tm* time) {
  /* 
   * The range of valid values of the tm_sec member is [0, 60] 
   * inclusive (to allow for leap seconds).
   */
  if (time->tm_sec < 0 || time->tm_sec > 60) return 0;
  if (time->tm_min < 0 || time->tm_min >= 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;
}
 
void func(void) {
  struct tm time_tm;
  /* Initialize time_tm */
  if (!validate_tm(&time_tm)) {
    /* Handle error */
  }
  char *time = asctime(&time_tm);
}

Note that while this is safer due to sanitizing the data, it is still non-compliant because asctime() is obsolete.  See MSC34-C. Do not use deprecated or obsolete functions

Compliant Solution (Annex K, asctime_s())

The asctime_s() function from Annex K requires a parameter specifying the maximum size of the resulting time string:

#define __STDC_WANT_LIB_EXT1__ 1
#include <time.h>
 
void func(void) {
  struct tm time_tm;
  const size_t maxsize = 26; 
  char buffer[maxsize];

  /* Initialize time_tm */
 
  if (asctime_s(buffer, maxsize, &time_tm)) {
    /* Handle error */
  }
}

Compliant Solution (strftime())

The strftime() function allows you to specify a more rigorous format and also to specify the maximum size of the resulting time string:

#include <time.h>
 
void func(void) {
  struct tm time;
  const size_t maxsize = 26;
  char s[maxsize];
  /* current time representation for locale */
  const char *format = "%c";
  const struct tm *timeptr;

  size_t size = strftime(s, maxsize, format, timeptr);
}

This call has the same effects as asctime(), but it also 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

MSC33-C

High

Likely

Low

P27

L1

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

Bibliography

 


 

 

  • No labels