質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
セキュリティー

このタグは、コンピューターシステムの安全性やデータの機密性に関連したトピックの為に使われます。

ファイルI/O

ファイルI/Oは、コンピューターにおけるファイルの入出力です。これは生成/削除やファイルを読み込んだり、出力をファイルに書き込むようなディレクトリやファイルの運用を含みます。

D言語

D言語は、プログラミング言語のひとつです。テンプレートメタプログラミング、関数型プログラミング、オブジェクト指向プログラミング等をサポートする汎用のシステム・アプリケーションプログラミング言語です。

Q&A

解決済

2回答

2313閲覧

D言語の単体機能で、ファイルレースコンディションを防ぐ方法

v_v

総合スコア47

セキュリティー

このタグは、コンピューターシステムの安全性やデータの機密性に関連したトピックの為に使われます。

ファイルI/O

ファイルI/Oは、コンピューターにおけるファイルの入出力です。これは生成/削除やファイルを読み込んだり、出力をファイルに書き込むようなディレクトリやファイルの運用を含みます。

D言語

D言語は、プログラミング言語のひとつです。テンプレートメタプログラミング、関数型プログラミング、オブジェクト指向プログラミング等をサポートする汎用のシステム・アプリケーションプログラミング言語です。

1グッド

2クリップ

投稿2016/10/20 02:03

編集2016/10/20 02:43

現在D言語でファイルを扱うプログラムをテストで組んでいます。
以下のようなコードはファイルレースコンディション脆弱性を含みます。
これを防ぐにはD言語が提供するAPI以外(OS依存)でやらないと実現できないのでしょうか。

D言語

