MSC33-C. 無効なデータを asctime() 関数に渡さない
C 標準 [ISO/IEC 9899:2011] 7.27.3.1 節には、asctime()
関数の実装例が次のように示されている。
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;
}
この関数は、終端ナル文字を含む最大26文字からなる文字列を出力する想定である。書式の指定が示す長さを数えると25文字になり、終端ナル文字を考慮しても、この文字列を収めるための配列サイズは十分であるようにみえる。
しかし、この処理系は struct tm
の値が通常の範囲内にあることを想定しており、値の取りうる範囲を全く制限していない。値のいずれかが想定を超える文字数を出力した場合、sprintf()
関数は result
配列をオーバーフローさせる可能性がある。たとえば、tm_year
の値が 12345
の場合、終端ナル文字を含み 27 文字出力され、バッファオーバーフローが発生する。
POSIX® Base Specifications は asctime()
関数と asctime_r()
関数について次のように規定している[IEEE Std 1003.1:2013]。
これらの関数は昔の処理系との互換性のためだけに提供される。結果の文字列が長すぎる場合の動作は未定義であるため、これらの関数の使用は推奨されない。出力文字長のオーバーフローを検出しない処理系においては、出力バッファがオーバーフローし、プログラムが終了したり、システムのセキュリティを侵害する可能性がある。また、これらの関数はローカライズされた日時フォーマットの使用をサポートしていない。これらの問題を回避する上でも、プログラムは、
strftime()
を使って時間を示す文字列を生成すべきである。
C 標準の附属書 Kでは、asctime()
のセキュアな代替関数として asctime_s()
を定義している。
asctime()
関数は「MSC24-C. 非推奨関数や時代遅れの関数を使用しない」において時代遅れの関数とされている。
違反コード
この違反コード例では、無害化されていない可能性のあるデータに対して asctime()
関数を呼び出している。
#include <time.h>
void func(struct tm *time_tm) {
char *time = asctime(time_tm);
/* ... */
}
適合コード (strftime()
)
strftime()
関数では、現在のロケールに応じた書式を指定することができる。また、結果の文字列の最大サイズも指定する。
#include <time.h>
enum { maxsize = 26 };
void func(struct tm *time) {
char s[maxsize];
/* 現在のロケールでの時刻表現 */
const char *format = "%c";
size_t size = strftime(s, maxsize, format, time);
}
この関数呼出しでは asctime()
と同じ結果が得られるが、出力は maxsize
文字を超えないように制限され、バッファオーバーフローの発生を防止する。
適合コード (asctime_s()
)
C 標準の附属書 K では、asctime()
関数の代替関数として asctime_s()
関数を定義している。asctime_s()
関数では引数が1つ追加されており、出力する文字列の最大値を指定する。
#define __STDC_WANT_LIB_EXT1__ 1
#include <time.h>
enum { maxsize = 26 };
void func(struct tm *time_tm) {
char buffer[maxsize];
if (asctime_s(buffer, maxsize, &time_tm)) {
/* エラー処理 */
}
}
リスク評価
出力文字列長のオーバーフローを検出しない処理系では、出力バッファがオーバーフローする可能性がある。
ルール |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
MSC33-C |
高 |
高 |
低 |
P27 |
L1 |
関連するガイドライン
CERT C コーディングスタンダード | MSC24-C. 非推奨関数や時代遅れの関数を使用しない |
参考資料
[IEEE Std 1003.1:2013] | XSH, System Interfaces, asctime |
[ISO/IEC 9899:2011] | 7.27.3.1, "The asctime Function" |
翻訳元
これは以下のページを翻訳したものです。
MSC33-C. Do not pass invalid data to the asctime() function (revision 46)