メインコンテンツ

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

CERT C: Rec.MSC22-C

Use the setjmp(), longjmp() facility securely

説明

ルール定義

setjmp() および longjmp() 機能は安全に使用します。1

Polyspace 実装

ルール チェッカーは、"setjmp/longjmp の使用" をチェックします。

すべて展開する

問題

setjmp/longjmp の使用は、setjmplongjmp あるいは sigsetjmpsiglongjmp の組み合わせを使用して通常の制御フローから逸脱し、ローカルではないジャンプがコード内で実行されると発生します。

リスク

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

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

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

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

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

修正方法

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

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

例 - setjmplongjmp の使用
#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); //Noncompliant
}
void func_main(int i) {
    signal(SIGINT, sighandler);
    if (setjmp(env)==0) { //Noncompliant
        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;
}

チェック情報

グループ: Rec.48.その他 (MSC)

バージョン履歴

R2019a で導入


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.