1void main() 2{ 3 string path="test.bin"; 4 5 // ファイルがなければ新規作成 6 if(!exists(path)){ 7 // このタイミングで新規作成するファイル名が 8 // シンボリックリンクにすり替えられると 9 // リンク先が空ファイルとなり破壊される。 10 scope File fp = File(path,"wb"); // 空ファイル新規作成 11 writeln("created."); 12 } 13 // シンボリックリンクだったら終了する 14 if(isSymlink(path)){ 15 return; 16 } 17 // ここから 18 writeln("no symlink."); 19 // このタイミングでシンボリックリンクへの 20 // すり替えが行われると 21 File fp = File(path,"rb+"); 22 // ↓のファイル書き換え処理によるリンク先の書き換えが発生 23 fp.rawWrite([0,20,30,40]); 24}

現状、WindowsとLinux用にソースを分けて書くくらいしか考えられておりませんが、D言語の標準ライブラリで可能ならそちらで対応したいと思っています。
標準ライブラリにアトミックにこれら一連の(チェック&作成、チェック&オープン)処理を行う機能はありますでしょうか。

以上、ご回答のほど宜しくお願い致します。

maisumakun👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

自己解決

回答者様へは申し訳ありませんが、そのままではコードを使うことができないため
BA取り消しさせていただきました・・・
回答について検証を致しましたので、頂いた回答への補足を致します。
また、やはり標準ライブラリでは解決できそうにないため、OS毎にコードを分ける実装をしたいと思います。

お手数をおかけいたしました。
ありがとうございます。

実際にコードを書く際は以下のケース等に配慮することが必要です。

D言語

1// --略-- 2 try { 3 // ファイルがなければ新規作成(ここでファイルが有った場合を考えます) 4 if (!exists(path)) { 5 new_file = true; 6 scope File fp = File(path, "ab"); 7 writeln("Creating new file..."); 8 } else if (exists(path) && isDir(path)) { 9 writeln("File is directory."); 10 writeln("exit..."); 11 return; 12 } else if (exists(path) && path.isSymlink) { 13 writeln("File is symlink."); 14 writeln("exit..."); 15 return; 16 } 17 // exists関数で「ファイルが存在する」という判定だった場合 18 // 下記の点に気を付ける必要があります。 19 // このコメント行のタイミングでファイル(実体)のすり替えが起こると 20 // 本来は意図しないファイルの書き換えが起こる可能性があります。 21 // ケース:他アプリでテスト用ファイルを削除、 22 // 本番用ファイルに差し替える操作が 23 // ここの僅かなタイミングで発生した場合、 24 // 被害:本番用ファイルが書き換えられるの等問題が発生する恐れがあります。 25 // =>最初に確認したファイルと開いたファイルの実体不一致による不具合の発生の恐れ。 26 // 対策:ファイルの存在確認からファイルのオープンをアトミックに行うこと 27 28 File fp = File(path, "rb+"); 29 if (isDir(path)) { // ディレクトリではないので入らない 30 writeln("File is directory."); 31 writeln("exit..."); 32 return; 33 } else if (path.isSymlink) { // シンボリックリンクではないので入らない 34 writeln("File is symlink."); 35 writeln("exit..."); 36 return; 37 } else if (new_file == true && fp.size != 0) { // 新規作成ではないので検知不能 38 //新しいファイルを作成してファイルサイズが0でないとき何らかの改ざんがなされていると仮定する 39 writeln("Error."); 40 return; 41 } else { 42 writeln("File is no symlink."); 43 } 44 // 本番用ファイルの書き換えが発生=意図しないファイルの破壊 45 fp.rawWrite([0, 20, 30, 40]); 46...

投稿2016/10/25 02:46

編集2016/10/25 03:00
v_v

総合スコア47

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

自分もプログラミング初心者なので、ファイルレースコンディションへの対策法は知らないです。
なので思いついた改善点だけ列挙します。

単純にファイルを新規に作成するだけのところは、
追加書き込み(aとかab)で開く
http://www.c-tipsref.com/reference/stdio/fopen.html

ファイルを読み込む前にファイルをシンボリックリンクに変えられる問題は、
・ファイルを読み込んでらもう一度シムリンクであるかどうかをチェック
・新規作成時であるときに、何もしてないのに0バイトでなかったら改ざんされているので終了

という風にすればいいと思います。

そんな感じで以下のコードになりました。

D言語

1import std.stdio; 2import std.file; 3 4 5static immutable string path = "test.bin"; 6 7void main() 8{ 9 10 bool new_file = false; 11 12 try { 13 // ファイルがなければ新規作成 14 if (!exists(path)) { 15 new_file = true; 16 scope File fp = File(path, "ab"); 17 writeln("Creating new file..."); 18 } else if (exists(path) && isDir(path)) { 19 writeln("File is directory."); 20 writeln("exit..."); 21 return; 22 } else if (exists(path) && path.isSymlink) { 23 writeln("File is symlink."); 24 writeln("exit..."); 25 return; 26 } 27 28 File fp = File(path, "rb+"); 29 30 if (isDir(path)) { 31 writeln("File is directory."); 32 writeln("exit..."); 33 return; 34 } else if (path.isSymlink) { 35 writeln("File is symlink."); 36 writeln("exit..."); 37 return; 38 } else if (new_file == true && fp.size != 0) { 39 //新しいファイルを作成してファイルサイズが0でないとき何らかの改ざんがなされていると仮定する 40 writeln("Error."); 41 return; 42 } else { 43 writeln("File is no symlink."); 44 } 45 46 fp.rawWrite([0, 20, 30, 40]); 47 48 } catch (Exception e) { 49 writeln(e); 50 return; 51 } 52 53} 54

他に思いつく改善点としては
・読み込む前にサイズとか更新日時とかを確認しておき、読み込んだ後比較する
・標準関数からinodeなどの番号を取得する関数を探す
くらいです。

投稿2016/10/22 01:21

dokutoku

総合スコア11

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

v_v

2016/10/24 08:58

ファイルの作成を追記モードでやる発想は無かったです。 シンボリックリンクのチェックについてはファイルハンドルを保持している状態であれば、恐らく問題なさそうですね。 少し検証してみます。 具体的な改善点の指摘ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問