Geoff Chappell, Software Analyst
The RtlValidSid function checks that a supposed Security Identifier (SID) is not obviously invalid.
BOOLEAN RtlValidSid (PSID Sid);
The Sid argument provides the address of the SID to validate.
The function returns FALSE if the SID is invalid, else TRUE.
The RtlValidSid function is exported by name from both the kernel and NTDLL in all Windows versions, i.e., in 3.10 and higher. It provides the low-level support for the documented high-level API function IsValidSid, which ADVAPI32 exports by name in all versions.
The RtlValidSid function is documented but has not always been. The first known documentation is from the Installable File System (IFS) Kit for Windows 2000, which was not widely circulated. The function is declared in NTIFS.H if compiling for Windows 2000 or higher.
In a valid SID, the low four bits of the Revision are SID_REVISION (1) and the SubAuthorityCount does not exceed SID_MAX_SUBAUTHORITIES (15). These two points are the core of the validity check in all versions. They are also all that Microsoft’s documentation says of the function.
Originally, this is indeed all the function does, but with all use of Sid being subject to exception handling: occurrence of an exception while accessing the SID means, of course, that the SID is invalid.
Version 5.0 and higher check first that Sid is not NULL. Version 5.0 also introduced a differentiation between the kernel and NTDLL implementations. In user mode only, unless the SubAuthorityCount is zero, the validity check ends by probing the variable-size SubAuthority array to test that the last subauthority identifier is readable.
Starting with version 6.1, the kernel-mode implementation does away with the exception handling and rejects the SID as invalid if Sid is in user-mode address space.
The last of the preceding variations is perhaps not without practical consequence, no matter that Microsoft hasn’t thought it important enough to document. In kernel mode, this function regards as invalid all SIDs in user-mode address space. Yet an obvious reason a programmer might think to use the function is that a supposed SID is received from user mode. Of course, even if the SID is valid, further work will be done with a copy that is captured into kernel-mode address space. But how does the kernel-mode programmer establish that a copy is safe to take? The documented way to get the size to copy is to call RtlLengthSid and you can likely see where this is going: yes, the documentation of RtlLengthSid says to call RtlValidSid first.
To keep within the documentation, you can instead follow the kernel’s technique for capturing a user-mode SID. Subject to the usual exception handling and checks against the MmUserProbeAddress, it might call RtlLengthSid to read the SubAuthorityCount and compute how big the SID ought to be, and then check whether that amount of memory is readable. It instead reads the SubAuthorityCount directly and feeds it to the RtlLengthRequiredSid function to compute how big the SID ought to be.
The kernel-mode implementation is in paged memory and must not be called at DISPATCH_LEVEL or higher. Microsoft’s documentation explicitly permits as high as APC_LEVEL.