CmpSecurityMethod is a method used by the Object Manager and called by this
subsystem whenever a security operation has to be done against a key object.
As CmpSecurityMethod is a specific OB construct we should not make any direct
call attempts to CmpSecurityMethod, only OB is responsible for that. This fixes
a deadlock where CmpSecurityMethod acquires a push lock for exclusive access
even though such lock is already acquired by the same calling thread in
CmpDoCreateChild.
This prevents a deadlock in DelistKeyBodyFromKCB when we delete a key
object because of an access check failure during a open procedure of a
registry key, as we are already holding a lock against the target KCB of
the key body.
Whenever a security request is invoked into a key object, such as when requesting
information from its security descriptor, the Object Manager will execute
the CmpSecurityMethod method to do the job.
The problem is that CmpSecurityMethod is not aware if the key control block
of the key body already has a lock acquired which means the function will attempt
to acquire a lock again, leading to a deadlock. This happens if the same
calling thread locks the KCB but it also wants to acquire security information
with ObCheckObjectAccess in CmpDoOpen.
Windows has a hack in CmpSecurityMethod where the passed KCB pointer is ORed
with a bitfield mask to avoid locking in all cases. This is ugly because it negates
every thread to acquire a lock if at least one has it.
The CmpUnLockKcbArray, CmpLockKcbArray and CmpBuildAndLockKcbArray routines
help us to lock KCBs within array so that information remains consistent when
we are doing a cache lookup during a parse procedure of the registry database.
Implement CmpBuildAndLockKcbArray and CmpUnLockKcbArray prototypes, we'll gonna need these
to do the locking/unlocking of KCBs stacked up in an array. In addition implement some CM
constructs specifically for cache lookup implementation (more at documentation remarks).
=== DOCUMENTATION REMARKS ===
CMP_SUBKEY_LEVELS_DEPTH_LIMIT -- This is the limit of up to 32 subkey levels
that the registry can permit. This is used in CmpComputeHashValue to ensure
that we don't compute more than the limit of subkeys we're allowed to.
CMP_KCBS_IN_ARRAY_LIMIT -- This is equal to CMP_SUBKEY_LEVELS_DEPTH_LIMIT
plus the addition by 2. This construct is used as a limit of KCB elements
the array can hold. 2 serves as an additional space for the array (one for
the root object and another one as extra space so we don't blow up the stack
array).
CMP_LOCK_KCB_ARRAY_EXCLUSIVE & CMP_LOCK_KCB_ARRAY_SHARED -- These flags are used exclusively
for CmpBuildAndLockKcbArray and CmpLockKcbArray. Their meaning are obvious.
CM_HASH_CACHE_STACK -- A structure used to store the hashes of KCBs for locking. It is named
"stack" because the way we store the hashes of KCBs is within an auxilliary "outer stack array".
CmpAcquireKcbLockSharedByKey can come in handy for use to lock KCBs by their convkey with a shared lock, specifically we would need this for cache lookup stuff.
- RtlpQuerySecurityDescriptor: Change argument type of first parameter from PISECURITY_DESCRIPTOR to PSECURITY_DESCRIPTOR, since it handles both absolute and self-relative SDs.
- RtlMakeSelfRelativeSD: rename first parameter from AbsoluteSD to SecurityDescriptor, since it handles both absolute and self-relative SDs.
- SepGetGroupFromDescriptor/SepGetOwnerFromDescriptor/SepGetDaclFromDescriptor/SepGetSaclFromDescriptor: Change parameter type from PVOID to PSECURITY_DESCRIPTOR for clarity.
The code was passing 0 instead of SECTION_INHERIT::ViewUnmap (2). 0 isn't even a proper constant to be used here. It worked, because MmMapViewOfSection only compares against ViewShare (1) and treats everything else as ViewUnmap.
The function set CtxSwitchFrame->ApcBypass to FALSE, preventing APCs (like when user mode sets the context while the thread is suspended) from being delivered as soon as the thread lowers IRQL to PASSIVE_LEVEL. This resulted in the SetContext APC to be delivered only after the user mode APC was initialized, overwriting the user mode APC context in the trap frame. This caused kernel32_winetest process to break.
Now that the Memory Management is a bit more under control again,
and branching releases/0.4.15 is near,
do mute some frequent log-spam that got introduced during 0.4.15-dev'ing
regarding lazy-flushes and MM balancing.
It frequently logged even while being idle.
Slightly improve the headers of the two touched files.
No rocket-science.
- They notify, via the "\\Callback\\SetSystemTime" callback, components
of a change of system time (for example, Win32k).
Note, that our Win32k currently does not handle power callouts, so
it isn't affected by these changes (yet).
- NtSetSystemTime(NULL, ...) means "update system time using the current
time-zone information", which is something we don't implement yet.
(And, nothing was previously protecting this call from a NULL parameter...)
Add redirections for KdSave/KdRestore and KdD0Transition/KdD3Transition.
Both KDBG and KD(TERM) need those since they will become external
transport DLLs later.
Split KdSendPacket and KdReceivePacket into those that manipulate the
KDBG state proper (reside in kdbg/kdbg.c), and those that deal only with
debug input/output that will reside in a KDTERM "KD Terminal Driver" DLL.
Based on some previous preparatory work by Hervé Poussineau in PR #4600.
(Equivalents of commits 5162bf106 and partly e9bcf7275.)
As it turns out, those three functions were duplicating the same code
between each other. Reimplement these in terms of a common helper,
RtlFindExportedRoutineByName().
Indeed: MiFindExportedRoutineByName() was just MiLocateExportName()
but taking a PANSI_STRING instead of a NULL-terminated string.
A similar state of affairs also existed in Windows <= 2003, and the
MS guys also noticed it. Both routines have been then merged and renamed
to MiFindExportedRoutineByName() on Windows 8 (taking a PCSTR instead),
and finally renamed and exported as RtlFindExportedRoutineByName()
on Windows 10.
It was implemented in psmgr.c but in a recursive way. That implementation
is replaced, in the NameToOrdinal() helper, by the better non-recursive one
found in the MiLocateExportName() and MiFindExportedRoutineByName() functions.
This NameToOrdinal() helper is then called in lieu of the duplicated code
in MiLocateExportName() and MiFindExportedRoutineByName(). In addition,
one block of code in MiSnapThunk() is simplified in a similar manner.
ACCESS_DENIED_ACE_TYPE, ACCESS_ALLOWED_ACE_TYPE, SYSTEM_AUDIT_ACE_TYPE and
SYSTEM_ALARM_ACE_TYPE belong to the same commonly internal ACE type, aka KNOWN_ACE,
as each of these ACEs have the same structure field offsets.
The only difference are ACCESS_DENIED_OBJECT_ACE_TYPE and ACCESS_ALLOWED_OBJECT_ACE_TYPE
as they have their own internal ACE type variant, the KNOWN_OBJECT_ACE structure.
The general guideline is that public ACE structure variants have to be used elsehwere
such as in UM whilst the kernel has to use the internal known ACE type variants when possible.
- Implement SepDenyAccessObjectTypeResultList, SepAllowAccessObjectTypeResultList,
SepDenyAccessObjectTypeList and SepAllowAccessObjectTypeList. These routines will
be used to grant or deny access to sub-objects of an object in the list.
- Refactor SepAnalyzeAcesFromDacl and SepAccessCheck to accomodate the newly
implemented access check by type mechanism.
- SepAccessCheck will now be SepAccessCheckWorker, a worker helper function that further
abstracts the access check mechanism in the kernel. Whereas the SepAccessCheck name will be
used as a centralized function used by the access check NT system calls.
- Deprecate SepGetSDOwner and SepGetSDGroup in favor of SepGetOwnerFromDescriptor and
SepGetGroupFromDescriptor. The former functions were buggy as they might potentially
return garbage data if either the owner or group were passed as NULL to a security
descriptor, hence a second chance exception fault. This was caught when writing tests
for NtAccessCheckByType.
- Shorten the debug prints by removing the name of the functions, the person who reads
the debugger output has to look at the source code anyway.
This implements various private kernel routines for object type list management
needed for access check code infrastructure. In addition, update the code documentation
and add missing comments.
This function will dump all the access status and granted access rights
of each object list of a list whenever an access check by type (or by type
result list) fails. This is for debugging purposes.
OBJECT_TYPE_LIST_INTERNAL will serve as an internal kernel data structure
to hold validated object type contents that are copied from UM.
The difference between the public and the internal one is that the internal structure has
an additional member for access check rights that have been granted on each
object element in the list.
I intend to port back the combined work of Thomas Faber and Serge Gautherie in context of CORE 14271.
Both developers fixed wrong retval evaluations for SeSinglePrivilegeCheck() and RtlCreateUnicodeString().
Both functions do return a BOOLEAN, and therefore using NTSTATUS() on them is wrong.
Those bugs have been fixed at multiple places. That is long gone.
But Serge fixed his locations a bit more elegantly, without the need for additional variables.
Therefore this addendum adapts a few of Thomas locations to the improved Serge-ified style.
Yes: I intentionally used a space instead of a minus after the mentioned CORE 14271,
as I don't want that pure stylistic addendum to be linked with the initial ticket anymore.
That would be overkill.