メインコンテンツ

子プロセスに対するファイル記述子の公開

複数のプロセスで使用されるコピーされたファイル記述子

説明

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

リスク

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

修正方法

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

すべて展開する

# 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);
	}
    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);
    }
}

結果情報

グループ: セキュリティ
言語: C | C++
既定値: オフ
コマンド ライン構文: FILE_EXPOSURE_TO_CHILD
影響度: Medium

バージョン履歴

R2017b で導入