檔案系統控制處理
處理 IRP_MJ_FILE_SYSTEM_CONTROL 作業與檔案系統內其他作業所需的資料緩衝區處理不同。 這是因為每個作業都會透過CTL_CODE宏,為 I/O 管理員建立其特定資料傳輸機制,作為其控制程式代碼的一部分。 此外,控制項程式碼會指定呼叫端所需的檔案存取權。 定義控制程式代碼時,檔案系統應該特別瞭解此問題,因為 I/O 管理員會強制執行此存取權。 某些 I/O 控制程式碼 (FSCTL_MOVE_FILE ,例如) 指定FILE_SPECIAL_ACCESS,這是允許檔案系統直接檢查作業安全性的機制。 FILE_SPECIAL_ACCESS數值相當於FILE_ANY_ACCESS,因此 I/O 管理員不會提供任何特定的安全性檢查,而是延遲至檔案系統。 FILE_SPECIAL_ACCESS主要提供檔,說明檔案系統將會進行其他檢查。
數個檔案系統作業會指定FILE_SPECIAL_ACCESS。 FSCTL_MOVE_FILE作業會當做檔案系統重組介面的一部分使用,並指定FILE_SPECIAL_ACCESS。 因為您想要能夠重組正在讀取和寫入的開啟檔案,所以使用的控制碼只有FILE_READ_ATTRIBUTES授與存取權,以避免共用存取衝突。 不過,此作業必須是特殊許可權作業,因為磁片是在低階上修改。 解決方案是確認用來發出FSCTL_MOVE_FILE控制碼是直接存取存放裝置, (DASD) 使用者磁片區開啟,這是特殊許可權控制碼。 FASTFAT 檔案系統程式碼可確保針對開啟的使用者磁片區執行這項作業,位於 FatMoveFile 函式中, (從 WDK 包含的 fastfat 範例中看到 fsctrl.c 原始程式檔) :
//
// extract and decode the file object and check for type of open
//
if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &FcbOrDcb, &Ccb ) != UserVolumeOpen) {
FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", STATUS_INVALID_PARAMETER);
return STATUS_INVALID_PARAMETER;
}
FSCTL_MOVE_FILE作業所使用的結構會指定要移動的檔案:
typedef struct {
HANDLE FileHandle;
LARGE_INTEGER StartingVcn;
LARGE_INTEGER StartingLcn;
ULONG ClusterCount;
} MOVE_FILE_DATA, *PMOVE_FILE_DATA;
如先前所述,用來發出FSCTL_MOVE_FILE控制碼是整個磁片區的「開啟」作業,而作業實際上會套用至MOVE_FILE_DATA輸入緩衝區中指定的檔案控制代碼。 這會使這項作業的安全性檢查稍微複雜。 例如,這個介面必須將檔案控制代碼轉換成代表要移動之檔案的檔案物件。 這需要仔細考慮任何驅動程式的一部分。 FASTFAT 會在 Fsctrl.c 原始程式檔的 fsctrl.c 原始程式檔中,以受防護的方式使用ObReferenceObject,而 WDK 包含的 fastfat 範例中:
//
// Try to get a pointer to the file object from the handle passed in.
//
Status = ObReferenceObjectByHandle( InputBuffer->FileHandle,
0,
*IoFileObjectType,
Irp->RequestorMode,
&FileObject,
NULL );
if (!NT_SUCCESS(Status)) {
FatCompleteRequest( IrpContext, Irp, Status );
DebugTrace(-1, Dbg, "FatMoveFile -> %08lx\n", Status);
return Status;
}
// Complete the following steps to ensure that this is not an invalid attempt
//
// - check that the file object is opened on the same volume as the
// DASD handle used to call this routine.
//
// - extract and decode the file object and check for type of open.
//
// - if this is a directory, verify that it's not the root and that
// you are not trying to move the first cluster. You cannot move the
// first cluster because sub-directories have this cluster number
// in them and there is no safe way to simultaneously update them
// all.
//
// Allow movefile on the root directory if it's FAT32, since the root dir
// is a real chained file.
// //
請注意,使用 Irp-RequestorMode > 來確保呼叫端是使用者模式應用程式,控制碼不能是核心控制碼。 必要的存取權為 0,以便在正在主動存取時移動檔案。 最後請注意,如果呼叫源自使用者模式,則必須在正確的進程內容中進行此呼叫。 FASTFAT 檔案系統中的原始程式碼也會在 fsctrl.c 的 FatMoveFile 函式中強制執行此專案:
//
// Force WAIT to true. There is a handle in the input buffer that can only
// be referenced within the originating process.
//
SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
FAT 檔案系統所執行的這些語意安全性檢查通常是檔案系統針對通過控制碼的任何作業所需的一般。 此外,FAT 檔案系統也必須執行作業特定的健全狀況檢查。 這些健全性檢查可確保在移動的檔案位於已開啟的磁片區上, (不同的參數相容,例如) ,以避免呼叫者在不應允許時執行特殊許可權作業。
對於任何檔案系統而言,正確的安全性是檔案系統控制作業不可或缺的一部分,包括:
適當地驗證使用者控制碼。
保護使用者緩衝區存取。
驗證特定作業的語意。
在許多情況下,執行適當驗證和安全性所需的程式碼,可能會構成指定函式內大量程式碼的部分。