http://bugs.winehq.org/show_bug.cgi?id=18426
--- Comment #5 from Anastasius Focht focht@gmx.net 2010-01-17 09:29:47 --- Hello,
looks like a problem of propagating NULL fields (SACL/DACL) when the security descriptor is in self relative format.
--- quote --- ... 0009:trace:ntdll:NtQuerySecurityObject (0x58,0x00000007,0x624f08,0x00000074,0x32cafc) 0009: get_security_object( handle=0058, security_info=00000007 ) 0009: get_security_object() = 0 { sd_len=00000074, sd={control=00000014,owner={S-1-5-7},group={S-1-5-32-544},sacl={},dacl={{AceType=ACCESS_ALLOWED_ACE_TYPE,Mask=1f01ff,AceFlags=0,Sid={S-1-5-18}},{AceType=ACCESS_ALLOWED_ACE_TYPE,Mask=1e00a9,AceFlags=0,Sid={S-1-5-7}},{AceType=ACCESS_ALLOWED_ACE_TYPE,Mask=1200a9,AceFlags=0,Sid={S-1-1-0}}}} } 0009: close_handle( handle=0058 ) 0009: close_handle() = 0 0009:trace:ntdll:NtAccessCheck (0x624f08, 0x48, 00120116, 0x32cadc, 0x32cac8, 0x32caf4, 0x32caec, 0x32ca84) 0009:trace:ntdll:RtlGetControlSecurityDescriptor (0x624f08,0x32ca0a,0x32ca0c) 0009:trace:ntdll:RtlLengthSid sid=0x624f1c 0009:trace:ntdll:RtlLengthSid sid=0x624f28 0009:trace:ntdll:RtlGetSaclSecurityDescriptor (0x624f08,0x32ca12,0x32ca18,0x32ca13) 0009:trace:ntdll:RtlGetDaclSecurityDescriptor (0x624f08,0x32ca12,0x32ca14,0x32ca13) 0009: access_check( handle=0048, desired_access=00120116, mapping_read=00120089, mapping_write=00120116, mapping_execute=001200a0, mapping_all=001201bf, sd={control=00000014,owner={S-1-5-7},group={S-1-5-32-544},sacl={,dacl={{AceType=ACCESS_ALLOWED_ACE_TYPE,Mask=1f01ff,AceFlags=0,Sid={S-1-5-18}},{AceType=ACCESS_ALLOWED_ACE_TYPE,Mask=1e00a9,AceFlags=0,Sid={S-1-5-7}},{AceType=ACCESS_ALLOWED_ACE_TYPE,Mask=1200a9,AceFlags=0,Sid={S-1-1-0}}}} ) 0009: access_check() = ACCESS_VIOLATION { access_granted=00000000, access_status=00000000, privileges_len=00000000, privileges={} } --- quote ---
NtQuerySecurityObject():
sd_len=00000074, sd={control=00000014,owner={S-1-5-7},group={S-1-5-32-544},sacl={},dacl=... (ACEs present)
The resulting security descriptor is returned in self relative format:
{Revision=1, Sbz1=0, Control=32788, Owner=0x14, Group=0x20, Sacl=(nil), Dacl=0x30}
control=0x8014 (SE_SELF_RELATIVE | SE_SACL_PRESENT | SE_DACL_PRESENT )
ntdll/sec.c:NtAccessCheck() collects various fields for transfer to wineserver's token access_check():
--- snip dlls/ntdll/sec.c --- NTSTATUS WINAPI NtAccessCheck( PSECURITY_DESCRIPTOR SecurityDescriptor, HANDLE ClientToken, ACCESS_MASK DesiredAccess, PGENERIC_MAPPING GenericMapping, PPRIVILEGE_SET PrivilegeSet, PULONG ReturnLength, PULONG GrantedAccess, NTSTATUS *AccessStatus) { ... RtlGetSaclSecurityDescriptor( SecurityDescriptor, &present, &sacl, &defaulted ); sd.sacl_len = ((present && sacl) ? acl_bytesInUse(sacl) : 0); ... } --- snip dlls/ntdll/sec.c ---
RtlGetSaclSecurityDescriptor() looks at the control flags and propagates "present", along with pointer to data:
--- snip dlls/ntdll/sec.c --- NTSTATUS WINAPI RtlGetSaclSecurityDescriptor( IN PSECURITY_DESCRIPTOR pSecurityDescriptor, OUT PBOOLEAN lpbSaclPresent, OUT PACL *pSacl, OUT PBOOLEAN lpbSaclDefaulted) { SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor;
TRACE("(%p,%p,%p,%p)\n", pSecurityDescriptor, lpbSaclPresent, pSacl, lpbSaclDefaulted);
if (lpsd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
if ( (*lpbSaclPresent = (SE_SACL_PRESENT & lpsd->Control) ? 1 : 0) ) { if (SE_SELF_RELATIVE & lpsd->Control) *pSacl = (PACL)SELF_RELATIVE_FIELD( lpsd, Sacl ); else *pSacl = lpsd->Sacl;
*lpbSaclDefaulted = (( SE_SACL_DEFAULTED & lpsd->Control ) ? 1 : 0);
TRACE("*pSacl=%p\n", *pSacl); } return STATUS_SUCCESS; } --- snip dlls/ntdll/sec.c ---
The problem is the self relative case with control flags set but not data present (corresponds to NULL DACL/SACL).
--- snip dlls/ntdll/sec.c --- #define SELF_RELATIVE_FIELD(sd,field) ((BYTE *)(sd) + ((SECURITY_DESCRIPTOR_RELATIVE *)(sd))->field) ... *pSacl = (PACL)SELF_RELATIVE_FIELD( lpsd, Sacl ); --- snip dlls/ntdll/sec.c ---
The returned pointer will be wrong, leading to later (mis)interpreted (ACL) data. You need to check for zero offsets (= NULL field case) because a valid self relative field offset is never 0 (SD header present).
You might want to check other code locations in ntdll/sec.c that have similar problem.
Regards