メインコンテンツ

CERT C: Rule POS38-C

フォークとファイル記述子を使用する際に競合状態に注意する

説明

ルール定義

フォークとファイル記述子を使用する際に競合状態に注意します。1

Polyspace 実装

ルール チェッカーは、"子プロセスに対するファイル記述子の公開" をチェックします。

すべて展開する

問題

子プロセスに対するファイル記述子の公開は、プロセスがフォークされ、子プロセスが親プロセスから継承したファイル記述子を使用する場合に発生します。

リスク

子プロセスをフォークする場合、ファイル記述子は親プロセスからコピーされます。つまり、同じファイルに同時操作を行うことができます。親プロセスと子プロセスで同じファイル記述子を使用すると、標準のデバッグでは把握できない競合状態につながる可能性があります。ファイル記述子のアクセス許可と権限を適切に管理しない場合、ファイルの内容は子プロセスを標的とした攻撃に対して脆弱となります。

修正方法

プロセスをフォークする前に、ファイルが変更されていないことをチェックします。継承されたファイル記述子をすべて閉じ、読み取り専用アクセス許可など、より厳格なアクセス許可と権限を使用してファイル記述子を再度開きます。

例 - フォークしたプロセスからアクセスされるファイル記述子
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <fcntl.h>
# include <sys/types.h>
# include <sys/stat.h>



const char *test_file="/home/user/test.txt";

void func(void)
{
    char c;
    pid_t pid;
	/* create file descriptor in read and write mode */
    int fd = open(test_file, O_RDWR); 
    if (fd == -1)
    {
        /* Handle error */
		abort();
    }
	/* fork process */
    pid = fork();
    if (pid == -1)
    {
        /* Handle error */
		abort();
    }
    else if (pid == 0)
    {   /* Child process accesses file descriptor inherited 
		from parent process */
        (void)read(fd, &c, 1); //Noncompliant
	}
    else
    {   /* Parent process access same file descriptor as 
		child process */
        (void)read(fd, &c, 1);
    }
}
      

この例では、ファイル記述子 fd は、読み取りおよび書き込みモードで作成されています。その後、プロセスがフォークされています。子プロセスは、親プロセスと同じアクセス許可で fd を継承し、アクセスします。親プロセスと子プロセスの間に競合状態が存在します。ファイルの内容は、子プロセスを介した攻撃に対して脆弱です。

修正 — 継承されたファイル記述子を閉じて再度開く

ファイル記述子を作成したら、ファイルに改ざんがないかどうかをチェックします。その後、子プロセスで継承されたファイル記述子を閉じ、読み取り専用モードで再度開きます。

# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <fcntl.h>
# include <sys/types.h>
# include <sys/stat.h>


const char *test_file="/home/user/test.txt";

void func(void)
{
    char c;
    pid_t pid;

    /* Get the state of file for further file tampering checking */
	
	/* create file descriptor in read and write mode */
    int fd = open(test_file, O_RDWR);  
    if (fd == -1)
    {
        /* Handle error */
		abort();
    }

    /* Be sure the file was not tampered with while opening */
	
	/* fork process */

    pid = fork();
    if (pid == -1)
    {
        /* Handle error */
        (void)close(fd);
		abort();
    }
    else if (pid == 0)
    {  /* Close file descriptor in child process and repoen 
		it in read only mode */
		
        (void)close(fd);
        fd = open(test_file, O_RDONLY); 
        if (fd == -1)
        {
            /* Handle error */
			abort();
        }


        (void)read(fd, &c, 1);
        (void)close(fd);
    }
    else
    {  /* Parent acceses original file descriptor */
        (void)read(fd, &c, 1);
        (void)close(fd);
    }
}

チェック情報

グループ: Rule 50.POSIX (POS)

バージョン履歴

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.