Another day, another beautiful C++ bug. My program is a
shareware Windows Mobile application. And it uses a unique device ID for the
purposes of licensing and user identification. On newer devices (iPhone,
Blackberry, WinMobile 5+) such a DeviceID is readily available. On older WM
devices, however, it was an optional feature. I have several fallback
mechanisms, the most basic of those would hash together several system-provided
data structures (CPU info, OS version, etc.) and use the hash value as a
DeviceID. This schema is somewhat open to collisions, but such devices are rare,
so I'm not worried much about those. A false negative is worse. And I had a case
of a device where such false negatives were happening all the time. You retrieve
a (hash-based) DeviceID, store it, on the next run it's different.
Here's the deal. One of the sources for the hash was the PROCESSOR_INFO
structure that the OS kernel (or maybe the OAL) readily provides. The structure
consists of some DWORD's and some wide (wchar_t) strings:
typedef struct {
WORD wVersion;
WCHAR szProcessorCore[40];
WORD
wCoreRevision;
WCHAR szProcessorName[40];
WORD
wProcessorRevision;
WCHAR szCatalogNumber[100];
WCHAR
szVendor[100];
DWORD dwInstructionSet;
DWORD dwClockSpeed;
}
PROCESSOR_INFO;
If you look closely, you'll see that the data size all the way up to szVendor is
566 bytes - not a multiple of 4. And DWORDs have to be aligned on 4-byte
boundary. So the in-memory layout of the structure includes two bytes of padding
between szVendor and dwInstructionSet. And it happened so that on this
particular device, the value of those two bytes would vary from call to call. So
the hash was different, so the DeviceID would vary from run to run.
One would expect a straightforward implementation of IOCTL_PROCESSOR_INFORMATION
to keep a copy of the struct somewhere in ROM, and memcpy() it into userspace on
demand. Not on this device, though...
No comments:
Post a Comment