メインコンテンツ

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

CERT C: Rule ENV31-C

環境ポインターを無効にする可能性のある操作の後にその環境ポインターに依存しない

説明

ルール定義

環境ポインターを無効にする可能性のある操作の後にその環境ポインターに依存しないようにします。1

Polyspace 実装

ルール チェッカーは、"前の操作によって無効になった環境ポインター" をチェックします。

すべて展開する

問題

[前の操作によって無効になった環境ポインター] は、ホストされている環境において、操作によってその環境が変更された後に main() の 3 番目の引数を使用してその環境にアクセスする場合に発生します。ホストされている環境では、多くの C 実装で非標準の構文がサポートされます。

main (int argc, char *argv[], char *envp[])
setenv または putenv ファミリ関数の呼び出しにより、*envp の参照先の環境に変更が加えられます。

リスク

setenv または putenv ファミリ関数の呼び出しによって環境が変更されると、環境のメモリが再割り当てされる可能性があります。そのホストされている環境のポインターが更新されず、正しくない場所を指す場合があります。このポインターを呼び出すと、予期しない結果が返されたり、プログラムの異常終了が発生したりすることがあります。

修正方法

ホストされている環境のポインターを使用しないようにします。代わりに、グローバル外部変数を使用します。Linux® では environ、Windows® では _environ_wenviron、またはこれらと同等のグローバル外部変数を使用します。環境を変更すると、これらの変数が更新されます。

例 - ポインター envp による環境へのアクセス
#include <stdio.h>
#include <stdlib.h>

extern int check_arguments(int argc, char **argv, char **envp);
extern void use_envp(char **envp);

/* envp is from main function */
int func(char **envp) 
{
    /* Call to setenv may cause environment
     *memory to be reallocated 
     */
    if (setenv(("MY_NEW_VAR"),("new_value"),1) != 0) 
    {
        /* Handle error */
        return -1;
    }
    /* envp not updated after call to setenv, and may
     *point to incorrect location.
     **/
    if (envp != ((void *)0)) {  //Noncompliant
        use_envp(envp);
/* No defect on second access to
*envp because defect already raised */
    }
    return 0;
}

void  main(int argc, char **argv, char **envp)
{
    if (check_arguments(argc, argv, envp))
    {
        (void)func(envp);
    }
}

この例では、環境のメモリが再割り当てされる可能性のある setenv の呼び出しの後に、func() 内で envp にアクセスしています。envp は、setenv によって環境が変更された後には更新されないため、正しくない場所を指す可能性があります。前のコード行で既に欠陥が報告されているため、use_envp() が呼び出されたときには欠陥が報告されません。

修正 — グローバル外部変数 environ を使用

1 つの修正方法として、setenv の呼び出し後に必ず更新される変数を使用して環境にアクセスします。たとえば、次のコードでは、ポインター envpmain() からも使用可能ですが、環境へのアクセスは func() 内でグローバル外部変数 environ を通じて行います。

#include <stdio.h>
#include <stdlib.h>
extern char **environ;

extern int check_arguments(int argc, char **argv, char **envp);
extern void use_envp(char **envp);

int func(void)
{
    if (setenv(("MY_NEW_VAR"), ("new_value"),1) != 0) {
        /* Handle error */
        return -1;
    }
  /* Use global external variable environ
   *which is always updated after a call to setenv */
    
    if (environ != NULL) { 
        use_envp(environ);
    }
    return 0;
}

void  main(int argc, char **argv, char **envp)
{
    if (check_arguments(argc, argv, envp))
    {
        (void)func();
    }
} 

チェック情報

グループ: Rule 10.環境 (ENV)

バージョン履歴

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.