2017-05-09 65 views
0

使用C,我試圖建立一個進程和它的子進程之間的管道連接,而子進程具有較低的強制性(完整性)級別(低,而父進程很高)。SetSecurityInfo返回訪問被拒絕

我寫了下面的程序(這是一個簡化版本,如果它),但它失敗:ERROR_ACCESS_DENIED (0x5)

INT wmain(IN SIZE_T nArgc, IN PWSTR *pArgv) 
{ 
    SECURITY_ATTRIBUTES securityArrtibutes = { 0 }; 
    HANDLE hPipeRead = NULL; 
    HANDLE hPipeWrite = NULL; 

    tSecurityArrtibutes.nLength = sizeof(tSecurityArrtibutes); 
    tSecurityArrtibutes.bInheritHandle = TRUE; 

    SetSeSecurityNamePrivilege(); 
    CreatePipe(&hPipeRead, &hPipeWrite, &securityArrtibutes, 0); 
    ChangeMandatoryLabelHandle(hPipeRead); 
} 

VOID ChangeMandatoryLabelHandle(HANDLE hObject) 
{ 
    BOOL bRetval = FALSE; 
    DWORD dwError = 0; 
    PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL; 
    PACL ptSacl = NULL; 
    BOOL bSaclPresent = FALSE; 
    BOOL bSaclDefaulted = FALSE; 
    PWSTR pSDDL = NULL; 

    SDDL = L"S:(ML;;LW;;;NW)"; 

    bRetval = ConvertStringSecurityDescriptorToSecurityDescriptorW(pSDDL, SDDL_REVISION_1, &pSecurityDescriptor, NULL); 
    if (FALSE == bRetval) 
     ... // Handle failure 

    bRetval = GetSecurityDescriptorSacl(pSecurityDescriptor, &bSaclPresent, &ptSacl, &bSaclDefaulted); 
    if (FALSE == bRetval) 
     ... // Handle failure 

    // getting ERROR_ACCESS_DENIED (0x5) 
    dwErr = SetSecurityInfo(hObject, SE_KERNEL_OBJECT, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, ptSacl); 
    if (ERROR_SUCCESS != dwErr) 
     ... // Handle failure 

    ... // Cleanup 
} 

我跟着https://msdn.microsoft.com/en-us/library/windows/desktop/aa379588(v=vs.85).aspx和上加註 To set the SACL of an object, the caller must have the SE_SECURITY_NAME privilege enabled.

BOOL SetSeSecurityNamePrivilege() 
{ 
    HANDLE hToken; 
    TOKEN_PRIVILEGES tp; 
    LUID luid; 

    if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_IMPERSONATE, &hToken) 
     return FALSE 

    if (!LookupPrivilegeValue(NULL, SE_SECURITY_NAME, &luid)) 
     return FALSE; 

    tp.PrivilegeCount = 1; 
    tp.Privileges[0].Luid = luid; 
    if (bEnablePrivilege) 
     tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
    else 
     tp.Privileges[0].Attributes = 0; 

    if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL)) 
     return FALSE; 

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) 
     return FALSE; 

    return TRUE; 
} 

注意:當我試圖用文件執行時,我得到了相同的結果,其中CreateFile而不是CreatePipe。 此外,如果我試圖用文件做到這一點,並且我將SetSecurityInfo替換爲SetNamedSecurityInfoW,併爲其指定文件的完整路徑,它的效果很好。

有沒有人有想法如何使它工作?謝謝!

+1

正如RbMm在他的回答中解釋的那樣,更改安全描述符不會對您實際嘗試解決的任何問題產生任何影響。一旦你確信自己,我建議你發表另一個關於你的實際問題的問題。 –

回答

2

在解決您的直接問題的原因之前的幾個注意事項。

首先,您根本不需要更改安全描述符,而這樣做不可能幫助您實現最終目標。只有當您嘗試打開對象的句柄時纔會檢查安全描述符;如果您已經有句柄,則安全描述符不起作用。由於您正在創建一個未命名的管道,因此您必須將句柄(而不是管道名稱)傳遞給子節點,因此您根本不需要ChangeMandatoryLabelHandle()函數。

其次,設置LABEL_SECURITY_INFORMATION時不需要SE_SECURITY_NAME權限。強制標籤在邏輯上與SACL的其餘部分不同,並被視爲特殊情況。

第三,您的"S:(ML;;LW;;;NW)"無效。

我試着在ConvertStringSecurityDescriptorToSecurityDescriptorW使用它,並得到了錯誤1336,訪問控制列表(ACL)結構無效。相反,使用"D:NO_ACCESS_CONTROLS:(ML;;;;;LW)"或者更好的是使用下面的代碼來創建一個安全描述符具有低的標籤且沒有DACL:

ULONG cb = MAX_SID_SIZE; 
PSID LowLabelSid = (PSID)alloca(MAX_SID_SIZE); 

ULONG dwError = NOERROR; 

if (CreateWellKnownSid(WinLowLabelSid, 0, LowLabelSid, &cb)) 
{ 
    PACL Sacl = (PACL)alloca(cb += sizeof(ACL) + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK)); 

    if (InitializeAcl(Sacl, cb, ACL_REVISION) && 
     AddMandatoryAce(Sacl, ACL_REVISION, 0, 0, LowLabelSid)) 
    { 
     SECURITY_DESCRIPTOR sd; 
     InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); 
     SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); 
     SetSecurityDescriptorSacl(&sd, TRUE, Sacl, FALSE); 

     SECURITY_ATTRIBUTES sa = { sizeof(sa), &sd, TRUE }; 

     // todo something here 
    } 
    else 
    { 
     dwError = GetLastError(); 
    } 
} 
else 
{ 
    dwError = GetLastError(); 
} 

但同樣,你要明白,有(幾乎)從來沒有創造任何意義未命名對象的安全描述符。只有在打開對象時才檢查安全描述符,並且(在用戶模式下)不能打開沒有名稱的對象。

(從內核模式中,我們可以通過指針使用ObOpenObjectByPointer打開的對象。)

(在舊版本的Windows,CreatePipe真正創建一個隨機命名的管道,但是從Windows 7中的管開始真是無名,因此它不能與的CreateFile或任何類似的方法被打開。)

在任何情況下,我認爲,在這種情況下使用CreatePipe是一個不錯的選擇。該功能設計不好,參數太少。沒有選擇創建雙向管道或以異步模式打開管道。我認爲最好使用CreateNamedPipeWCreateFileW

(或者,從Windows 7開始,您可以使用ZwCreateNamedPipeFileZwOpenFile創建和打開一個未命名的管道。)


貼近的問題與代碼張貼是SetSecurityInfoSetKernelObjectSecurity返回ERROR_ACCESS_DENIEDCreatePipe返回的句柄調用時。這是因爲,如文檔中的LABEL_SECURITY_INFORMATION描述:

右鍵設置要求:WRITE_OWNER

由於CreatePipe不給你選擇手柄打開訪問權限選項與,你沒有辦法做到這一點。如果您改爲使用CreateNamedPipe,則可以設置WRITE_OWNER in dwOpenMode

但是,您應該注意,如果您希望創建具有特殊安全描述符的對象,則最好在創建對象時提供該安全描述符。使用默認安全描述符創建對象並改變它是沒有意義的;爲什麼在兩個操作中你可以在一箇中做什麼?在這種情況下,您傳遞給SECURITY_ATTRIBUTES結構CreatePipeCreateNamedPipe可用於指定安全描述符,提供解決您的直接問題的另一種方式,但如前所述,這實際上並不會有用。