メインコンテンツ

setjmp/longjmp の使用

setjmplongjmp により通常の制御フローからの逸脱が発生

説明

この欠陥は、setjmplongjmp あるいは sigsetjmpsiglongjmp の組み合わせを使用して、通常の制御フローから逸脱し、コード内で非ローカル ジャンプを実行した場合に発生します。

リスク

setjmplongjmp、あるいは sigsetjmpsiglongjmp を使用すると、次のようなリスクがあります。

  • ローカルではないジャンプは、バッファー オーバーフローのような一般的なエラーを狙った攻撃に対し脆弱です。攻撃者は制御フローをリダイレクトし、任意のコードを実行することができます。

  • 動的に割り当てられたメモリや開いているファイルなどのリソースが閉じられず、リソース リークが発生する可能性があります。

  • setjmplongjmp が信号ハンドラーとの組み合わせで使用されると、想定外の制御フローが発生することがあります。POSIX® では、setjmp が信号マスクを保存するかどうかを指定しません。

  • setjmplongjmp あるいは sigsetjmpsiglongjmp を使用すると、プログラムの理解と保守が難しくなります。

修正方法

setjmp/longjmp または sigsetjmp/siglongjmp を使用して、コード内のローカルではないジャンプを、ジャンプが安全に実行できるコンテキストでのみ実行します。あるいは、可能な場合は POSIX スレッドを使用します。

C++ の場合、例外のスローとキャッチをシミュレートするため、throw 式や catch ステートメントなどの標準イディオムを使用します。

すべて展開する

#include <setjmp.h>
#include <signal.h>

extern int update(int);
extern void print_int(int);

static jmp_buf env;
void sighandler(int signum) {
    longjmp(env, signum);
}
void func_main(int i) {
    signal(SIGINT, sighandler);
    if (setjmp(env)==0) {
        while(1) {
            /* Main loop of program, iterates until SIGINT signal catch */
            i = update(i);
        }
    } else {
        /* Managing longjmp return */
        i = -update(i);
    }

    print_int(i);
    return;
}

この例では、setjmp の初期の戻り値は 0 です。関数 update は、ユーザーが信号によって割り込むまで、無限 while ループで呼び出されます。

信号処理関数では、longjmp ステートメントによって main へ戻るジャンプが発生し、setjmp の戻り値は 1 になります。そのため、else 分岐が実行されます。

修正 — setjmplongjmp の代替方法を使用

同じ動作をより安全にエミュレートするために、setjmplongjmp の組み合わせの代わりにグローバル変数 volatile を使用します。

#include <setjmp.h>
#include <signal.h>

extern int update(int);
extern void print_int(int);

volatile sig_atomic_t eflag = 0;

void sighandler(int signum) {
     eflag = signum;                   /* Fix: using global variable */
}

void func_main(int i) {
      /* Fix: Better design to avoid use of setjmp/longjmp */
    signal(SIGINT, sighandler);
    while(!eflag) {                   /* Fix: using global variable */
        /* Main loop of program, iterates until eflag is changed */
        i = update(i);
    }

    print_int(i);
    return;
}

結果情報

グループ: 適切な手法
言語: C | C++
既定値: オフ
コマンド ライン構文: SETJMP_LONGJMP_USE
影響度: Low

バージョン履歴

R2015b で導入