CERT.SIG.SIG_HANDLER.SHARED_OBJ
シグナルハンドラー内で共有オブジェクトにアクセスしない
チェッカー CERT.SIG.SIG_HANDLER.SHARED_OBJ は、非ローカル変数にアクセスするシグナルハンドラーを検出します。
このチェッカーは、静的ストレージ期間が設定されているデータの読み取り/書き込みをシグナルハンドラーが行った場合にトリガーされます。これには、以下のものが含まれます。
-
グローバル変数または静的変数
-
このコンテキストで、ヒープに割り当てられたストレージを参照し、共有ポインターとして扱われるポインター
脆弱性とリスク
シグナルハンドラー内で共有オブジェクトへのアクセスや変更を行うと、競合状態が発生し、データが不整合なままになる可能性があります。この規則の 2 つの例外 (C 規格 5.1.2.3 第 5 段落) は、ロックフリーのアトミック型オブジェクトおよび volatile sig_atomic_t 型の変数に対する読み取りおよび書き込み機能です。シグナルハンドラーから他の型のオブジェクトへのアクセスは未定義の動作です。
軽減と防止
シグナルハンドラー内では、共有オブジェクトに対するアクセスや変更を行わないでください。 そのようにする場合は、共有オブジェクトへのアクセスが以下の例外に該当することを確認してください。
-
volatile sig_atomic_tの非ローカル変数の読み取りと書き込み -
ロックフリーの
atomic型非ローカル変数の読み取りと書き込み
脆弱コード例
#include <signal.h>
#include <stdlib.h>
#include <string.h>
enum { MAX_MSG_SIZE = 24 };
char *err_msg;
void handler(int signum) {
strcpy(err_msg, "SIGINT encountered."); // Non-compliant
}
int main(void) {
signal(SIGINT, handler);
err_msg = (char *)malloc(MAX_MSG_SIZE);
if (err_msg == NULL) {
/* Handle error */
}
strcpy(err_msg, "No errors yet.");
/* Main code loop */
return 0;
}
共有オブジェクト (err_msg) を変更するためにシグナルハンドラーで strcpy() が呼び出され、strcpy() が非同期シグナルセーフであることが保証されておらず、それは 未定義の動作 であるため、このコードは非準拠です。
修正コード例
#include <signal.h>
#include <stdlib.h>
#include <string.h>
enum { MAX_MSG_SIZE = 24 };
volatile sig_atomic_t e_flag = 0;
void handler(int signum) {
e_flag = 1;
}
int main(void) {
char *err_msg = (char *)malloc(MAX_MSG_SIZE);
if (err_msg == NULL) {
/* Handle error */
}
signal(SIGINT, handler);
strcpy(err_msg, "No errors yet.");
/* Main code loop */
if (e_flag) {
strcpy(err_msg, "SIGINT received.");
}
return 0;
}
sig_atomic_t 型と volatile 修飾子が指定されている共有オブジェクトにシグナルハンドラーがアクセスしているため、準拠コードになりました。