作成処理
ファイル システムの場合、興味深いセキュリティ作業のほとんどは、IRP_MJ_CREATE 処理中に発生します。 この手順では、受信要求を分析し、操作を実行するための適切な権限が呼び出し元にあるかどうかを判断し、それに応じて操作を許可または拒否する必要があります。 ファイル システム開発者にとって幸運なことに、ほとんどの決定メカニズムはセキュリティ リファレンス モニター内に実装されています。 したがって、ほとんどの場合、ファイル システムは適切なセキュリティ リファレンス モニター ルーチンを呼び出してアクセスを適切に決定するだけで済みます。 ファイル システムにとってリスクが発生するのは、必要なこれらのルーチンの呼び出しに失敗し、不適切に呼び出し元にアクセスを許可するときです。
FAT ファイル システムなどの標準ファイル システムの場合、IRP_MJ_CREATE の一部として行われるチェックは主にセマンティクス チェックです。 たとえば、FAT ファイル システムには、ファイルまたはディレクトリの状態に基づいて IRP_MJ_CREATE 処理が許可されるようにするための多数のチェックがあります。 FAT ファイル システムによって行われるこれらのチェックには、読み取り専用メディア用のチェック (たとえば、読み取り専用メディアで上書きや置き換えなどの破壊的な "作成" 操作を実行しようとする試みは許可されません)、共有アクセス チェック、oplock チェックが含まれます。 この分析の最も困難な部分の 1 つは、あるレベル (ファイル レベルなど) での操作が、別のレベル (ボリューム レベルなど) のリソースの状態が原因で実際に許可されない場合があると認識することです。 たとえば、別のプロセスがボリュームを排他的にロックしている場合、ファイルを開けない場合があります。 チェック対象の一般的なケースは次のとおりです。
ファイル レベルのオープン状態がボリューム レベルの状態と互換性があるかどうか。 ボリュームレベルのロックに従う必要があります。 つまり、1 つのプロセスがボリューム レベルの排他的なロックを保持している場合、そのプロセス内のスレッドのみがファイルを開くことができます。 他のプロセスのスレッドがファイルを開くことは許可できません。
ファイル レベルのオープン状態がメディアの状態と互換性があるかどうか。 特定の "作成" 操作では、"作成" 操作の一環としてファイルが変更されます。 これには、ファイルの上書き、置き換え、最後のアクセス時刻の更新も含まれます。 これらの "作成" 操作は読み取り専用メディアでは許可されず、最後のアクセス時刻は更新されません。
ボリューム レベルのオープン状態がファイル レベルの状態と互換性があるかどうか。 排他的なボリューム上で既存のファイルが開いている場合、そのボリュームのオープンは許可されません。 新しい開発者にとってこれは共通の問題です。ボリュームを開こうとして失敗するためです。 これが失敗すると、FSCTL_DISMOUNT_VOLUME を使用して、開いているハンドルを無効にしてマウント解除を強制し、新しくマウントされたボリュームへの排他アクセスを許可できます。
さらに、ファイル属性の互換性が必要です。 読み取り専用属性があるファイルを書き込みアクセス用に開くことはできません。 汎用権限を拡張した後で、必要なアクセス権をチェックする必要があることに注意してください。 たとえば、FASTFAT ファイル システム内のこのチェックは FatCheckFileAccess 関数にあります (WDK に含まれる fastfat サンプルの Acchksup.c ソース ファイルを参照してください)。
次のコード例は、FAT セマンティクス固有です。 DACL も実装するファイル システムの場合は、セキュリティ リファレンス モニターのルーチン (SeAccessCheck など) を使用して追加のセキュリティ チェックも行われます。
//
// check for a read-only Dirent
//
if (FlagOn(DirentAttributes, FAT_DIRENT_ATTR_READ_ONLY)) {
//
// Check the desired access for a read-only Dirent
// Don't allow
// WRITE, FILE_APPEND_DATA, FILE_ADD_FILE,
// FILE_ADD_SUBDIRECTORY, and FILE_DELETE_CHILD
//
if (FlagOn(*DesiredAccess, ~(DELETE |
READ_CONTROL |
WRITE_OWNER |
WRITE_DAC |
SYNCHRONIZE |
ACCESS_SYSTEM_SECURITY |
FILE_READ_DATA |
FILE_READ_EA |
FILE_WRITE_EA |
FILE_READ_ATTRIBUTES |
FILE_WRITE_ATTRIBUTES |
FILE_EXECUTE |
FILE_LIST_DIRECTORY |
FILE_TRAVERSE))) {
DebugTrace(0, Dbg, "Cannot open readonly\n", 0);
try_return( Result = FALSE );
}
FASTFAT によって実装されるさらに繊細なチェックでは、呼び出し元によって要求されるアクセスが、FAT ファイル システムが認識しているものであることが確認されます (WDK に含まれる fastfat サンプルの Acchksup.c の FatCheckFileAccess 関数)。
次のコード例は、ファイル システムのセキュリティに関する重要な概念を示しています。 ファイル システムに渡される内容が想定の範囲外ではないことを確認してください。 セキュリティの観点から見た保守的で適切なアプローチは、アクセス要求を理解していない場合、その要求を拒否する必要があるということです。
//
// Check the desired access for the object.
// Reject what we do not understand.
// The model of file systems using ACLs is that
// they do not type the ACL to the object that the
// ACL is on.
// Permissions are not checked for consistency vs.
// the object type - dir/file.
//
if (FlagOn(*DesiredAccess, ~(DELETE |
READ_CONTROL |
WRITE_OWNER |
WRITE_DAC |
SYNCHRONIZE |
ACCESS_SYSTEM_SECURITY |
FILE_WRITE_DATA |
FILE_READ_EA |
FILE_WRITE_EA |
FILE_READ_ATTRIBUTES |
FILE_WRITE_ATTRIBUTES |
FILE_LIST_DIRECTORY |
FILE_TRAVERSE |
FILE_DELETE_CHILD |
FILE_APPEND_DATA))) {
DebugTrace(0, Dbg, "Cannot open object\n", 0);
try_return( Result = FALSE );
}
ファイル システムにとって幸運なことに、初期作成処理中にセキュリティ チェックが完了すると、その後のセキュリティ チェックは I/O マネージャーによって実行されます。 たとえば、I/O マネージャーによって、読み取りアクセス専用に開かれたファイルに対して、ユーザーモード アプリケーションが書き込み操作を実行しないことが保証されます。 実際、IRP_MJ_WRITE ディスパッチ ルーチン中に、ファイル オブジェクトが読み取りアクセス専用に開かれている場合でも、ファイル システムがファイル オブジェクトに対して読み取り専用セマンティクスの適用を試行すべきではありません。 これは、メモリ マネージャーが特定のファイル オブジェクトを特定のセクション オブジェクトに関連付ける方法のためです。 そのセクションの後続の書き込みは、ファイルが読み取り専用で開かれている場合でも、ファイル オブジェクトに対する IRP_MJ_WRITE 操作として送信されます。 つまり、アクセスの適用が行われるのは、Nt システム サービス エントリ ポイントで ObReferenceObjectByHandle によって、ファイル ハンドルが対応するファイル オブジェクトに変換されるときです。
ファイル システム内には、"作成" 処理と同様に、セマンティック セキュリティ チェックを行う必要がある場所が 2 箇所あります。
名前の変更またはハード リンクの処理中。
ファイル システム制御操作を処理するとき。
名前の変更の処理とファイル システム制御の処理については、以降のセクションで説明します。
これは "作成" 処理に関連するセマンティックの問題の完全な一覧ではないことに注意してください。 このセクションの目的は、ファイル システム開発者向けのこれらの問題に注目することです。 すべてのセマンティックの問題は、特定のファイル システムに対して識別し、特定のセマンティクスを満たすように実装し、実装によってさまざまなケースを確実に処理できるようにテストする必要があります。