檢查IRP_MJ_CREATE周遊許可權

其中一個主要考慮 IRP_MJ_CREATE 檢查是呼叫端是否具有 周遊 許可權,這是存取物件路徑的許可權。 也就是說,呼叫端可以存取 dirA/dirB/file之類的檔案物件,但無法存取該檔案物件路徑中目錄的內容, (dirAdirA/dirB) 。

根據預設,Windows 會將周遊許可權授與所有使用者。 「User Right」 常數是 SeChangeNotifyPrivilege,其會對應至 ACCESS_MASK 中的 FILE_TRAVERSE。 身為安全性功能,系統管理員可以從使用者移除周遊許可權。

由於大部分呼叫端都有周遊許可權,因此檔案系統通常會在 IRP 安全性內容的 AccessState-Flags > 欄位中檢查此許可權,

    BOOLEAN traverseCheck = 
        !(IrpContext->IrpSp->Parameters.Create.SecurityContext->AccessState->Flags
            & TOKEN_HAS_TRAVERSE_PRIVILEGE);

檔案系統會使用 旗標 來追蹤作業進度中已授與哪些存取權限。 然後檔案系統可以先快速檢查存取狀態位,並避免存取檢查呼叫的費用,如果已授與存取權 (周遊Check = 0) 。

如果先前尚未授與周遊許可權,檔案系統必須在每個目錄上執行周遊檢查,並沿著開啟的檔案路徑執行周遊檢查。 在下面的部分程式碼片段中,周遊檢查是使用泛型常式來完成,通常用於大部分的安全性檢查:


{
// accessParams is passed to the file system and is normally based
// on the fields of the same name from the IRP.

// Only one thread can be looking at this data structure in memory
// at a time (and potentially changing it), so acquire a lock on it.

    SeLockSubjectContext(
        &accessParams.AccessState->SubjectSecurityContext);

// Check whether the desired access can be granted.
// For this example, assume desiredAccess = FILE_TRAVERSE

    granted = SeAccessCheck( Fcb->SecurityDescriptor,
        &AccessParams.AccessState->SubjectSecurityContext,
        TRUE,
        AccessParams.desiredAccess,
        0,
        &Privileges,
        IoGetFileObjectGenericMapping(),
        AccessParams.AccessMode,
        &AccessParams.GrantedAccess,
        &AccessParams.status );

    // The file system uses AccessState to cache access privileges
    // that have been granted thus far along the operation's code
    // path. Update AccessState with the newly acquired Privileges.
    
    if (Privileges != NULL) {

        (void) SeAppendPrivileges(AccessParams.AccessState, Privileges );
        SeFreePrivileges( Privileges );
        Privileges = NULL;
    }

    if (granted) {
        //
        // The desired access was granted, so clear the
        // granted bits from desiredAccess. 
        //
        AccessParams.desiredAccess &= 
            ~(AccessParams.GrantedAccess | MAXIMUM_ALLOWED);
 
        if (!checkOnly) {
        //
        // The caller wants to modify the access state for this 
        // request
        //
            AccessParams.AccessState->PreviouslyGrantedAccess |= 
                AccessParams.GrantedAccess;
        }

        if (maxDesired) {

            maxDelete = 
                (BOOLEAN)(AccessParams.AccessState->PreviouslyGrantedAccess & 
                    DELETE);
            maxReadAttr = 
                (BOOLEAN)(AccessParams.AccessState->PreviouslyGrantedAccess & 
                    FILE_READ_ATTRIBUTES);
        }
        AccessParams.AccessState->RemainingDesiredAccess &= 
            ~(AccessParams.GrantedAccess | MAXIMUM_ALLOWED);
    }

    // Release the lock on the security context
    SeUnlockSubjectContext(&accessParams.AccessState->SubjectSecurityContext);  
}

此函式會執行一般安全性檢查。 此函式必須處理下列問題:

  • 它必須指定要用於檢查的正確安全性描述元。

  • 它必須沿著安全性內容傳遞, (這些是執行作業的實體認證) 。

  • 它必須根據安全性檢查的結果來更新存取狀態。

  • 它必須考慮 MAXIMUM_ALLOWED 選項, (請參閱 ntifs.h) 。 MAXIMUM_ALLOWED 選項會指定檔案系統應該設定檔案系統 (讀取/寫入/刪除允許的最大存取權,例如) 。 非常少的應用程式會使用 MAXIMUM_ALLOWED 選項,因為 FASTFAT 檔案系統不支援此選項。 因為MAXIMUM_ALLOWED選項位不是 FASTFAT 檔案系統辨識的其中一個存取位,所以它會拒絕對指定檔案的存取要求。 嘗試在 FASTFAT 磁片區上開啟檔案且設定MAXIMUM_ALLOWED選項的應用程式,會發現要求失敗。 如需詳細資訊,請參閱 WDK 所包含之 FASTFAT 範例程式碼之 Acc hksup.c 原始程式檔中的 FatCheckFileAccess 函式。

請注意,針對簡單的周遊檢查,要求存取權會 FILE_TRAVERSE ,而安全性描述元會是呼叫端嘗試周遊的目錄,而不是從原始 IRP_MJ_CREATE IRP 要求存取。