One unfortunate requirement of the CoInitializeSecurity
function is that it requires a security descriptor in absolute format. I call this unfortunate because the most common format for security descriptors is self-relative format. A common way to specify a security descriptor is to use the security descriptor definition language (SDDL), and the ConvertStringSecurityDescriptorToSecurityDescriptor
function that converts these strings to security descriptors produces self-relative security descriptors. Another common way to specify a security descriptor is as a block of bytes, perhaps stored in the registry, or stored in a file, or just hard-coded into a binary blob, and these are naturally in self-relative format, since absolute format would be dependent on the location of the block of bytes in memory.
Unfortunately, if you pass a self-relative security descriptor to CoInitializeSecurity
it fails with HRESULT_
. The requirement that the security descriptor be in absolute format is documented, but it’s still annoying.
Internally, the reason is that the CoInitializeSecurity
converts the incoming security descriptor to relative format by calling MakeSelfRelativeSD
, without first checking whether the conversion is even necessary. The MakeSelfRelativeSD
function fails with
if the security descriptor is not absolute, and that error is propagated from CoInitializeSecurity
.
Now, CoInitializeSecurity
could be updated to support self-relative security descriptor. It would just be a check whether the security descriptor is already self-relative, and using the existing one if so. However, this would create a compatibility problem, but not in the way you’re used to thinking of them.
Most of the time, the compatibility issue is “Will existing old code continue to work on a new system?” But in this case, the compatibility issues goes the other way: “Will new code continue to work on an old system?”
If CoInitializeSecurity
started allowing self-relative security descriptors, then somebody writing code today could take advantage of this new feature (perhaps unwittingly), and then encounter problems when their program is run on an older version of Windows. There is no obvious indication as to what went wrong because the function CoInitializeSecurity
does exist on the old system.
The scenario is that somebody wants to be compatible with (say) Windows 10 Version 1803, so they compile their program with the Windows 10 Version 1803 SDK, and it compiles just fine. It also runs fine on Windows 11, and since they used the Windows 10 version 1803 SDK, they erroneously conclude that the program also works on Windows 10 version 1803.
Now, maybe you say that somebody who does this deserves what they get, and maybe you’re right, but Windows traditionally has been wary of creating too many of these “pits of failure” where somebody proceeding with the best of intentions can stumble into a bad situation.
This one seems easy enough to fix by Apple’s technique of giving the function the old behavior when the program is linked against the old SDK.
This is the kind of policy choice that shows the value (and required tradeoffs) of a stable API. If this were google they’d change in a heart beat, older phones would stop working sooner, and everybody would just nod and agree that the e-waste was totally worth the (minor) API improvement. And again, next year the cycle would repeat, except this time the API would be debatably improved. And next year, Lo! Again with the change, breaking old phones. But this time for a demonstrably worse API with fewer features, and harder to use too.
So the Microsoft way may lead to some thorns and rough spots in the API that are 20+ years old. But the other way eventually leads to madness.
In fact MS isn’t immune to this issue, lots of little changes have accrued to the win32 API that are of debatable advantage, but astronomically fewer than in the android world. I get the sense that Apple is somewhere in-between?
Another consideration, especially with a security function is that someone may have come to rely on the returned error, perhaps even to enforce a security property! Introducing security vulnerabilities into someone else’s code from a distance.
I struggle to imagine how how might rely on rejecting relative SIDs… but people are very creative.
As someone, who has recently read and reread the WinSock MSDN pages to holes in my monitor, I’m surprised. I remember like lots of stuff where I saw ”this thing works this way” and then ”but in WinXP until SPx it works differently”. Anyway, the one who uses latest SDK and, especially, tests on the latest OS version has lost the war of being compatible with older versions far before even starting.
P.S. And if we talk about Win11, my students have quite a lot of trouble with it when writing low-level software projects. And they use Win10 all the time to work those troubles around. For sure, they don’t care about the ”Artificial Idiocy” features.
One solution: introduce another flavor CoInitializeSecurityEx() taking the same parameters, but it would support self-relative security descriptors,
And so the program would simply fail to run on older systems, classic Windows style.
And later on, CoInitializeSecurityExEx()….
But yes, a preferable solution, probably.
For this specific case, I’d lean towards a CoInitializeSecurityRelative()
@Shawn Van Ness
Not an Ex3, but there is a MapViewOfFile3 function.
Internet Explorer has IHTMLDocument7 interface…
The naming convention is “Ex2”. (not joking .. there are a few of these throughout the SDK .. eg. InternetGetCookieEx2)
Not sure if any “Ex3” APIs exist. Some COM interfaces, perhaps — which have greater liberty to evolve, than a static Win32 API function.